Skip to content

Revert "Fix SwipeItem IconImageSource color handling and rendering across platforms (#35632)" - #36883

Closed
kubaflo wants to merge 43 commits into
inflight/candidatefrom
revert-35632-swipeitem-icon-tint
Closed

Revert "Fix SwipeItem IconImageSource color handling and rendering across platforms (#35632)"#36883
kubaflo wants to merge 43 commits into
inflight/candidatefrom
revert-35632-swipeitem-icon-tint

Conversation

@kubaflo

@kubaflo kubaflo commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

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!

Issue Details

This reverts #35632 ("Fix SwipeItem IconImageSource color handling and rendering across platforms") from the .NET 10 servicing line.

#35632 stopped auto-tinting SwipeItem.IconImageSource for PNG/SVG sources, so those icons now render in their own colors instead of a contrast color derived from the item background. It shipped in 10.0.90 (SR9) and is causing #36766 — an SVG icon whose fill is #212121 now renders black on a black swipe item in dark mode, i.e. effectively invisible.

The change is a reasonable direction, but it is too breaking for a servicing release:

Description of Change

Straight git revert of c78acfe, restoring the previous behavior on all platforms:

  • AndroidSetColorFilter(GetTextColor(), SrcAtop) applied to every drawable again
  • iOS/MacAlwaysTemplate rendering mode on every image again, with TintColor = fontImageSource.Color ?? GetTextColor()
  • WindowsMapSourceAsync back to ToIconSource() (BitmapIconSource, whose ShowAsMonochrome defaults to true); the LoadFileIconAsync helper is removed

The Issue23074 host-app page, shared test, cancel_red.svg and the SwipeItemFontAndSvgIconsRenderCorrectly snapshots are removed with it, and the SwipeView snapshots are restored to their pre-#35632 baselines.

Conflict resolution note: TestCases.iOS.Tests/snapshots/ios/VerifyCollectionViewContentWithIconImageSwipeItem.png conflicted because #36202 re-saved it for iOS 18 after #35632 landed. That test's swipe item has BackgroundColor = #6A5ACD (luminosity ≈ 0.40 → white), so with this revert groceries.png is tinted solid white again and the pre-#35632 baseline is the correct content. If iOS 18 CI shows drift unrelated to the tint, this one snapshot may need a re-save from the CI artifact.

Follow-up

The behavior change itself is good and should ship — just in .NET 11 rather than servicing, paired with an explicit swipe-item icon color / tint opt-out API so users get a real migration path instead of a silent rendering change in a patch release. Tracking that separately for net11.0.

Issues Fixed

Fixes #36766

PureWeen and others added 30 commits July 7, 2026 12:40
…scoped event triggers (#36409)

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

## Why
The `[Release Readiness]` tracker issues (SR9 #35867, preview7 #36138,
preview6 #35866) were refreshed once per weekday morning, so they
drifted stale as the day progressed. This keeps them fresher without
spamming watchers, and surfaces staleness explicitly when a body is
frozen by the idempotent no-op.

## What
**1. Cadence + freshness banner** (`release-readiness.yml`,
`NightlyFeed.ps1`, both engines)
- Schedule `30 8 * * 1-5` → `30 8-20/3 * * *` (every 3h, 08:30–20:30
UTC, all 7 days).
- New pure helper `Format-ReportFreshnessBanner -GeneratedAt -Now
[-StaleHours 4]` renders `🕐 Report generated N ago` and appends `⏳ …data
may be stale (older than 4h)` past threshold. Fail-open on
null/unparseable; clamps clock skew. Wired into both the SR and preview
reports. **Derived at render time from the generation timestamp and
deliberately excluded from `Get-ReportSemanticHash`** so it never churns
the idempotent no-op.

**2. Same-tracker writer serialization** (`release-readiness.yml`)
- Added a JOB-level `concurrency: group: release-readiness-tracker-${{
matrix.canonicalKey }}` (`cancel-in-progress: false`) on
`per-tracker-report`. Same-tracker writers now serialize across ALL
event kinds — the old top-level group keyed on `event_name` let two
different-event runs race the same `gh issue edit` and clobber Release
Captain Notes. Different trackers still run in parallel.
- Top-level `cancel-in-progress` → `${{ github.event_name ==
'pull_request' }}` (only PR validation cancels; writer runs are never
cancelled mid-edit). The existing re-read-live-body-before-edit +
malformed-marker skip guards are preserved as defense-in-depth.

**3. Scoped base-repo event triggers** (`release-readiness.yml`)
- Added `issues` (labeled, closed), `milestone` (created, closed), and
`push` (main, net11.0, release/**). **No `pull_request_target`.**
- Detect step maps each event to a scope filter (reusing existing
BRANCH_FILTER plumbing + new MAJOR_FILTER): push→pushed branch,
issues→majors from `regressed-in-<major>*` labels, milestone→major in
title, dispatch/schedule unchanged. Untrusted text (label names,
milestone/issue titles) flows ONLY via `env:` and is parsed with jq/grep
— never interpolated into a `run:` block. Org gate `github.repository ==
'dotnet/maui'` prevents fork activation. `issues: write` stays on the
writer job only.

## Tests
- New hash-stability test: renders the report twice with different
`fetchedAt`, asserts the banner text differs but the
`release-readiness-hash` marker is identical (proves the banner is not
hashed).
- 12 new `Format-ReportFreshnessBanner` unit tests
(fresh/stale/singular/plural/ISO-string/null/unparseable/clock-skew/custom-threshold).
- Full suite green (838/0 in a networked env).

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

---------

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

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

## Why
The release-readiness regression classifier could report a **CLOSED**
issue as an active `open-on-main` regression (Tier 2 — "wait for main
merge, then backport"). That's contradictory: an unmerged OPEN PR cannot
have closed a completed issue. It happens when a giant still-open
"Candidate" changelog PR `Fixes`-lists dozens of issues — its OPEN state
gets attributed to an already-completed issue. Real-world: issue #35615
(CLOSED/COMPLETED) surfaced under `open-on-main` in the SR9 tracker
while candidate PR #35716 was still open.

## What
`Classify-RegressionCandidate` now enforces: **never emit `open-on-main`
for a CLOSED issue.** When the aggregated best verdict is exactly
`open-on-main` and the issue is CLOSED:
1. First try the same comment-prose recovery the empty-candidate path
uses — a merged fix verifiably present on the SR wins →
`closed-fix-unlinked` (Tier 3, "no ship risk; add a closing reference
for traceability").
2. Otherwise fall to the honest `no-fix-yet` (Tier 3 for a CLOSED issue
via the existing `Get-OverallVerdict` downgrade) — the automation can't
pin a verified fix on this SR and the open candidate hasn't merged.

The shared recovery logic is extracted into a new
`Resolve-ClosedFixUnlinked` helper, called from both the
empty-`strongPrs` CLOSED path and the new guard, preserving the
fix-phrase gate, merged-on-SR gate, revert guards, and tooling-only
skips exactly.

**Strictly scoped:** only `open-on-main` + CLOSED is contradictory.
Every other verdict (`merged-on-main-no-backport`,
`backport-in-progress`, `rejected-from-sr`, `in-sr-*`,
`needs-human-review`) is unchanged even for CLOSED issues — those remain
legitimately actionable (the SR may still need the backport).
Genuinely-OPEN issues still get `open-on-main`.

## Tests
Three new unit tests in `Test-ReleaseReadiness.ps1`:
1. CLOSED issue + OPEN candidate on main + no comment fix →
`no-fix-yet`, proven non-blocking (🟢) via `Get-OverallVerdict`.
2. CLOSED issue + OPEN candidate + comment-cited merged fix on SR →
`closed-fix-unlinked` (recovery wins).
3. Regression guard: OPEN issue + OPEN candidate → stays `open-on-main`.

Full suite green (829/0).

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

---------

Co-authored-by: PureWeen <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!

> [!NOTE]
> 🤖 **AI-generated PR.** These workflows, and this description, were
produced with AI assistance. Please review carefully before merging.

## Summary

Adds two [gh-aw](https://github.com/github/gh-aw) agentic workflows that
proactively **find** and **fix** managed, cross-platform memory leaks in
MAUI — turning the AI-driven leak-hunting flow several contributors
already run by hand (scan → repro → measure → file → fix) into a
repeatable, reviewable pipeline.

**Design principle: only empirically-proven leaks.** The scanner files
an issue **only** when a plain `dotnet test` demonstrates the leak; the
fixer opens a PR **only** with a red→green regression test proving the
fix. There is no "you're missing a test" / coverage-gap mode — every
artifact is backed by a passing/failing test.

**Key property:** neither workflow needs an emulator/simulator or a MAUI
source build to *detect* a leak — the leak signature is proven by a
`dotnet test` against the **shipped `Microsoft.Maui.Controls` NuGet
package** on the plain library TFM, so detection runs on a standard
GitHub-hosted runner.

Only 4 files are added — the workflow source (`.md`) and its compiled
artifact (`.lock.yml`) for each:

```
.github/workflows/daily-leak-hunter.md   + .lock.yml
.github/workflows/leak-fixer.md          + .lock.yml
```

---

## 1. `daily-leak-hunter` — the scanner (files `[leak-scan]` issues)

**Trigger:** `schedule: every 12h` + manual (`workflow_dispatch`). Files
**only empirically-proven `[leak-scan]` issues** — up to **8 per run**.

1. **Sweeps every focus area** of the managed surface (`src/Core/src`,
`src/Controls/src/Core`, `src/Essentials/src`) in one run — it does not
stop after the first find.
2. Each focus area is **seeded with proven MAUI leak signatures** (from
the community's known-leak catalog) so the hunt targets where leaks
actually live: shared publisher → strong
`CollectionChanged`/`PropertyChanged` (e.g. `Picker.ItemsSource`,
`TableRoot`, `SelectedItems`, `GradientStops`), shared `ICommand` →
`CanExecuteChanged` (`ListView.RefreshCommand`, `SwipeItemView.Command`,
`BackButtonBehavior.Command`), VSM state triggers →
`DeviceDisplay.MainDisplayInfoChanged`, and static/`ResourceDictionary`
roots.
3. For each candidate it writes a standalone control / leaky /
mitigation xUnit repro (referencing the shipped package, no source
build) and measures retention with `WeakReference` + a forced GC. All
candidates go in **one test project** (one `[Fact]` each, one
restore/run).
4. It files a `[leak-scan]` issue **only for each leak the test
confirms** — the leaky scenario retains while **both** the control and
the mitigation release. A false positive is treated as worse than a
quiet run; unconfirmed candidates are dropped. **If a run proves
nothing, it files nothing** (no fallback mode).

**De-dup & safety:** skips a leak already covered by one of *its own*
open `[leak-scan]` issues; never touches product or test code (read-only
+ `create-issue`); `noop: report-as-issue: false`.

---

## 2. `leak-fixer` — the fixer (opens draft `[leak-fix]` PRs)

**Trigger:** `schedule: every 12h` + manual (`workflow_dispatch`). At
most **one action per run**, with de-dup + a 3-attempt cap. It picks the
**higher-priority** of two tracks:

### Track C — respond to review feedback (checked first)
Before doing new work, it checks whether one of *its own* open
`[leak-fix]` PRs (**hosted on this repo** — fork-hosted heads it can't
push to are left for a human) has an **unaddressed `CHANGES_REQUESTED`
review**. If so it works on that PR: **applies** the valid requested
changes (pushes a commit, re-validated so the PR's own test still holds)
and/or **posts a comment pushing back** on any request that is wrong,
would regress behaviour, or asks for a mute. A loop-guard (act only on a
review newer than the PR's last commit *and* the workflow's last
comment) prevents re-processing the same review.

### Track A — `[leak-scan]` runtime leak → `[leak-fix]` PR
For the selected proven leak it:
1. Writes a focused regression test in `Controls.Core.UnitTests`.
2. Builds MAUI **from source** and confirms the test **FAILS on `main`**
— proving it catches the leak.
3. Implements the minimal, idiomatic managed fix — a weak subscription /
teardown mirroring the existing `WeakEventManager` / `WeakNotify*Proxy`
patterns.
4. Rebuilds and confirms the **same test now PASSES**, no neighbouring
regressions.
5. Opens a **draft `[leak-fix]` PR** with `Fixes #N` and the red→green
evidence.

### Safety
- Enforces red→green **in both directions** — a fix without a
demonstrated failing-then-passing test is rejected.
- **Never** mutes / skips / disables a test; rejects its own attempt if
the only thing that goes green is a mute — **including when a review
asks for one** (it pushes back with a comment instead).
- **One action per run** — Track C review-response *or* one new Track A
`[leak-fix]` PR, never both.
- Writes only via scoped safe-outputs (agent job is read-only); PR
branches are limited to `leak-fix/**`, changes to managed `src/**` (+
`PublicAPI.Unshipped.txt`).
- Skips cleanly if already fixed on `main`, out of scope (needs a device
fix), or attempt-capped.

---

## Validated end-to-end on **dotnet/maui itself** (pre-merge)

Both workflows were executed on this repo's own Actions infrastructure
(via short-lived `push`-triggered test branches, since
`workflow_dispatch` only lights up once a workflow is on `main`). Real
outputs, all on **dotnet/maui**:

- **Multi-leak in one run** — a single hunter run filed **5** distinct
proven `[leak-scan]` issues via the catalog-seeded sweep: #36343
`SwipeItemView.Command`, #36344 `ListView.RefreshCommand`, #36345 `Shell
BackButtonBehavior.Command` (all `ICommand.CanExecuteChanged`), #36346
`Picker.ItemsSource`, #36347 `IndicatorView.ItemsSource`
(`CollectionChanged`). #36344 and #36345 are leaks not previously
tracked upstream.
- **Proven-only** — a later run filed `[leak-scan]` #36350
`CollectionView.SelectedItems` and (correctly) **nothing else**, having
de-duped the already-filed leaks.
- **Track A fix** — #36309 `[leak-fix] Fix ResourceDictionary
MergedDictionaries memory leak` (regression test red→green + managed
fix).
- **Track C review-response** — on #36253 the fixer independently
re-read the code, agreed with the reviewer's findings, validated the
reviewer's `WeakEventManager` approach (24/24, red→green), and posted
the concrete fix.

---

## Notes for reviewers

- Everything the workflows file/open is **AI-generated** and clearly
labelled as such; treat them as high-quality drafts for human review.
- The workflows are self-contained (`.md` source + compiled
`.lock.yml`); merging them enables the `schedule` triggers on `main`.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Backport of #35049 to main

/cc @PureWeen

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Updated [Magick.NET-Q8-AnyCPU](https://github.com/dlemstra/Magick.NET)
from 14.13.1 to 14.14.0.

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

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

## 14.14.0

### What's Changed
- Renamed `ExifParts` to `ExifIfds` and renamed `ExifProfile.Parts` to
`ExifProfile.AllowedIfds` and mark the old names as obsolete.
- Store the exif ifd in the ExifTag to make prevent marking a tag as
duplicate when it is found in another ifd (#​2017)
- Fixed Regression: Clip() doesn't take the correct bounding box
(#​2019)
- Fixed Regression: ColorType is no longer persisted (#​2020)
- Fixed Native DLLs (Magick.Native-Q16-*.dll) appear at project root in
Solution Explorer on .NET Framework 4.8 (#​2029)

### Related changes in ImageMagick since the last release of Magick.NET:
- Heap Buffer Underwrite in Floyd-Steinberg depth dithering
(GHSA-2hhq-c99x-492r)
- Stack Overflow in MVG decoder
(GHSA-h36c-3666-h489)
- Infinite Loop in subimage-search with crafted image
(GHSA-5v62-8fq6-cp9m)
- Policy Bypass in DCM decoder could result in image with invalid
dimensions
(GHSA-8pj9-6897-74xc)
- Policy Bypass can read disallowed files
(GHSA-xcjm-wqff-m669)
- Heap Buffer Over-Write in MAT decoder on 32-bit systems
(GHSA-4v89-6mgq-6rgc)
- Policy Bypass can trigger out-of-Memory condition
(GHSA-q62c-h75r-2xhc)
- Heap Buffer Over-Write in ICON decoder due to incorrect loop
(GHSA-g22q-f7gc-5jhr)
- Use-After-Free when allocation in CheckPrimitiveExtent fails
(GHSA-px7q-ggqj-hcf2)
- Null Pointer Dereference in distort operation when passing incorrect
arguments
(GHSA-p9rq-q46c-g4x6)
- Memory Leak in wand option parser when providing invalid arguments
(GHSA-j989-f892-2335)
- Heap Buffer Over-Write in SF3 encoder when writing multi-frame image
(GHSA-44cp-c3ww-9rv5)

### Library updates:
- ImageMagick 7.1.2-25 (2026-06-04)
- aom 3.14.1 (2026-05-22)
- libde265 1.1.0 (2026-05-26)
- openexr 3.4.12 (2026-05-25)
- libheif 1.23.0 (2026-05-29)

**Full Changelog**:
dlemstra/Magick.NET@14.13.1...14.14.0

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

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

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

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

---

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

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

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…empt human hand-off) (#36317)

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

## What this changes

Today the `ci-status-fix` agentic workflows (`main` + `net11.0`) open
**one** `[ci-fix]` PR per failing-CI tracking issue and then **hand off
to a human forever** — nobody re-checks whether the fix actually turned
CI green, and if it didn't, the loop never tries again.

This PR turns them into a **self-watching loop**: on each scheduled poll
the workflow re-reads the CI of the PR it already opened, and — when the
failure is caused by its own fix — pushes a **fresh follow-up commit
onto the same PR**, up to **10 attempts**, with **no human intervention
between attempts**. It stays **one PR per issue, forever** (never a
second PR), and stops + hands off to humans only after 10 attempts.

Round 1 keeps a human in the loop for exactly one thing: typing `/azp
run maui-pr` to kick CI on each new commit (a `GITHUB_TOKEN` push
doesn't fire CI). Everything else — watch, classify, re-fix — is
autonomous. Auto-CI-triggering is deferred to Phase 2 (see the
`GH_AW_CI_TRIGGER_TOKEN` note under **Validation & operation**).

The loop also **responds to maintainer review feedback** (Track C): when
a human maintainer (OWNER/MEMBER/COLLABORATOR relationship) formally
requests changes on the open PR, it applies the valid findings and
pushes back on the rest — one push + one comment — rather than sitting
idle waiting for a human to also make the edit.

## How it works

```mermaid
flowchart TD
    A[Scheduled poll every 12h] --> B[pre_activation job:<br/>Query-CiFixPRs.ps1 prefetch]
    B --> C{Open ci-fix PR<br/>for this issue?}
    C -- No --> D[FRESH: open ONE draft PR<br/>seed marker 1/10]
    C -- Yes --> E{Watch state machine}
    E -- Maintainer (OWNER/MEMBER/<br/>COLLABORATOR) requested changes<br/>gate 0, highest priority --> M[Track C: apply valid findings,<br/>push back on rest —<br/>one push + comment]
    E -- Human commented / pushed / reviewed --> F[Skip — defer to human]
    E -- CI still pending --> G[Wait, re-check next poll]
    E -- CI green --> H[Surface + comment, don't advance]
    E -- CI red --> I{Classify red on<br/>the PR's OWN build}
    I -- Unrelated flake --> J[Annotate + comment,<br/>don't burn an attempt]
    I -- Caused by the fix & attempt < 10 --> K[ADVANCE: push follow-up commit<br/>to SAME branch, bump marker N+1/10]
    I -- attempt = 10 --> L[Hand off: needs-human]
```

### 1. Deterministic prefetch — `.github/scripts/Query-CiFixPRs.ps1`
(new)
Runs in a pre-agent `pre_activation` job (not by the model), so it never
executes PR-controlled code. It lists open `ci-fix/**` PRs and emits
JSON per PR: number, head ref/SHA, `refsIssue`, `isDraft`,
settled/overall CI conclusion, per-leg failures, a `humanEngaged` flag
(reviews/comments/non-bot pushes), and the parsed `<!-- ci-fix-attempts:
N/10 -->` marker. The agent consumes this via
`needs.pre_activation.outputs.ci_fix_candidates` — no blind re-querying.

### 2. Attempt counter = a body marker
Each PR body carries `<!-- ci-fix-attempts: N/10 -->`. FRESH seeds
`1/10`; every ADVANCE bumps it via `update-pull-request`. If the marker
is ever missing, the agent reconstructs the count from the bot commits
already on the branch.

### 3. Keep-ONE-PR advance (`push-to-pull-request-branch`)
When a red build is classified as caused by the fix, the agent checks
out the **existing** PR branch at its remote tip (guarded by a head-SHA
equality check against the classified commit), commits **one new,
distinct** fix, and uses `push-to-pull-request-branch` to add it to the
same PR — plus `update-pull-request` (marker bump) and `add-comment`
(attempt note). It never opens a second PR.

### 4. The watch state machine (per open PR)
Ordered gates: human-engaged → skip · CI pending/unknown → wait · green
→ surface + comment (don't advance) · red → classify on the PR's **own**
build (`maui-pr` for `C.headSha`): unrelated-flake → annotate, don't
burn an attempt; caused-by-fix → advance if `attempt < 10`, else hand
off `[ci-fix][needs-human]`.

### 5. `net11.0` twin
`ci-status-fix-net11.md` mirrors the redesign for the `net11.0` branch:
base/label/scanner token swaps, cross-reference inversions, and the
net11-only `checkout.fetch: [net11.0]` + transport-patch-cap rationale
(a `main`-based patch for a `net11.0` fix would exceed gh-aw's 10 MB
cap, which is why the two are separate workflows).

### 6. Review-response (Track C — respond to a maintainer's
change-request)
Gate 0 of the watch state machine (highest priority, checked before
"human engaged"): a `CHANGES_REQUESTED` review is the ONE case where a
human touching the PR means *"act on my instruction"*, not *"back off"*.
When the open PR carries an un-addressed change request from a **human
maintainer with an established repo relationship**
(OWNER/MEMBER/COLLABORATOR), the agent reads the findings, classifies
each as **APPLY** (correct + in-bounds) or **PUSH BACK** (wrong / out of
area bounds / would weaken a test), applies only the APPLY items in
place, and emits one push + one comment listing what it did and why it
declined the rest. Guards:
- **Author filter (the hardening):** only reviews where `state ==
"CHANGES_REQUESTED"` **and** `user.type == "User"` (and the author is
not in the bot denylist) **and** `author_association ∈ {OWNER, MEMBER,
COLLABORATOR}` are actionable. Bot reviews and drive-by reviews from
`CONTRIBUTOR`/`FIRST_TIME_CONTRIBUTOR`/`NONE` accounts are ignored. Note
`author_association` is a **coarse relationship signal, not a per-repo
write-permission check** — it is a cheap pre-filter, not an
authorization gate. The real safety comes from the narrow APPLY bounds
below (`src/**` + PublicAPI only, never mute a test), a defense-in-depth
carve-out to Hard-Rule 10 ("review content is untrusted by default").
- **Per-review idempotency:** each maintainer review is answered at most
once. The agent stamps the answered review id into its response comment
(`<!-- ci-fix-track-c-responded: <RID> -->`); the deterministic prefetch
fully paginates the PR's comments and hands the agent the set of
already-answered ids (`respondedTrackCReviewIds`), so a review is
actionable only if its id is **not** in that set. A secondary
`submitted_at >` last-commit guard remains on the APPLY path. This
replaces the earlier "newer than the last bot comment" timestamp
heuristic, which could silently re-fire the same decline every run on a
PR with more than one page (100) of comments.
- **Attempt accounting:** an APPLY commit counts toward the same `≤ 10`
bot-commits-per-PR ceiling; a PUSH-BACK-only response makes no commit
and consumes no attempt. In-bounds means `src/**` + PublicAPI only,
never muting a test.
- Reuses the existing ADVANCE emit trio (push + marker bump + comment) —
**no new safe-output, permission, or config surface** (the compiled-lock
delta is `body_hash` only).

## Safety &amp; scoping

The loop runs **live** (`safe-outputs.staged` is not set) and holds
`pull-requests: write`, so every write path is scoped at the **handler**
level, not just by prompt text:

| Safe output | Handler-level scope |
|---|---|
| `push-to-pull-request-branch` (code) | `required-title-prefix:
"[ci-fix] "` + `required-labels: [agentic-workflows]` + `allowed-files`
allowlist |
| `add-comment` | `required-title-prefix: "[ci-fix] "` +
`required-labels: [agentic-workflows]`, `discussions: false` |
| `update-pull-request` | `title: false` → `allow_title:false` (no
retitles); body-marker edits only |
| `create-pull-request` | `[ci-fix]` title prefix + `agentic-workflows`
label; `allow-empty` intentionally unset |

- **Reads / triggers are integrity-gated** — `min-integrity: approved`
filters PR/issue content to trusted authors (OWNER/MEMBER/COLLABORATOR)
before the agent ever sees it.
- **Review-response is relationship-gated (Track C):** the sole path
that treats review *content* as an instruction requires a
`CHANGES_REQUESTED` review from a human (`user.type == "User"`, not in
the bot denylist) whose `author_association ∈ {OWNER, MEMBER,
COLLABORATOR}` — a coarse relationship pre-filter, **not** a per-repo
write-permission check — and even then may only touch `src/**` +
PublicAPI and may never mute a test. Bot and
outside/first-time-contributor reviews stay non-actionable.
- **`update-pull-request` caveat (documented inline in both twins):**
gh-aw v0.79.8's compiler silently drops
`required-title-prefix`/`required-labels` from *this one* handler —
verified against the compiled `.lock.yml`, unlike `add-comment` /
`push-to-pull-request-branch` which do emit them. So it can't be
prefix-locked the same way; we remove the sharpest capability instead
(`title: false`), leaving only body-marker edits on an already
`min-integrity:approved` target.
- **Keep-ONE-PR / no duplicates:** `create-pull-request` does not set
`allow-empty`, and the fixer dedups by `Refs: dotnet/maui#<N>` + issue
number (the `ci-scan-fingerprint` marker is *optional* and never the
dedup key), so a re-poll advances the existing branch instead of
spawning a second — or empty — PR.
- **No cost guardrail:** `max-ai-credits` / `max-daily-ai-credits` are
`-1` (unlimited). A live auto-fixer must not silently stall mid-loop on
a budget cap — a deliberate maintainer trade-off, not an oversight.

## Validation &amp; operation (round 1)

1. **Scoped dispatch:** Actions → "CI Failure Fixer (main)" → Run
workflow → `issue_number` (e.g. `36180`) drives one issue; empty runs
the full scheduled sweep. A `dry_run` input gives a live-but-write-free
canary.
2. **Exercise the commit:** when the loop pushes, a maintainer types
`/azp run maui-pr` (+ the gated `maui-pr-uitests` /
`maui-pr-devicetests` legs when relevant). A bare `/azp run` does
**not** count as human engagement, so the loop keeps watching.
3. **Open item — `GH_AW_CI_TRIGGER_TOKEN`:** a bot
`push-to-pull-request-branch` uses `GITHUB_TOKEN`, which does **not**
re-fire the AzDO `maui-pr` webhook build — that's why the manual `/azp
run` exists in round 1. A provisioned PAT/OIDC trigger token (Phase 2)
would remove that human step; **until then the token is a harmless
no-op** and the `/azp run` step is the expected round-1 behavior.

## Files
| File | Change |
|------|--------|
| `.github/scripts/Query-CiFixPRs.ps1` | **new** — deterministic
prefetch |
| `.github/workflows/ci-status-fix.md` (+`.lock.yml`) | keep-one loop +
watch state machine + Track C review-response + scoped safe-outputs |
| `.github/workflows/ci-status-fix-net11.md` (+`.lock.yml`) | net11.0
mirror |

Both `.lock.yml` were recompiled in the same commit as their `.md`
source (per pipeline security rules). No `cgmanifest.json` /
`templatestrings.json` changes.

---------

Co-authored-by: PureWeen <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ption-wiring & feed-drift checks (evolve #36268) (#36213)

&lt;!-- Please let the below note in for people that find this PR --&gt;
&gt; [!NOTE]
&gt; Are you waiting for the changes in this PR to be merged?
&gt; 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!

### What

Makes the local ask **"run release readiness skill to see if net11
preview6 is ready"** consult the *authoritative* official-preview build
**and** verify the preview branch is actually ship-wired — not just
public CI/regression health. Three files:

**1. `release-readiness/SKILL.md` — net-new bridge (the star of this
PR).**
A new **Preview: authoritative blessed-build source** subsection so the
`release-readiness` skill, after its public survey, runs the access gate
and — when the caller has access **and** the plugin is enabled — invokes
the private **`dotnet-release-tracker`** plugin for the blessed build /
BAR id + stage, then combines that with the CI/regression verdict. It
branches on the gate token (`AVAILABLE_ENABLED` → use the plugin;
`AVAILABLE_NOT_ENABLED` → offer the opt-in; `ACCESS_ON_INACTIVE_ACCOUNT`
→ advise an account switch; `NO_ACCESS` → **public-feed fallback**:
report the latest build on the public Preview N channel as a *labeled
candidate* that may not be the official/blessed build, without naming
the private tool) and adds a **"Blessed ≠ green"** caveat so the blessed
build never masks open `regressed-in-*` blockers. DRY — it
cross-references dependency-flow's tier table / opt-in / guardrails
rather than duplicating them.

**2. `dependency-flow/` gate — evolves the version already merged in
#36268.**
The deterministic classifier `scripts/Get-PreviewReleaseReadiness.ps1`
emits:

```
RELEASE_TRACKER_STATUS = NO_ACCESS | ACCESS_ON_INACTIVE_ACCOUNT | AVAILABLE_NOT_ENABLED | AVAILABLE_ENABLED
```

It checks (1) GitHub read access to the private marketplace repo that
hosts the internal **.NET Release Tracker** plugin and (2) whether that
plugin is enabled locally. It fetches **no** release data and always
exits `0`. This PR carries improvements over the version on `main`:

- **JSONC-tolerant** enabled-plugin parser — the strict
`ConvertFrom-Json` on `main` chokes on the `//`-commented opt-in snippet
the skill itself documents;
- `$USERPROFILE` support (Windows user scope) alongside `$HOME`;
- **multi-account advisory** — when the active `gh` identity can't read
the repo but a logged-in *inactive* account can, the gate emits
`ACCESS_ON_INACTIVE_ACCOUNT` and advises `gh auth switch --user
<account>` instead of a false-positive `AVAILABLE` (the plugin loads
under the *active* identity). Only fires when access is confirmed on
some account, so a true no-access caller still gets a silent
`NO_ACCESS`;
- `-ReleaseRepo` / `-PluginId` / `-Json` parameters and a public-safe
`.NOTES` contract;
- try/catch hardening so an unexpected terminating error still emits the
safe `NO_ACCESS` default;
- the *"why a special source"* / Preview 6 (#35364) trap prose in
`SKILL.md`.

&gt; **Relationship to #36268.** #36268 ("public-safe preview release
readiness gate") already merged the first version of this gate. This PR
is a **forward-evolution** of those two files, **plus** the net-new
release-readiness bridge — it does **not** revert any shipped behavior.
In particular the plugin opt-in stays **user-scope only**
(`~/.copilot/settings.json`); there is no committable project-scope
enablement, so forks and no-access users are never silently opted in.
The "comment-only on GitHub" guardrail is retained.

**3. Preview wiring checks — subscriptions + feed drift + component pins
(net-new).**
A preview can pass CI and even have a blessed build yet still not be
*ship-wired*. Three **public** (BAR/Maestro + git) checks close that
gap:

- **Check A — subscriptions wired?** Confirm `release/11.0.1xx-previewN`
has its default-channel mapping **and** the baseline three subs (android
+ macios + dotnet on `.NET 11.0.1xx SDK Preview N`). Branch cut +
default-channel present but **zero subs** = a start-of-preview flow gap
→ surfaced as an **FYI note** (not a ship blocker); the skill still
knows how to remediate via the existing **combined-PR pattern** (DRY,
honoring its confirm/draft-PR gate).
- **Check B — feed matches the branch?** Compare the latest build
promoted to the `.NET 11.0.1xx SDK Preview N` channel
(`maestro_latest_build`) against `origin/release/11.0.1xx-previewN`
HEAD. Branch ahead of the promoted build = stale feed → flag.
- **Check C — component pins coherent?** Report which `dotnet/android`,
`dotnet/macios`, and `dotnet/dotnet` (VMR) builds MAUI bundles (version
+ SHA from `eng/Version.Details.xml`) and confirm they **match the
inflight `netN.0` branch the preview was cut from**. Match = clean cut
✅; divergence or an off-band pin (macios/dotnet missing the
`-net11-pN`/`preview.N` stamp) → flag. The `.NET Release Tracker`
exposes **only** SDK/runtime-level data, so there is **no** "blessed"
per-component android/macios build to look up — this is git+BAR only.
"Behind the latest component build" is *expected* for a cut branch
(don't flag it); android's `-ci.main.NN` scheme is normal for net11 and
validated against inflight rather than alarmed on.

Mechanics (exact MCP/`darc`/git commands, interpretation tables,
remediation, and **live net11 Preview 6 worked examples**) live in a new
**"Wiring checks: is Preview N actually plumbed?"** subsection (Checks
A/B/C) in `dependency-flow/SKILL.md` (its Maestro/subscription domain);
`release-readiness/SKILL.md` gets a short orchestration hook that
cross-references it and folds the results into the preview report.

**4. Preview generator — scope Maestro PRs to the target branch (net-new
bug fix).**
`scripts/Get-PreviewReadiness.ps1` (the deterministic generator the
GitHub Action runs to author the `[Release Readiness]` preview tracker,
e.g. #35866) was listing Maestro / dependency-flow PRs that target
`netN.0` (the **inflight** branch) inside the preview tracker's own
"Maestro / dependency-flow PRs" section. Once a preview is **branched**,
those `netN.0` bumps belong to the inflight branch's own readiness, not
the preview tracker. `Get-CategorizedPullRequests` now computes the
Maestro bucket from `$TargetPRs` (the survey ref) **only** instead of
target + inflight, so `netN.0` (inflight) Maestro PRs land in no
rendered bucket and are intentionally dropped from a branched preview
tracker. Non-Maestro inflight PRs still surface unchanged in the
Inflight-human bucket. In **candidate** mode the survey ref *is*
`netN.0` and the inflight list is empty, so target-only is correct there
too. Unit tests (`tests/Test-ReleaseReadiness.ps1`, precedence +
AutomationNull null-safety) updated to assert target-only scoping,
including a new assertion that an inflight Maestro PR appears in no
bucket.

**5. Surface human-authored dependency-bump PRs in High-priority items +
drift-proof SR E2E tests (net-new).**
Two follow-ups in `scripts/Get-PreviewReadiness.ps1`:

- **Dependency-bump detection was author-only.** The component-bump PR
that *is* the release (e.g. #36433 — `rmarinho`, "Bump dotnet/dotnet
(BAR 321614), dotnet/android (BAR 321622) and dotnet/macios (BAR
321780)", head `update-321614`, no labels) was authored by a human, so
the old `-match "dotnet-maestro"` author filters missed it and it fell
into the generic release-branch bucket instead of **High-priority
items**. A new `Test-IsDependencyFlowPr` helper now flags a PR as
dependency-flow if it matches *any* of: `dotnet-maestro` author **OR** a
`Bump dotnet/(dotnet|android|macios|runtime|sdk|…) … (BAR NNN)` title
**OR** an `update-<id>` head ref. The three maestro bucket filters were
rewired to use it, and the high-priority row kind was renamed `📦 Maestro
PR` → `📦 Dependency-flow PR`. Merge-up PRs (`[automated] Merge branch
…`, head `merge/…`) are intentionally *not* matched.
- **Human-notes block repositioned.** The blessed-build / wiring /
component-pin notes now render directly under **High-priority items**
(previously below the Target section), so the authoritative-build
context sits next to the items it qualifies.
- **Drift-proof SR E2E tests.** The end-to-end tests in
`tests/Test-ReleaseReadiness.ps1` run the *real* detector against the
live repo and had pinned a specific SR as the not-yet-cut candidate;
when that SR shipped/cut the fixtures rotted (7 stale failures). They
now **derive** the in-flight/candidate split structurally from the
detector output (≥1 SR, exactly one candidate numbered one past the
highest in-flight SR, clean partition, regression-label formula mirrored
from `New-RegressionLabelList`), so they survive every future SR
cut/ship without a per-cut edit.

**6. Action-owned best-effort component-build section (net-new).**
The authoritative *blessed* build lives in the private **.NET Release
Tracker** (`dotnet/release`), which the GitHub Action's repo-scoped
`GITHUB_TOKEN` **cannot** reach — so on an automated run that row can
only come from a maintainer's local notes (spliced into the preserved
human-notes block). To give the Action *something* to say on its own,
`scripts/Get-PreviewReadiness.ps1` now emits a **best-effort**
component-build section sourced from the branch's own
`eng/Version.Details.xml` (a **public** git source always readable in
CI). A new `Get-BranchComponentPins` reads the `dotnet/dotnet`
(VMR/SDK), `dotnet/android` and `dotnet/macios` anchor pins (version +
commit SHA) and renders a `🏷️ Preview N component build — branch pins
(best-effort)` table. It is **explicitly labeled NOT a confirmed blessed
build** — it reports what's *currently bundled on the branch* and points
maintainers to the **Release Captain Notes** block (filled locally with
tracker access) for the authoritative designation. The section renders
**outside** the human-notes markers so it **self-refreshes** on every
automated re-run (verified: after #36433 merged, the pins advanced to
the post-bump build automatically), and it surfaces an open
component-bump PR (e.g. #36433) as a *pending advance* when one is still
open. `Get-BranchComponentPins` handles the `[xml]` attribute-vs-child
gotcha (`Name`/`Version` are attributes; `Uri`/`Sha` are child
elements), prefers the most representative dependency name per repo with
a `Uri`-based fallback, and returns `$null` (no throw) when the file
can't be read/parsed. Adds 9 unit assertions. Full suite: **794 passed /
0 failed**.

### Why

During the Preview 6 cycle (see #35364), two same-band VMR builds (e.g.
`…26325.125` vs `…26326.122`) looked interchangeable. Public BAR/Maestro
data can enumerate candidate builds but **cannot, on its own, identify
which staged build releases.dot.net has *blessed* as the official
preview**. That authoritative signal lives in the internal release
tracker. This change lets developers *with access* get the authoritative
answer automatically from the `release-readiness` skill, while
developers *without access* fall back to the **public preview-feed
candidate** — the latest build promoted to the public Preview N channel,
explicitly labeled as possibly-not-the-official build — with the private
*tool* never named or implied. The wiring checks add the complementary
*"is the branch even receiving flow, and is its feed current?"* signal —
validated live: net11 Preview 6 is branched with a promoted build **but
has no subscriptions authored yet** (Preview 5's set was never rolled
forward), exactly the gap Check A surfaces (as an FYI).

### Privacy / safety

The plugin is **double-gated** (GitHub read access to load it + an
authorized Azure AD identity to pull data), so referencing it from this
public repo is safe. The change deliberately:

- contains **no** Azure AD resource ids / `api://…` audiences, backend
hostnames, or internal endpoint paths — only the sanctioned *marketplace
pointer* (repo name + plugin name);
- performs **no** fetch-and-exec of remote code;
- defaults to `NO_ACCESS` for any unconfirmed-access case, so the agent
**never** reveals the private plugin *tool* to users who can't use it —
the NO_ACCESS path now emits an honest, public-source-labeled
preview-feed candidate (public data), which reveals nothing about the
gated tooling — the multi-account advisory only fires when access is
*confirmed* on some logged-in account, and never prints a token;
- keeps the opt-in **user-scope** (personal `~/.copilot/settings.json`),
so forks and no-access users are unaffected;
- the wiring checks read only **public** BAR/Maestro + git data and
never mutate config — remediation is opt-in and routes through the
documented confirm/draft-PR gate.

### Testing

`scripts/Get-PreviewReleaseReadiness.ps1` was exercised across all
states locally with `pwsh` (token **and** `-Json` forms):

| Scenario | Result |
|----------|--------|
| Real access probe (`dotnet/release`), plugin enabled in
`~/.copilot/settings.json` (JSONC w/ comments) | `AVAILABLE_ENABLED`,
exit 0 |
| Real access probe, plugin not enabled | `AVAILABLE_NOT_ENABLED`, exit
0 |
| Active identity lacks access, but a logged-in inactive account has it
| `ACCESS_ON_INACTIVE_ACCOUNT` + `gh auth switch --user &lt;account&gt;`
advice, exit 0 (and `GH_TOKEN` restored after probing) |
| Same user settings with `: false` | `AVAILABLE_NOT_ENABLED` (correctly
not matched), exit 0 |
| Nonexistent repo (no account can read) | `NO_ACCESS`, exit 0 |

The wiring checks (items **3A/3B**) were validated against **live
Maestro/BAR + git** for net11 Preview 6:
`maestro_subscriptions(targetBranch="release/11.0.1xx-preview6")` → **0
rows** (FYI note correctly surfaced); `maestro_latest_build(".NET
11.0.1xx SDK Preview 6")` → build #321033 @ `6e35dc58d0` == branch HEAD
(feed current); Check C (component pins) → dotnet/dotnet
`11.0.0-preview.6.26325.125`, dotnet/macios `26.5.11717-net11-p6`,
dotnet/android `37.0.0-ci.main.51` all **byte-identical to `net11.0`
HEAD** = clean cut.

The **Action-owned best-effort component section** (item **6**) is
unit-tested (9 assertions over `Get-BranchComponentPins`: parse
correctness, name preference, `[xml]` attribute/child handling,
unreadable-file → `$null`) and validated end-to-end by dispatching the
real GitHub Action against this PR branch — the section rendered on
#35866 sourced purely from `eng/Version.Details.xml` and self-refreshed
to the post-#36433 pins with no local tracker access. Full suite: **794
passed / 0 failed**. Docs/skill-only change — no product code or public
API is affected.

---------

Co-authored-by: PureWeen <223556219+Copilot@users.noreply.github.com>
…r) (#36460)

<!-- 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 **two net-new** [GitHub Agentic Workflows](https://gh.io/gh-aw)
that keep dotnet/maui's own gh-aw setup current. This is
**maintenance-only automation** — it does **not** touch the existing 11
gh-aw workflows, product code, or CI. Both are **credential-free** on
the write path (they use only the default `GITHUB_TOKEN` via
safe-outputs); the Copilot PAT pool is used solely for model
**inference**, exactly like every existing MAUI agentic workflow.

### Workflow A — `aw-actions-update.md` ("Action Pin Refresh")
Low-risk action-pin refresher.
- **Triggers:** weekly `schedule` + `workflow_dispatch`, pinned to
`main` (`checkout: ref: main`), fork-guarded.
- **What it does:** installs the gh-aw CLI **pinned to v0.80.9** (the
same `compiler_version` as the committed locks, so `actions-lock.json`
stays consistent with them — no version skew; failing closed if that
exact version can't be installed), runs `gh aw update`, then opens a PR
**only** when `.github/aw/actions-lock.json` changes (the SHA-pin
lockfile for the actions our workflows use).
- **Blast radius pinned:** `allowed-files` restricts the write to that
single file, and `protected-files: allowed` is scoped to just that one
path under `.github/`. Generated `.github/workflows/*.lock.yml` and any
source-workflow drift are explicitly discarded (including brand-new
**untracked** files, via a scoped `git clean`) and verified out with
`git status --porcelain` — this workflow can *only* touch the actions
lock.
- De-dupes against its **own** open `[actions]` PRs (scoped to `--author
"app/github-actions"`); no-ops quietly when there's nothing to update.

> **Known behavior (by design, not a defect):**
> - The PR only edits `.github/aw/actions-lock.json`. Because each
`.lock.yml` embeds its resolved action SHAs, the refreshed pins take
runtime effect only after the workflows are **recompiled** (`gh aw
compile`) — which is Workflow B's maintainer runbook. Pushing
regenerated `.lock.yml` files would require a GitHub-App `workflows:
write` token this credential-free workflow deliberately avoids.
> - Because the PR is created with the default `GITHUB_TOKEN`, it will
**not** auto-trigger CI (GitHub platform rule: `GITHUB_TOKEN` pushes
don't fire workflow events). A maintainer may need to nudge CI (e.g.,
close/reopen the PR or push an empty commit).

### Workflow B — `aw-version-update.md` ("Agentic Workflow Version
Auto-Update")
gh-aw version updater, **detect → file issue** design (fully automatic,
credential-free).
- **Triggers:** weekly `schedule` (live) + `workflow_dispatch`, pinned
to `main`, fork-guarded.
- **What it does:** a **read-only** detector (`permissions: { contents:
read, issues: read }`) installs/refreshes the gh-aw CLI **to the latest
release** (detecting newer versions is its whole purpose), runs `gh aw
upgrade` + `gh aw compile`, and checks whether that produces a non-empty
change set (`git status --porcelain`, so brand-new untracked locks are
caught). It then hard-resets its worktree so nothing leaks out of the
detection run.
- **If an upgrade is pending,** it emits exactly **one** `create-issue`
— a `[Auto Update]` tracking issue asking a maintainer to run `gh aw
upgrade` locally and open the PR. The issue is filed with the default
`GITHUB_TOKEN` (`issues: write`, granted to the separate safe-outputs
job). Steady state is `noop` (no issue, no noise).
- **De-dupes** against its **own** open `[Auto Update]` issues (scoped
to `--author "app/github-actions"`), and runs with `min-integrity:
approved` so community content stays out of the agent's view.

> **Why an issue instead of an automated PR (deliberate design):** `gh
aw upgrade` / `gh aw compile` regenerate `.github/workflows/*.lock.yml`,
which the default `GITHUB_TOKEN` cannot push (GitHub platform rule) and
which would otherwise require a Copilot-licensed / `workflow`-scoped
agent token this repo intentionally does **not** provision. Filing an
issue keeps the workflow fully automatic and credential-free; a
maintainer performs the actual upgrade. There is **no**
`create-agent-session`, `GH_AW_AGENT_TOKEN`, or staged-delegation step.

Both workflows reuse MAUI's existing Copilot PAT-pool import +
`copilot-pat-pool` environment (inference only), carry a fork guard
(won't run in forks), and were compiled with **gh-aw v0.80.9** — the
same `compiler_version` as all 11 existing locks, so no other lock files
are bumped.

## Validation
- ✅ `gh aw compile` — **0 errors, 0 warnings** on both.
- ✅ `gh aw lint` — clean across all workflows.
- ✅ gh-aw security review (gh-aw-guide scanner) — clean on both.
- ✅ Scope check — only the 4 new workflow files (2 `.md` + 2 generated
`.lock.yml`); the existing 11 workflows are untouched. No auto-generated
files (`cgmanifest.json`, `templatestrings.json`) changed.

## Rollout
- **Workflow A** can be enabled immediately — low-risk, single-file,
human-reviewed PRs.
- **Workflow B** is safe to run live on merge — its only possible write
is a single tracking issue for a maintainer; the actual upgrade is
always human-performed. No secrets to provision.

## Notes for reviewers
- No hardcoded PATs; both use the standard `COPILOT_PAT_0..9` pool via
the existing `shared/pat_pool.md` import (inference only).
- No auto-merge — every PR/issue these produce is
human-reviewed/actioned.
- `.lock.yml` files are auto-generated; regenerate via `gh aw compile
<name>`, never hand-edit.

<sub>Co-authored-by: Copilot App</sub>

---------

Co-authored-by: PureWeen <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!

## Summary

- Reverts the iOS layout changes from #34936 for `Default` and `Fixed`
`FlyoutHeaderBehavior`.
- Restores the prior overlapping ScrollView frame and top content inset,
allowing flyout items to scroll behind a semi-transparent header.
- Removes the regression test that asserted the reverted behavior.
- After merge, backport this commit to `release/10.0.1xx-sr9` for
10.0.90.

Fixes #36249

## Test plan

- `pwsh .github/skills/run-device-tests/scripts/Run-DeviceTests.ps1
-Project Controls -Platform ios -TestFilter "Category=Shell"` (203
passed)

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!

Fixes #36154.

Forward-ports the final implementation and regression coverage from
#36231 to `main`, preserving the newer WebView lifecycle handling
already present on `main`.

The Android SwipeView now yields to a nested WebView while it can scroll
in the gesture direction, and handles the gesture at the WebView edge.

---------

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!

## Summary

- Advances `main` from the SR9 `10.0.90` cycle to the SR10 `10.0.100`
cycle.
- Keeps `SdkBandVersion` and prerelease settings unchanged.
- Matches the previous cycle bumps in #35433 and #35879.

This clears the `Main bumped to SR10 cycle` release-readiness blocker
for 10.0.90.

_This PR was created by GitHub Copilot CLI on behalf of @kubaflo._

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

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

## What this changes

Follow-up to #36317 (the self-watching `ci-status-fix` loop). Today,
when a `[ci-fix]` draft PR's CI comes back green — or red only on
**unrelated** flakes — the loop posts a comment but **leaves the PR as a
draft forever**. A maintainer has to notice it, confirm the specific
fixed test actually passed, and flip it to ready. In practice these
validated-green draft PRs sit unreviewed for weeks.

This PR adds a **target-test verification + mark-ready gate (Step 3.6)**
to both twins (`main` + `net11.0`). When a draft `[ci-fix]` /
`[ci-fix-net11]` PR reaches the green-surface or unrelated-flake branch,
the loop now drills into the PR's **own** AzDO test-results for the
**specific test(s)** the fix targeted. If every target test is `Passed`
on ≥1 leg and `Failed` on none (VALIDATED-GREEN), it:

- posts a `🎯 Target test validated green on <headSha>` comment (naming
the test + legs + buildId), and
- transitions the draft PR to **ready for review**.

This is a **state transition only** — it never approves and never
merges; a human still reviews and merges. Overall red on **unrelated**
legs no longer keeps a validated fix parked as a draft.

## How it works

- **Preconditions** (all required): PR `isDraft == true`; it is
unmistakably this workflow's own PR (`[ci-fix]`/`[ci-fix-net11]` title
prefix **and** `agentic-workflows` label); and it was reached from the
green or **unrelated-flake** path (never from caused-by-fix — that path
advances an attempt instead).
- **T1 — identify target test(s)** from the `[ci-scan]` issue signature
+ the PR diff. If no specific test can be identified (e.g. a product
build-break), it records a skip — build-only fixes are validated by
overall-green, which the existing green branch already handles.
- **T2 — drill AzDO test-results** for the build(s) on the PR's current
head SHA, filtered to the target test's `testCaseTitle`. A test that
never ran (e.g. an `/azp`-gated `maui-pr-uitests`/`maui-pr-devicetests`
leg that wasn't kicked) is **not** validated — the loop records an
honest "not yet executed" skip and does **not** mark ready. No
overclaiming: a green *sibling* leg is not the target test.
- **T3 — mark ready + report**, guarded by a per-head-SHA idempotency
marker and the existing `dry_run` gate (dry-run emits nothing and
tallies `would-mark-ready`).

## Safe-output

Adds the `mark-pull-request-as-ready-for-review` safe-output to both
twins (`max: 3`, `target: "*"`, `required-title-prefix` +
`required-labels`). Unlike `update-pull-request`, this output's
`required-*` guards **do** survive the gh-aw v0.80.9 compile (verified
against the generated locks), so which-PR scoping is enforced at the
handler level in addition to the Step 3.6 preconditions and
`min-integrity: approved`. No gh-aw version bump is required — the
capability already exists at our pinned v0.80.9.

## Enabling fix — the loop's own create-PR commit no longer counts as
"human engaged"

While validating this feature against #36429 I found the mark-ready path
was **unreachable for every loop-owned draft PR**, and traced it to a
regression from #36317's own review-hardening.

gh-aw's `create_pull_request` builds a PR's initial commit through the
GitHub API, which stamps `author=github-actions[bot]` but
**`committer=web-flow`**. Commit `2f6b77b330` (in #36317) removed
`web-flow` from the prefetch's bot-login denylist so a maintainer
"Update branch" would correctly hand the PR off — but that also made
`Test-AnyHumanCommitActor`'s committer check read the loop's **own**
first commit as human engagement. Result: every freshly opened
`[ci-fix]` draft PR computed `humanEngaged=true` from commit #1, so the
watch loop skipped it forever — never surfacing green, never marking
ready. This regression is live on `main` today (all four open loop-owned
draft PRs have `committer=web-flow`).

Fix (`Query-CiFixPRs.ps1`): a human **committer** only trips the
hand-off when the commit **author** is not one of this workflow's own
bot identities (`$LoopBotCommitAuthors`). A human **author** still
counts unconditionally, so maintainer direct commits and
web-flow-authored "Update branch" merges continue to hand off correctly.
Unit-tested across all six author/committer shapes.

## Validation

- Both twins recompiled with `gh aw compile` (0 errors / 0 warnings);
locks show no action-SHA or `compiler_version` drift (only
frontmatter/body hash + the new handler config).
- `mark_pull_request_as_ready_for_review` config confirmed present in
**both** locks with the correct `[ci-fix] ` / `[ci-fix-net11] ` prefixes
and `agentic-workflows` label; the `safe_outputs` job carries
`pull-requests: write`.
- Twin symmetry preserved (only `[ci-fix]` ↔ `[ci-fix-net11]` /
`ci-scan` ↔ `ci-scan-net11` token differences).
- **Live dry-run against #36429** (scoped `workflow_dispatch`,
`dry_run=true`, this branch): the workflow prefetch now computes
`humanEngaged=false` for #36429 (was `true` pre-fix), and the agent's
gate walk correctly advances **past** the human-engaged gate to the
CI-pending WAIT gate — `checksSettled=false` because #36429's macOS
`SafeAreaEdges` leg is still queued. Once that leg settles green, the
same run path reaches Step 3.6 and marks the PR ready. Emitted zero
writes (dry-run).

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

---------

Co-authored-by: PureWeen <223556219+Copilot@users.noreply.github.com>
…le grouped comments (#36533)

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

### What this changes

The `/review tests` **Test Failure Analysis** workflow classifies
whether a PR's CI failures are PR-caused or unrelated. Its deterministic
gate computed `legsRegressedVsBase` — the "Likely PR-caused" headline —
by comparing each red PR leg against **a single most-recent base
build**. Flaky UI-test legs that happened to be green on that one base
build produced false **"regressed-vs-base / Likely PR-caused"**
positives, so the generated comments carried little signal.

This PR makes the regression diff sample **several recent base builds of
the PR's own base branch** (`main` or `net11.0`) and only calls a leg a
regression when it is green across enough of them and red on none — and
switches the LLM engine to Opus. It also **replaces the per-test result
table with a skimmable, root-cause-grouped bullet list** (the
deep-UI-test-analysis style) so a run with hundreds of failures
collapses to a handful of readable groups inside the existing compact
badge + collapsible header instead of a giant table.

### Changes

- **`Gather-TestFailureContext.ps1`** — new `Get-AggregatedBaseLegMap`
aggregator + params `RegressionBaseBuilds=5` and
`MinBaseGreenSamples=2`. A leg is a regression only if it is green on
**≥ `MinBaseGreenSamples`** base builds **and red on NONE**. Per base
build, a leg that failed even one attempt counts RED (a retry that later
passed does not clear a base flake). New leg states `flaky-on-base` /
`succeeded-on-base-unconfirmed` and new per-failure fields
`baseSampleCount` / `baseGreenCount` / `baseFailedCount`.
- **Asymmetric conservatism (preserved)** — multi-build sampling widens
**only** the false-RED (assert-a-regression) side. The test-level
dismissal / false-GREEN side stays single-build-strict on purpose, so
this change never turns a real failure green.
- **`copilot-review-tests.md` / `.lock.yml`** — engine model
`claude-sonnet-4.6` → `claude-opus-4.8`; **replaced only the per-test
Markdown table** (an unreadable wall of text on runs with hundreds of
failures) with a deep-UI-test-analysis style **root-cause-grouped**
bullet list using subtle tokens (`✗ PR-related` / `ℹ Uncertain` / `●
Unrelated`). The compact **badge row and the `Test Failure Review:
[verdict] - click to expand` collapsible are kept** so the collapsed
comment stays a one-glance summary; the badge set now surfaces the key
multi-build signal — `Overall` / `Failures` / **`Regressed vs base`**
(replacing the old `Platform` badge) / `Baseline on base`. Everything
detailed (verdict sentence, grouped bullets, coverage counts, this-PR +
base-sampling build links, recommended action) lives inside the
collapsible. `img.shields.io` stays in the network allowlist. Lock
recompiled (gh-aw v0.80.9).
- **`SKILL.md` / `maui-ci-facts.md`** — document the multi-build
sampling, the new states/fields, and soften the "green on base is proof"
wording to require green across several base builds and red on none.

### Validation

Ran the gatherer locally against **PR #36478** (base `main`), before vs
after:

| | `legsRegressedVsBase` | Verdict |
|---|---|---|
| **Before** (single base build) | **14** | Not ready |
| **After** (5 base builds) | **0** | Needs human investigation |

The `ValidateDynamic*` (×9), `CollectionViewInfiniteScroll`, and
`Issue17400` legs — each green on 4/5 base builds and red on 1/5 — are
now correctly classified as `flaky-on-base` instead of PR regressions.

### Notes

- Extracted as a focused, standalone change from the broader
`improved-reviewer` work (#36473).
- CI-tooling-only change (`.github/`); no framework/runtime code is
touched.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… twin) (#36601)

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

## Problem

The **net11 twin** of the CI Failure Fixer (`ci-status-fix-net11`) has
been failing in its `safe_outputs` job on most scheduled runs since
~2026-07-10 (red on 07-10, 07-12, 07-13, 07-14, and 07-15 ×2). Every
failure is the same error:

```
Cannot create pull request: patch modifies files outside the allowed-files list
(src/AI/tests/Essentials.AI.UnitTests/...)
```

`net11.0` gained a new **`src/AI/`** source tree (Essentials.AI /
streaming-JSON) that **does not exist on `main`** (it 404s there). The
agent repeatedly finds a flaky `Essentials.AI.UnitTests` test, builds a
valid fix, and emits `create_pull_request` — but `src/AI/**` was never
added to the enforced `allowed-files` allowlist. The handler rejects the
patch, so:

- the whole scheduled run goes **red** every time,
- that AI-test flake can **never** be filed, and
- one create-PR slot is **burned** each sweep.

The `main` twin is unaffected because there is no `src/AI/` tree on
`main`.

## Fix

Add `src/AI/**` to **both** `allowed-files` blocks
(`create-pull-request` and `push-to-pull-request-branch`) in **both**
twins:

- On **net11.0** it unblocks the failing PR creation.
- On **main** it is a harmless no-op (no `src/AI/` tree exists there to
match) and keeps the two workflow files byte-identical per the
established mirror invariant — future-proofing a forward-port of the AI
tree.

Both `.lock.yml` files were recompiled with `gh aw compile` (0 errors /
0 warnings). The only substantive lock delta is the prepended
`"src/AI/**"` entry in the two `allowed_files` arrays (plus the metadata
hash line). No other handler config changed — `max` values, `add_labels
allowed:[p/0]`, `mark_pull_request_as_ready_for_review`,
`protected_files`, `base_branch`, and `title_prefix` are all unchanged.

## Verification

- `gh aw compile ci-status-fix` and `gh aw compile ci-status-fix-net11`
→ **0 errors / 0 warnings** each.
- Twin-symmetry invariant preserved (transformed-net11 vs main diff =
**124 lines**, the pre-existing cosmetic delta — unchanged by this PR).
- `gh aw lint` → no lint issues.
- Confirmed via lock diff that the sole config change is `"src/AI/**"`
prepended to the two `allowed_files` arrays in each twin.

Co-authored-by: PureWeen <223556219+Copilot@users.noreply.github.com>
…Copilot follow-ups from #36213) (#36483)

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

### What

Two small follow-up fixes to the release-readiness reporting skill,
closing two **low-severity** edge cases that the GitHub Copilot reviewer
flagged on #36213 and that shipped into `main`. Both are docs/skill-only
(PowerShell + tests) — no product code, no public API.

**1. `Test-PluginEnabled` — minified `settings.json` false negative**
`.github/skills/dependency-flow/scripts/Get-PreviewReleaseReadiness.ps1`

The enabled-plugin matcher was anchored to the start of a physical line
(`(?m)^\s*`). A **minified / single-line** `settings.json` (e.g.
`{"enabledPlugins":{"dotnet-release-tracker@dotnet-release":true}}`)
therefore failed to match, so an *enabled* plugin was reported as
**not** enabled (a false-negative that wrongly degrades to
`AVAILABLE_NOT_ENABLED`). It fails safe — it never produces a false
*enabled* — but it's still wrong for anyone whose settings file isn't
pretty-printed.

Fix: anchor the key to a JSON boundary (`{`, `,`, or whitespace) via a
look-behind `(?<=[{,\s])` instead of a line start. Comment-avoidance is
already handled by the string-aware `Remove-JsoncComments` scrub applied
just below, so the line anchor was redundant.

**2. `Test-IsSdkBumpPr` — `dotnet-optimization` collision**
`.github/skills/release-readiness/scripts/Get-PreviewReadiness.ps1`

`'(?i)\bBump\b.*dotnet/(dotnet|sdk)\b'` — the trailing `\b` sits between
`t` and `-`, so `Bump dotnet/dotnet-optimization …` was misclassified as
an SDK/VMR bump (which would attach a spurious "verify blessed build
locally" emphasis). Fix: use the `(?![\w-])` boundary that its sibling
matchers already use (`selectPin`, `Get-ComponentFlowSignal`).
Practically dormant on maui today (real dep-flow PRs are titled
`[netN.0] Update dependencies from…`), but now correct.

### Tests

Added hermetic regression guards in `Test-ReleaseReadiness.ps1`:
- `Test-PluginEnabled`: minified, pretty, suffix-only-key (no false
positive), and absent-entry cases (writes fixtures into a throwaway
`HOME`/`USERPROFILE`, restored in `finally`; no `gh`/network).
- `Test-IsSdkBumpPr`: `dotnet/dotnet-optimization` does **not** collide
→ `false`; a real `dotnet/sdk` later in the same title still → `true`.
This mirrors the `Get-ComponentFlowSignal` collision guard that already
existed — the sibling matcher just never got the parallel assertion (the
exact gap this closes).

Suite: **853 passed / 0 failed** (`-SkipE2E`).

### Why low-risk

Skill/tooling only. Fix 1 only ever *widens* a previously-too-narrow
match and still can't produce a false enable; Fix 2 only *narrows* an
over-broad match to exclude a hyphenated sibling. Both are covered by
new tests that fail against the old patterns.

Co-authored-by: PureWeen <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!

## Summary

The live manual validation of Action Pin Refresh ([run
29052735587](https://github.com/dotnet/maui/actions/runs/29052735587))
correctly produced a no-op: the runner had gh-aw v0.81.6 preinstalled,
but the v0.80.9-compiled workflow needed its matching CLI. `gh extension
remove gh-aw` could not authenticate because the agent had only the
Copilot inference PAT, and direct binary download was blocked.

This follow-up supplies the agent's `GH_TOKEN` from the workflow's
existing read-only `${{ github.token }}` permissions, leaving the
Copilot PAT limited to inference. It also reads and validates the
required gh-aw version from `aw-actions-update.lock.yml` metadata,
avoiding manual pin drift when the dedicated version-updater changes the
compiler version.

## Scope

- `.github/workflows/aw-actions-update.md`
- Regenerated `.github/workflows/aw-actions-update.lock.yml` (compiled
with gh-aw v0.80.9)

The safe-output remains constrained to `.github/aw/actions-lock.json`;
permissions and write scope are unchanged.

## Validation

- `gh aw compile aw-actions-update`
- gh-aw workflow security scanner: `aw-actions-update.md` passed
- `gh aw lint .github/workflows/aw-actions-update.lock.yml` reported no
lint issues; its local actionlint integration exited 125 due to a
tooling error.

Co-authored-by: PureWeen <223556219+Copilot@users.noreply.github.com>
…ry inline-findings.json write (#36002)

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

## What & why

Fixes to the Copilot PR-reviewer pipeline, driven by analyzing **64
recent `maui-copilot` PR-reviewer CI sessions** (most-recent run per PR,
last 7 days). Three independent analysis agents mined disjoint batches
and **converged on the same top two systemic issues** — strong signal
these are structural, not anecdotal. Fixes #1 and #2 are
**prompt/instruction-only**; the PR additionally ships
**regression-guard evals** for both, plus a **token-auth migration** of
the eval harness workflow (see Scope & safety).

### 1. `gh` CLI is unauthenticated by design, but the prompt doesn't say
so — ~61/64 sessions
The `CopilotReview` task intentionally strips all GitHub tokens
(`copilot ...
--secret-env-vars=GH_TOKEN,COPILOT_GITHUB_TOKEN,GITHUB_TOKEN`), so `gh
pr view` / `gh issue view` / `gh api` always fail inside the agent run.
But `pr-preflight.md` still *leads* with those commands, so nearly every
session burns 1-3 turns watching them fail and pivoting — and several
then **wrongly log an "environment blocker" or lower review
confidence**.

**Fix:** `pr-preflight.md` now opens with an explicit "Environment &
Authentication" note stating that unauthenticated `gh` is **expected,
not a blocker** (don't stop, don't reduce confidence), and provides
**local-`git` + unauthenticated public-REST (`curl`)** recipes that work
in CI. The original `gh` recipes are retained for local `pr-review` runs
where a token is present.

### 2. Agent refuses to write the REQUIRED `inline-findings.json` —
~34/64 sessions
The expert-review step over-generalizes a host "do not write output
files" guardrail and refuses to write `inline-findings.json`, dumping
the JSON into chat instead. There is **no fallback** —
`post-inline-review.ps1` finds no file (`Test-Path` fails) and **inline
review comments are silently dropped** in roughly half of sessions. This
is the most damaging correctness issue found.

**Fix:** the STEP 5b prompt in `Review-PR.ps1` and the
`maui-expert-reviewer` agent now **explicitly authorize and mandate**
writing the file, state that the general "don't write review output"
guidance does **not** apply to this required artifact, and forbid
substituting a chat-text dump (with an orchestrator-writes-it-itself
fallback instruction).

## Files
- `.github/pr-review/pr-preflight.md` — environment note + local-first /
`curl` recipes (#1)
- `.github/scripts/Review-PR.ps1` — strengthened STEP 5b inline-findings
mandate (#2, prompt string only)
- `.github/agents/maui-expert-reviewer.md` — reinforce required file
write, no chat-dump (#2)
- `.github/skills/pr-review/tests/eval.gh-auth.vally.yaml` — **new**
regression guard for #1
- `.github/skills/code-review/tests/eval.inline-findings.vally.yaml` —
**new** regression guard for #2
- `.github/workflows/skill-validation.yml` — **token-auth migration**
for the eval harness (see Scope & safety)

## Scope & safety
- **Fixes #1 and #2 are prompt/instruction text only.** No pipeline
control-flow or security-boundary changes — the #1 note merely
*documents* the existing token-stripping (reinforces it, never weakens
it). `Review-PR.ps1`'s change is confined to a here-string prompt;
`pwsh` parse check passes and `$PRNumber` interpolation is preserved.
- **`skill-validation.yml` is a token-provisioning migration (not prompt
text).** The prior `COPILOT_GITHUB_TOKEN*` secrets were rotated out with
the removal of `gh-aw-agents`, so the eval harness now sources Copilot
auth from the **`copilot-pat-pool`** environment (`COPILOT_PAT_0..9`,
index/run-id modulo selection, masked before `GITHUB_OUTPUT`). This is a
**like-for-like** auth-source swap — same `pull_request_target` exposure
model as before, no new secret exposure and no security loosening. ⚠️
**Merge prerequisite:** the `copilot-pat-pool` environment must be
populated with `COPILOT_PAT_0..9` (and must NOT carry
required-reviewer/wait-timer protection rules, which would hang the
`pull_request_target` job) so eval goes green immediately after merge.

## Evals (regression guards for these fixes)
Now that we run
[`vally`](https://www.npmjs.com/package/@microsoft/vally-cli) eval
suites, each fix ships with a guard that reproduces the exact failure
mode it fixes. Both pass `vally lint --strict` and run on this PR (each
lives under its skill's `tests/` dir, which flags that skill as
changed).

- `.github/skills/pr-review/tests/eval.gh-auth.vally.yaml` (#1) — the
vally eval step is already tokenless, so it **natively reproduces** the
CI condition where `gh` is unauthenticated. The agent must classify that
as **expected, not a blocker**, pivot to the local-first
`git`/anonymous-REST path, and **not lower its review confidence**.
Structural floor: the agent must end with `GH_AUTH_BLOCKER: no` — a
*necessary, not sufficient* signal — with an LLM judge scoring the
reasoning.
- `.github/skills/code-review/tests/eval.inline-findings.vally.yaml`
(#2) — pins a worktree to a real regression commit so the agent has a
genuine diff, then must **write** `inline-findings.json` (canonical
`path`/`line`/`body` schema) to the path the pipeline reads from disk
and prove it landed (read back, echo `FILE_OK:[…`). An agent that
refuses (`"prohibited"`) and chat-dumps the JSON has no file to echo and
fails. An LLM judge scores finding quality, non-refusal, and requires
transcript evidence of an actual write tool call (not just a fabricated
`FILE_OK:` line).

Each suite keeps two graders — one structural floor + one LLM judge.
Both floors are *satisfiable by a partial regression* (the prompt hands
the agent the giveaway token), so `scoring.threshold` is set to **0.7**
(above the house 0.6): with the unweighted `mean(floor, judge_norm)`
aggregate, a floor-1.0-but-judge-failing run scores `(1.0 + 0.25)/2 =
0.625`, which 0.6 would **pass** but 0.7 **fails**. This makes the **LLM
judge load-bearing** (must reach ≥3/5) rather than letting the spoofable
floor decide. Live-validated: good path 1.00, partial-regression 0.625.

## Follow-ups (identified, not in this PR)
Same analysis surfaced: PowerShell-vs-bash redirection footguns in
`try-fix` recipes; test-result classification keyed off exit code
instead of TRX `failed=` count; winners crowned with no regression
evidence; gate=FAILED conflating real regressions with
wrong-platform/ineffective tests; and the agent re-deriving the true PR
diff base each run. These can be addressed in separate PRs.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

## What this adds

A reusable, **local-only** dotnet/maui skill —
`.github/skills/analyze-sessions` — that analyzes a contributor's
Copilot CLI sessions to drive iterative improvements to the **PR-review
agent** (and other agents/skills/instruction files).

It automates the loop the team has been running by hand: **select →
extract → score → judge → cluster → propose → emit-eval**. The emit-eval
step is what makes it iterative — every recurring failure mode becomes a
`vally` guard-eval, the exact mechanism PR #36002 used by hand, now run
over the whole fleet of local sessions.

## Architecture — one engine, two front doors

```
 local front door  ─┐
 -Repository/-Last   │   scripts/Get-SessionAnalysis.ps1  (deterministic, NO LLM)
 -SessionId         ─┤     select → extract → score → digest → redact
                     │       • dotnet-replay --summary --json  (normalization)
 CI front door      ─┤       • thin raw events.jsonl scan      (success/tokens/…)
 -EventsPath/-Dir   ─┘     emits: session-analysis.md + JSON contract
                                     │
                                     ▼  redacted digests + ranking
                          agent, in the contributor's OWN session:
                          judge → cluster → propose → emit guard-eval
```

- **Deterministic shared core** (`Get-SessionAnalysis.ps1`, no LLM) does
select/extract/score/digest + redaction. It **wraps `dotnet-replay`
v0.9.1** for normalization and adds a thin raw `events.jsonl` scan for
the signals replay's `--json` omits (per-tool `success`, `outputTokens`,
truncations/compactions, aborts, retries, subagent failures).
- **Local front door:** `-Repository` / `-Last` / `-SessionId` select
from `session-store.db`.
- **CI front door:** `-EventsPath` / `-EventsDir` point the *same*
engine at already-downloaded AzDO `events.jsonl` artifacts — one engine
reused by the existing CI-session pipeline, inside its artifact
boundary.
- The **judge / cluster / propose / emit-eval** steps run in the
contributor's **own Copilot session** (no third-party endpoint), driven
by `SKILL.md`.

## Privacy / safety

- **Local-only by default** — reads `~/.copilot/…`, writes a report into
the session workspace. It **never** opens a gist and **never** POSTs a
transcript.
- **Redaction on by default** — home paths → `~`, tokens
(`ghp_`/`gho_`/`Bearer`/`password=`/`key=`), and emails are stripped
from the report **and** any emitted eval.
- The LLM-judge runs through the contributor's own auth/quota;
cross-machine sharing is explicit, manual, opt-in.

## Deliverables

| File | Purpose |
|------|---------|
| `SKILL.md` | Triggers, 6-phase workflow, judge rubric, learn-from-pr
proposal taxonomy, #36002 emit-eval template, privacy model,
when-NOT-to-use |
| `scripts/Get-SessionAnalysis.ps1` | The deterministic shared core
(PowerShell — matches every other repo skill script) |
| `references/design-rationale.md` | Cites `dotnet-replay` (+ the
`--json` gap), the `events.jsonl` 35-event schema, the privacy model,
the two-front-doors architecture, and the hand-run proof-of-concept |
| `tests/eval.vally.yaml` | Capability + privacy suite: privacy floor
(`SHARE_ACTION: none`), capability (`PROPOSED_EVAL: yes`), and
negative-trigger — each a refutation-proof structural floor + LLM judge
|

## Verification

- Core validated end-to-end against real local maui sessions; ranking is
driven by genuine inefficiency (failures, retries, truncations, tokens)
rather than calendar span (resumed-session wall-clock is capped for
scoring).
- Metrics spot-checked against raw `events.jsonl` (tool-failure count,
`outputTokens`, compactions all matched exactly).
- Both front doors exercised (local DB select **and** `-EventsPath`);
`-Json` contract is valid JSON; redaction confirmed against synthetic
secrets.
- `npx -y @microsoft/vally-cli@0.6.0 lint --eval-spec
.github/skills/analyze-sessions/tests/eval.vally.yaml --strict`
**passes**.

No production code changes — this is additive tooling under
`.github/skills/`.

---------

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!

## Summary

- Process every prefetched CI-fix watch candidate before broad `ci-scan`
discovery, with actionable candidates first.
- Keep an open CI-fix PR autonomous until it is closed; eligible
`CHANGES_REQUESTED` reviews continue through Track C.
- Allow `src/AI/**` so the net11 fixer can address that source subtree,
while keeping the main twin behaviorally aligned.
- Regenerate both gh-aw lock files.

## Validation

- `gh aw compile ci-status-fix`
- `gh aw compile ci-status-fix-net11`
- PowerShell parser check for `Query-CiFixPRs.ps1`
- `git diff --check`
- Live prefetch confirms #36404 remains an actionable candidate.

---------

Co-authored-by: PureWeen <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!

## Summary
- Upgrade the Skill Validation workflow from
`@microsoft/vally-cli@0.6.0` to `0.10.0`.
- Preserve MAUI's explicit `*.vally.yaml` enumeration because Vally
directory discovery recognizes only `eval.yaml` and `eval.yml` by
default.
- Update all 0.6-specific scoring guidance: these specs intentionally
omit `scoring.weights`, retaining Vally 0.10's equal-weight aggregation
and existing thresholds.

## Validation
- Ran strict lint with `@microsoft/vally-cli@0.10.0` for all 10 MAUI
eval specs.
- Parsed `.github/workflows/skill-validation.yml` as YAML and ran `git
diff --check`.

## Scope
This PR is limited to the Vally 0.10.0 upgrade. It intentionally
excludes the Trim/AOT fixture-workflow changes from #34962.

Co-authored-by: PureWeen <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!

## Summary

Add Trim/NativeAOT annotation-chain guidance to the active MAUI expert
reviewer and cover it with hermetic Vally scenarios.

## Motivation

The HybridWebView NativeAOT investigation showed that IL2026/IL3050
warnings require annotation-chain and target-toolchain analysis. A
blanket rule that every suppression is wrong is inaccurate: #34868 uses
a documented, narrowly scoped Android NativeAOT ILC workaround, while
#34958 demonstrates the structural annotated-helper alternative on
`net11.0`.

## What changed

- **`maui-expert-reviewer.md`**: expands the Trimming/AOT dimension to
require tracing the annotated member, generic/DAM hops, feature guard,
reachability, and target analyzer. It distinguishes broad suppression
from a documented, scoped toolchain workaround and covers
structural-helper/source-generation alternatives.
- **Dimension routing**: activates Trimming/AOT review for relevant
annotations and IL20xx/IL30xx suppressions, not only direct reflection
APIs.
- **Hermetic Vally coverage**: uses Vally 0.10 `environment.files` to
materialize frozen candidate diffs and the exact supporting source
snapshots needed to trace the HybridWebView handler annotations, generic
registration DAM hop, and runtime feature guard. No Git history, remote
repository, or custom workflow fixture setup is exposed to the reviewer.
- **Three discriminating scenarios**: covers the scoped #34868
exception, the #34958 annotated-helper approach, and a
reachable-suppression counterfactual that replaces the feature guard
with `if (true)` and must be rejected.
- **Live-eval reliability**: gives the existing multi-surface
prior-review reconciliation scenario a 10-minute cap after passing
trials took 4m01s and 4m54s and another was terminated at the former
5-minute cap.

## Evaluation scope

The separate `eval.trim-aot.vally.yaml` suite tests technical review
reasoning on inert checked-in inputs. Tool-call grading requires
inspection of the candidate patch and all annotation-chain sources while
rejecting GitHub/network access. The five-run suite retains a `0.9`
threshold so the required verdict cannot be masked by the other graders.

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
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!

### Root Cause

The labeler treated agent skills and AI-assisted workflows as generic
infrastructure, so it never selected the more-specific `area-ai-agents`
label. Its issue-platform guidance also inferred labels too broadly and
included the unsupported `platform/tizen` label.

### Description of Change

- Routes Copilot CLI agents, agent skills, agentic workflows,
evaluations, and AI-assisted development to `area-ai-agents`.
- Keeps `area-infrastructure` for generic CI execution, authentication,
scheduling, dependency flow, and pipeline plumbing, with an explicit
dominant-subject tie-break.
- Distinguishes setup concerns such as workload availability and
target-framework recognition (`area-setup`) from debugging, editor,
build-task, and tooling behavior (`area-tooling`).
- Never applies `platform/tizen`, while still selecting the appropriate
`area-*` label for Tizen-related content.
- Infers issue platform labels only from explicitly named affected
platforms; generic claims such as "all platforms" do not infer labels,
while an explicit affected-platform list takes precedence.
- Expands the active Vally suite from 21 to 25 scenarios, including
deterministic regression coverage for `area-ai-agents`, platform
exclusion, and exact area selection.
- Explicitly activates `agentic-labeler` in every capability scenario
and requires labels-only output so the suite measures skill behavior
rather than nondeterministic skill discovery or explanatory prose.

### Validation

- Rebased onto `main` with `@microsoft/vally-cli@0.10.0` pinned by the
Skill Validation workflow.
- Full three-trial `agentic-labeler` Vally 0.10.0 evaluation passed at
99.8% (threshold: 85.0%).
- JUnit aggregate: 0 failures, 0 errors.
- Strict Vally 0.10.0 static validation passed.
- Harness hermeticity gate passed.
- Skill Validation run:
https://github.com/dotnet/maui/actions/runs/29609999793

### Issues Fixed

Follow-up to and replacement for #35570.

---------

Co-authored-by: bot <bot@test>
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 of Change

Retires automation targeting the unsupported `net10.0` branch:

- Removes the scheduled/event-driven `main` → `net10.0` merge workflow
and its configuration.
- Removes `net10.0` from the daily formatting workflow matrix.
- Disables the live merge workflow immediately to prevent replacement
PRs while this change is reviewed.

The matching dependency-flow cleanup is tracked by
[maestro-configuration PR
63025](https://dev.azure.com/dnceng/internal/_git/maestro-configuration/pullrequest/63025),
removing the Android, dotnet, and macios subscriptions plus the
`net10.0` default-channel mapping.

### Issues Fixed

No issue. Retires the automation responsible for generated PRs #36400
and #36641.

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

<!-- Please keep the note below for people who 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 whether this change resolves your
issue. Thank you!

## What this PR does

Adds a scheduled regression-corpus scanner that finds recently merged
`i/regression` fixes and drafts a hermetic Vally regression stimulus for
the `code-review` skill. When the bad change is statically reviewable,
the draft may also propose a small, generalizable `SKILL.md`
improvement; downstream Vally evaluation can measure it after a
repository contributor triggers `/evaluate-skills`.

The manual seed work originally on this branch was superseded by
#35942's Vally migration. This PR now contains only the automation that
grows the corpus.

## How it works

1. A deterministic PowerShell pre-pass finds recent regression-fix PRs,
identifies an explicitly attributed introducing PR, resolves its merge
SHA, deduplicates the corpus and pending scanner drafts, and emits
bounded candidate data.
2. The agent inspects the introducing merged PR's diff and drafts one
hermetic `eval.vally.yaml` entry. The reviewed stimulus contains no live
PR or issue context.
3. The only possible draft-PR changes are
`.github/skills/code-review/tests/eval.vally.yaml` and
`.github/skills/code-review/SKILL.md`; they target `main` from a
`regression-corpus/**` branch.

## Rebase and security rework (2026-07-15)

- Rebased onto current `main` and regenerated the lock file with gh-aw
v0.80.9.
- Attribution now requires an explicit `#NNNN` or `PR NNNN` reference,
preserves source-text order, and ignores out-of-range identifiers.
- Only `OWNER`, `MEMBER`, and `COLLABORATOR` linked-issue comments can
supply attribution; public comment text is excluded.
- Candidates without a linked regression issue require human attribution
instead of generating an invalid eval tag.
- Empty GitHub search results produce no candidates rather than a
phantom `fixPr: 0` record.
- The candidate payload is now structural identifiers only; fetched
titles, prose, and file paths are excluded before it reaches the agent
prompt.
- The scanner deduplicates corpus entries, pending scanner drafts, and
accepted candidates from the same run.
- The scanner runs only in `dotnet/maui`, uses the repository's gated
`copilot-pat-pool`, filters agent GitHub reads at `min-integrity:
approved`, and suppresses no-op issues.

## Security review

The recompile introduces references to the existing `COPILOT_PAT_0`
through `COPILOT_PAT_9` pool, replacing the direct
`COPILOT_GITHUB_TOKEN` inference credential. The shared `pat_pool`
import selects one credential inside the protected `copilot-pat-pool`
environment and passes it only to the Copilot engine; the pre-pass uses
only scoped read permissions.

The generated lock adds SHA-pinned gh-aw v0.80.9 framework dependencies,
including `actions/cache/restore` and `actions/cache/save` v5.0.5, and
refreshes the existing GitHub action/container pins. No redirects or
unpinned external actions were added. The create-PR safe output is
limited to one draft PR, `main`, `regression-corpus/**`, a 256 KB patch,
the two files above, and the `agentic-workflows` label.

## Related

- #34814 — eval lifecycle and CI integration
- #35048 — PR-review improvement epic
- #36008 — before/after skill-evaluation presentation
- #35977 — worked red-to-green example

Draft pending review of the scanner workflow and generated lock.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
<!-- Please keep the note below for people who 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 whether this change resolves your
issue. Thank you!

## What this PR does

Extends `skill-validation.yml` so skill PRs show a **before→after** eval
comparison, not just a pass/fail "after" result.

Today the workflow runs each skill PR's Vally evals against the **PR's**
reviewer instructions and prints one score column — it proves the eval
passes *with* the change ("after" / green), but it never runs the
*pre-change* reviewer, so any claimed improvement is asserted, not
shown.

This adds an advisory **baseline** run and renders a `Before | After |
Threshold | Verdict` table (with a 📈/📉 trend) on the PR comment, so a
reviewer-instruction change's effect is measured directly.

## How it works

- A new **baseline** step reverts **only** the skill's instruction files
(`SKILL.md` / `*.md`, **not** `tests/`) to the PR base, runs the same
eval specs, and uploads the result. The diff under review is identical
in both runs — only the reviewer instructions differ.
- The comment job downloads the baseline artifact and switches the table
to `Before | After | Threshold | Verdict` when a baseline exists,
falling back to the original single-score table otherwise.
- **Advisory only** — the baseline never gates; PR status still keys on
the authoritative "after" run.
- **Auto-skips** when there's no base (manual dispatch), the base commit
is unavailable, the skill is new on the branch, or its instructions are
unchanged vs base (then before == after).
- Same hermetic posture as the after-run: the baseline `env:` carries
only `COPILOT_GITHUB_TOKEN` (model auth) — no `GH_TOKEN`/`GITHUB_TOKEN`.
Reverting to the base instructions only *reduces* PR-controlled content,
so it adds no leak surface.

**Cost:** roughly **2×** LLM eval minutes, but only on PRs that actually
change reviewer instructions.

## Validation

- YAML parses; `actionlint` clean (no errors/warnings); `node --check`
passes on the full comment script.

## Context

This is the **measurement half** of the regression-improvement loop
being built for the `code-review` skill. The other half — the scanner
that auto-drafts the eval + proposed reviewer fix — is #35925; #35977 is
a live worked example. Split out of #35925 so that PR stays scoped to
just the scanner.

---------

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!

### What this is

A worked, hermetic regression-corpus example for the `code-review`
skill. It pairs a Vally stimulus based on a real lifecycle regression
with reviewer guidance that targets the general failure mode.

### Regression captured

- **Introducing PR:** #31931
- **Regression:** #35756, fixed by #35803
- **Mechanism:** an early return added to `Page.SendNavigatedTo`
suppressed not only duplicate local lifecycle work, but also propagation
to the current child when the page's latch was already set.

### Rework

- Rebased onto current `main`.
- Generalized the guidance: reviewers must distinguish a guard's local
duplicate suppression from downstream propagation or side effects, then
trace a subsequent call while inputs, recipients, or downstream state
may have changed.
- Clarified that `**Confidence:**` represents confidence in the safety
recommendation, not certainty that an individual failure mechanism
exists. An unresolved failure mode must report `**Confidence:** low`.
- Hardened the lifecycle eval against its original false pass: a review
that identifies the risk but still returns `LGTM` fails the structural
floor; semantic analysis remains LLM-judged.

### Validation

- `vally lint --eval-spec
.github/skills/code-review/tests/eval.vally.yaml --strict` passes
locally.
- The regression suite is configured for five trials; the CI model
evaluation remains the authoritative measurement of the before/after
effect.

### Related

- #35925 — regression-corpus scanner
- #36008 — before/after skill-evaluation reporting

---------

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 of Change

Updates the agentic workflow infrastructure for gh-aw v0.81.6 by
applying the generated `gh aw upgrade && gh aw compile` output.

Key changes:
- Refreshes `.github/aw/actions-lock.json` and generated
`.github/workflows/*.lock.yml` files to gh-aw `v0.81.6`.
- Renames/updates the agentic workflows agent definition and adds the
generated agentic workflow skill files.
- Adds the missing local `.github/skills/otel-queries/SKILL.md` target
referenced by the new agentic-workflows router for
OTEL/trace/telemetry-driven analysis.
- Pins gh-aw prompt/reference URLs in
`.github/agents/agentic-workflows.md` and designer references to
`v0.81.6` instead of floating `main`.
- Adds the missing ASCII Charts prompt route and wires
`aw-actions-update` safe outputs to depend on `pat_pool`.
- Hardens `rerun-review-scanner` by pinning the write-scoped
`trigger-rerun-review` safe-output checkout to `main` before running
`.github/scripts/Invoke-RerunReviewTrigger.ps1` with `GH_TOKEN`.
- Hardens `agentic-labeler` with a source-level safe-output allowlist
that permits only `area-*` and `platform/*` labels. gh-aw v0.81.6
validates, sanitizes, and length-bounds label names through its
issue-intent normalizer.
- Updates workflow source files changed by the compiler, including
action pins and rerun/CI scanner workflow sources.
- Updates PAT pool validation/docs to use the generated gh-aw setup
scripts and Copilot CLI `1.0.65`.
- Hardens maintenance workflows by deriving the gh-aw updater pin from
`actions-lock.json`, requiring exactly one non-empty setup-cli lock
entry with graceful fail-closed fallback, and avoiding `eval` in PAT
validation.

### Issues Fixed

Fixes #36485

### Validation

- `gh aw upgrade --approve --verbose`
- `gh aw compile --approve --verbose`
- `gh aw validate --verbose`
- YAML parse check for `.github/workflows/validate-pat-pool.yml`
- Verified action tags for `actions/checkout@v7.0.0` and
`actions/github-script@v9.0.0`
- Focused positive/negative checks for gh-aw pinned-version extraction
from `.github/aw/actions-lock.json`, including duplicate-entry graceful
guard behavior under `set -e`
- Static route-target check that
`.github/skills/agentic-workflows/SKILL.md` references existing
`.github/skills/otel-queries/SKILL.md`
- Static check that `.github/agents/agentic-workflows.md` no longer
references floating `raw.githubusercontent.com/github/gh-aw/main` prompt
URLs
- Static checks for OTEL and ASCII Charts route targets, pinned designer
reference URLs, and `safe-outputs.needs: [pat_pool]`
- Targeted check that `rerun-review-scanner` pins the write-scoped
safe-output checkout to `main` in both source and generated lock files
- Verified upstream gh-aw v0.81.6 routes `add_labels` through
`validateIssueIntentLabels` for type checking, sanitization, and a
128-character limit
- Verified the regenerated `agentic-labeler.lock.yml` carries `allowed:
["area-*", "platform/*"]` in both safe-output configuration surfaces

### Platforms Tested

- [ ] iOS
- [x] Android — not applicable; workflow-only change
- [ ] Windows
- [ ] Mac

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: PureWeen <5375137+PureWeen@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 of Change

#### Root cause

`Get-PrNumbersBetweenTags` and `Get-PrNumbersReachableFromTag` treated
every parenthesized `(#N)` reference in a commit subject as a merged PR.
GitHub squash subjects can contain linked issue references before the
actual PR suffix, so preview6 attempted to fetch issues #34716 and
#34898 through the pulls API and logged two false 404 errors.

#### Fix

Add one shared `Get-PrNumbersFromGitLog` helper used by both tag paths.
It accepts only the final numeric `(#N)` suffix (with optional trailing
whitespace), ignores malformed or non-terminal references, and preserves
sorted deduplication.

#### Preview6 proof

For `11.0.0-preview.5.26304.4..11.0.0-preview.6.26360.8`:

- Before: 192 candidate references; false #34716 and #34898 included.
- After: 190 candidate PRs; #34716 and #34898 excluded while actual PRs
#34719 and #35031 remain.
- Real dry run exited 0 and resolved `.NET 11.0-preview6` (#129).
- 39 relevant PRs checked, 151 wrong-branch PRs skipped, 15 linked
issues checked, and 40 items already correct.
- All 14 legitimate milestone corrections remain, with zero report
errors.
- `-CloseFixedIssues` remained a dry run: two open issues would close
and 13 were already closed; no GitHub state was changed.

#### Tests

- New parser regression selection: 12 tests; restoring the former parser
produces 6 failures.
- `Fix-MilestoneDrift.Tests.ps1`: 212 passed.
- `MilestoneTrigger.Tests.ps1`: 116 passed.

#### Non-goals

This fixes tag-audit parsing on `main`. It does not address the missed
historical preview6 workflow launch: the preview6 tag was created from a
net11.0 commit that did not yet contain the already-merged `main`
tag-push trigger. Branch-flow/backport policy is intentionally
unchanged.

### Issues Fixed

N/A — this defect was discovered while auditing the preview6 tag.

Co-authored-by: PureWeen <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!

## Summary

Updates all repository agentic workflows from gh-aw v0.81.6 to the
latest stable v0.82.14 and repairs the PAT-pool source shape that
prevented regeneration with the new compiler.

## Root Cause

The v0.82.14 compiler emitted invalid generated YAML for the multiline
`engine.env.COPILOT_GITHUB_TOKEN` `case()` expressions used by all 14
workflows (`non-map value is specified`). This was a
compiler/source-shape incompatibility, not an organization-billing or
PAT-authentication failure. Audited v0.81.6 runs showed the existing
`copilot-pat-pool` job, Copilot inference, and safe outputs completing
successfully.

## Changes

- Normalize all PAT-pool `COPILOT_GITHUB_TOKEN` expressions to
compiler-safe single-line scalars.
- Preserve the environment-scoped PAT pool; do not add `permissions:
copilot-requests: write` or org-billed inference.
- Apply supported v0.82.14 migrations, including top-level `model`
fields and `checkout: false` for the `pull_request_target` labeler.
- Add explicit protected-file blocking to code-writing workflows.
- Update gh-aw action pins, dispatcher assets, PAT-pool documentation,
and the PAT validator.
- Regenerate all 14 `.lock.yml` files and `agentics-maintenance.yml`
with gh-aw v0.82.14.
- Remove the obsolete local agentic workflow designer skill replaced by
the v0.82.14 dispatcher route.

## Validation

- `gh aw compile --approve --strict --validate --schedule-seed
dotnet/maui --verbose` — 14/14 workflows compiled successfully.
- Trial-mode compile against `PureWeen/maui` — 14/14 workflows compiled
successfully.
- `gh aw trial ... --clone-repo PureWeen/maui --dry-run` accepted all 14
workflows without changes.
- `gh aw fix` reports no remaining migrations.
- All 14 lock files report compiler v0.82.14.
- Structural YAML parsing passed for all locks, maintenance, and PAT
validation workflows.
- PAT-pool preservation checks confirm all workflows still use
`COPILOT_GITHUB_TOKEN` and none grant `copilot-requests: write`.

Container-backed actionlint, zizmor, and poutine could not run locally
because the Docker Desktop daemon was unavailable.

---------

Co-authored-by: PureWeen <223556219+Copilot@users.noreply.github.com>
kubaflo and others added 8 commits July 23, 2026 14:03
…eed guidance (#36497)

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

Release-readiness reports identified the right blockers, but did not
always provide enough precise, safe instructions for a release captain
or future agent to complete them. This PR makes the SR transition
workflows explicit and test-backed.

- Require a fix PR to be merged and verified on `main` before
recommending `/backport to release/...`.
- Document the Arcade backport path and the manual `git cherry-pick -x`
conflict fallback.
- Document and detect the SR servicing flip: preserve `PatchVersion`,
set `PreReleaseVersionLabel=servicing`, and enable stable package
versions only on the release branch.
- Teach the next-cycle `main` bump as a separate one-file, one-line PR,
including the exact title and XML edit. For SR9 → SR10 this is `Update
PatchVersion from 90 to 100` and `<PatchVersion>90</PatchVersion>` →
`<PatchVersion>100</PatchVersion>`.
- Preserve `SdkBandVersion`, `PreReleaseVersionLabel=ci.main`, and
`StabilizePackageVersion=false` on `main`, matching the SR7/SR8/SR9
precedent.
- **Surface the per-build validation feed for the ship Assessment.**
When a promoted BAR build exists for SR HEAD,
`Get-MaestroOperationalChecks` now derives and emits the
`darc-pub-dotnet-maui-<sha8>` NuGet feed URL (the `Ship Assessment
validation feed` check) to paste into the DevDiv ship **Assessment**,
plus the `darc get-asset` confirm command. It reports `WATCH` when the
build isn't promoted — no default channel → no promotion → no feed → the
Assessment has nothing to link (the SR9 miss).
- Add focused coverage for backport recommendations, servicing
transitions, the triple-digit SR9 → SR10 bump, promoted/unpromoted feed
cases, and the valid post-ship/no-in-flight transition before the next
SR branch is cut.
- Keep preview readiness available when GitHub's GraphQL PR-list
endpoint is unhealthy by falling back to bounded REST queries with
conservative field mapping and complete merged-PR pagination.

## Release workflow captured

| Operation | Target | Required behavior |
|---|---|---|
| Source fix backport | Merged source PR on `main` | Post `/backport to
release/<branch>` only after main ancestry is verified |
| SR stabilization | `release/<major>.0.1xx-sr<N>` | Keep its
`PatchVersion`; switch to `servicing` and stable packages after the
final backport |
| Next-cycle preparation | `main` | Change only `PatchVersion` to
`(N+1)*10`; keep SDK-band and CI prerelease settings unchanged |
| Ship Assessment feed | `release/<major>.0.1xx-sr<N>` build | Add
default channel → promote the build → link the per-build
`darc-pub-dotnet-maui-<sha8>` feed in the DevDiv Assessment so
CSI/customers can validate the exact candidate packages |

## What not to do

- Do not recommend a backport command for a fix that exists only on
`inflight/current`.
- Do not combine the `main` next-cycle bump with the release branch
servicing flip.
- Do not change `SdkBandVersion` or copy servicing settings onto `main`.
- Do not create the ship Assessment without the per-build validation
feed — if the SR branch has no BAR default channel the build is never
promoted and no `darc-pub-dotnet-maui-<sha8>` feed exists to link.
- Do not let the report mutate release or `main` refs, or create
channels / promote builds / edit the Assessment; the skill remains
report-only (it only derives and surfaces the feed URL).

## Validation

- The added and affected release-readiness assertions pass, including
the exact SR9 → SR10 title/XML guidance, promoted (`READY`) / unpromoted
(`WATCH`) feed cases, common-ancestry main-revert detection, the
shipped-SR + next-candidate state with no in-flight SR, and GraphQL→REST
PR-discovery fallback pagination.
- The complete release-readiness harness reports **1069 passing
assertions and 0 failures**.
- A live preview-readiness smoke-run completed successfully through REST
fallback while GitHub's GraphQL endpoint was returning HTTP 502.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: kubaflo <kubaflo@users.noreply.github.com>
Copilot-Session: cf5a6299-1e58-4157-b7fd-b85efaa14755
Copilot-Session: 04bf990b-a216-41df-aa75-08f62a1ecaf0
Copilot-Session: 136770fc-91e0-451c-8a4d-ea6a176f30e8
Copilot-Session: d00747b7-96f3-4e7a-8dfb-e3a48db04b2d
Copilot-Session: 4c228cec-8795-4bd5-a86c-c3fede46d534
<!-- 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 of Change

Automates visual snapshot evidence in `/review tests`. When public AzDO
results contain failed screenshot comparisons, the command now emits
exactly one test-failure analysis comment containing bounded, expandable
baseline/actual/diff panels.

Visual evidence remains supplementary: it does not change
`gate.verdictCeiling`, deterministic attribution, or the merge-readiness
verdict.

#### One-comment flow

1. Trusted pre-activation code discovers failed visual results through
the public AzDO `resultsbybuild` API, including retry-suffixed
attachments such as `Snapshot[1].png` and `Snapshot-diff[1].png`.
2. It resolves baselines from the exact source version tested by AzDO
and maps runtime evidence to the correct snapshot directory (`ios-26`,
`android-notch-36`, `mac`, or `windows`).
3. It streams and validates bounded PNG assets, then stores them on
`review-tests-assets` using immutable commit-pinned
`raw.githubusercontent.com` URLs.
4. The Copilot agent emits the normal single `add_comment` analysis
payload with a trusted insertion marker.
5. A sealed post-step validates the published asset manifest and injects
as many expandable comparison panels as fit into that same comment. Each
collapsed panel shows a conservative relationship label:
- `Likely PR-caused` for an exact test/platform base regression or
directly changed snapshot/test;
- `Likely unrelated` for an exact base/known-issue match without direct
visual scope;
   - `Needs human investigation` for unmatched or mixed evidence.
6. Excess comparisons are summarized as omitted instead of creating a
companion comment.

The local `.github/scripts/Review-Tests.ps1 -PostComment` path uses the
same merger. It also recognizes complete reports returned in Copilot's
final response, preserving nested evidence code fences without wrapping
a second title or badge section.

### Security and Failure Safety

- PR text, logs, test names, attachment metadata, changed files, and
visual labels remain untrusted input.
- The merger script and visual context are copied to a root-owned
location before the workflow checks out the untrusted PR branch.
- The post-step runs without `COPILOT_GITHUB_TOKEN`, `GH_TOKEN`, or
`GITHUB_TOKEN`.
- AzDO attachment URLs must match the expected public project and
attachment route.
- Published assets are size-bounded, signature-checked PNGs with
validated dimensions and repository paths.
- Raw image URLs must match the exact repository, asset commit, PR
directory, and safe filename.
- Labels are HTML-escaped and `@` is neutralized before insertion.
- Relationship labels use fixed trusted text. Untrusted attribution
values are never rendered, and same-named snapshots changed on another
platform do not count as PR scope.
- The final body is checked panel-by-panel against conservative limits
of 45 URLs, 10 mentions, and 60,000 UTF-16 characters, below gh-aw's
throwing limits.
- The analysis JSON update is atomic (written to a temp file, then
renamed over the original). Invalid context, malformed output, missing
analysis payloads, limit failures, and dry-run/noop output leave the
original analysis unchanged.
- The publisher never creates or patches PR comments; only the existing
gh-aw `add_comment` payload is mutated.

### What NOT to Do

- Do not use the ordinary anonymous AzDO test-runs listing for
discovery; it redirects to sign-in. Use the public failed-results
endpoint.
- Do not resolve baselines from the current PR head; use the source
version actually tested by the selected AzDO build.
- Do not let the agent construct or trust visual asset URLs.
- Do not publish a second companion comment; merge bounded panels into
the single analysis payload.

### Validation

- 98 focused Pester tests pass.
- Changed PowerShell scripts parse successfully.
- `gh aw compile copilot-review-tests --approve` completes without
errors or warnings.
- A real `agent_output.json` from gh-aw run
[29674953402](https://github.com/dotnet/maui/actions/runs/29674953402)
was replayed through the post-step:
  - one `add_comment` item remained one item;
  - five visual panels were inserted;
  - the final body contained 26 URLs, one mention, and 9,585 characters.

### Live Single-Comment Examples

The exact local `/review tests` path from this branch posted or repaired
these merged comments after the PRs' `/azp run` pipelines completed:

| PR | Single merged result | Included evidence | Relationship labels |
Final limits |
| --- | --- | --- | --- | --- |
| #36413 | [Test-failure analysis with visual
panels](#36413 (comment))
| 5 panels / 15 images | 1 PR-caused, 4 investigate | 23 URLs, 13,156
chars |
| #36631 | [Test-failure analysis with visual
panels](#36631 (comment))
| 6 panels / 18 images | 2 PR-caused, 4 investigate | 31 URLs, 21,367
chars |
| #36395 | [Test-failure analysis with visual
panels](#36395 (comment))
| 11 panels / 33 images; 19 omitted | 11 investigate | 43 URLs, 19,858
chars |
| #36404 | [Test-failure analysis with visual
panels](#36404 (comment))
| 14 panels / 40 images; 81 omitted | 14 investigate | 45 URLs, 23,779
chars |
| #35846 | [Test-failure analysis with visual
panels](#35846 (comment))
| 10 panels / 30 images; 9 omitted | 10 investigate | 43 URLs, 22,496
chars |
| #36277 | [Test-failure analysis with visual
panels](#36277 (comment))
| 7 panels / 19 images | 3 PR-caused, 4 investigate | 31 URLs, 18,355
chars |
| #36170 | [Test-failure analysis with visual
panels](#36170 (comment))
| 11 panels / 33 images; 8 omitted | 11 investigate | 44 URLs, 23,180
chars |
| #35578 | [Test-failure analysis with visual
panels](#35578 (comment))
| 12 panels / 36 images; 50 omitted | 12 investigate | 44 URLs, 25,443
chars |
| #36672 | [Test-failure analysis with visual
panels](#36672 (comment))
| 14 panels / 40 images; 9 omitted | 14 investigate | 45 URLs, 25,915
chars |
| #31755 | [Test-failure analysis with visual
panels](#31755 (comment))
| 12 panels / 36 images; 3 omitted | 12 investigate | 44 URLs, 22,728
chars |
| #34637 | [Test-failure analysis with visual
panels](#34637 (comment))
| 9 panels / 27 images; 81 omitted | 9 investigate | 43 URLs, 22,325
chars |
| #35156 | [Test-failure analysis with visual
panels](#35156 (comment))
| 2 panels / 6 images | 1 PR-caused, 1 investigate | 19 URLs, 11,911
chars |
| #35885 | [Test-failure analysis with no visual
failures](#35885 (comment))
| 0 panels / 0 images | No visual failures detected | 8 URLs, 4,239
chars |
| #36577 | [Test-failure analysis with visual
panels](#36577 (comment))
| 1 panel / 3 images | 1 investigate | 44 URLs, 21,768 chars |
| #36212 | [Test-failure analysis with no visual
failures](#36212 (comment))
| 0 panels / 0 images | No visual failures detected | 5 URLs, 5,982
chars |

Each result contains one `Tests Failure Analysis` title and one merged
review marker. Across 114 rendered panels, all 336 embedded image URLs
returned HTTP 200. Seven panels were safely classified as likely
PR-caused; no panel in this sample had enough exact evidence to be
safely classified as likely unrelated, so the remaining 107 stayed at
`Needs human investigation`. Another 260 comparisons were omitted safely
by the comment limits.

The latest eight-example batch was regenerated concurrently, and #36672,
#31755, #34637, #35156, #35885, #36577, and #36212 were added afterward.
The current [`review-tests-assets`
head](f937993)
retains the full asset history.

The protected `copilot-pat-pool` environment rejects feature-branch
`workflow_dispatch` runs before job execution. The live local-runner
examples validate comment generation and asset publication, while the
real gh-aw output replay validates the workflow post-step mutation
without weakening that branch protection.

### Issues Fixed

N/A - reviewer workflow enhancement.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: kubaflo <kubaflo@users.noreply.github.com>
Copilot-Session: a280b482-e102-4ca0-9ff9-1cfe1946e21f
Copilot-Session: d00747b7-96f3-4e7a-8dfb-e3a48db04b2d
Copilot-Session: 478d195b-20f3-4bc6-aeed-f6aa88b55fda
<!-- 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 of Change

Set `tools.github.integrity-proxy: false` for the regression-corpus
scanner's deterministic pre-agent `gh` calls while retaining
`min-integrity: approved` for every agent MCP read. The scanner
continues to emit only validated structural IDs, labels, and merge SHAs;
fetched prose never enters the agent prompt. The generated lock file is
updated in the same commit.

### Root Cause

The deterministic pre-activation pass inherited gh-aw's integrity proxy
because the agent uses `min-integrity: approved`. The proxy redacted
maintainer-authored attribution fields before
`Find-RegressionFixPRs.ps1` could apply its own
OWNER/MEMBER/COLLABORATOR checks, so [production run
29947778128](https://github.com/dotnet/maui/actions/runs/29947778128)
completed successfully but emitted `usableCount: 0` and opened no draft
PR.

The two trust boundaries remain separate: the pre-pass applies its
deterministic maintainer-association validation to live REST data, while
the agent's GitHub MCP gateway still enforces approved integrity.

### Validation

- 77 Pester tests passed
- Production-shaped scan resolved fix PR #35768 to introducing PR #31931
at `af540589fc5a3b053cd8c08334d0ca5a0125451b`, source `pr-body`, with
`usableCount: 1`
- `gh aw compile regression-corpus-scanner --strict`: 0 errors, 0
warnings; recompilation parity confirmed
- Generated `pre_activation` contains no integrity/CLI proxy injection;
agent MCP remains `min-integrity: approved`
- Vally 0.10 strict lint passed for the code-review eval corpus
- Three independent adversarial reviewers found no significant issues
(3/3 consensus)

### Issues Fixed

N/A - fixes the regression-corpus scanner behavior observed in the
linked production run.

Co-authored-by: PureWeen <223556219+Copilot@users.noreply.github.com>
Copilot-Session: e0da256b-eef3-41b1-b532-0d8557106c0c
<!-- 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!

Context: #24744
Context: #24952

### Description of Change

`Java.Interop.ExportAttribute` is annotated with
`[RequiresUnreferencedCode]`, so every use of `[Export]` produces an
IL2026 trim warning and depends on `Java.Interop.Export.dll` reflection
at runtime. #24744 established the alternative: declare an abstract
class in `src/Core/AndroidNative` and `override` it, which lets the Java
Callable Wrapper generator emit the method — and its
`@android.webkit.JavascriptInterface` annotation — statically.

This adds `T:Java.Interop.ExportAttribute` to `eng/BannedSymbols.txt` so
the pattern is enforced by RS0030 going forward, instead of relying on
reviewers to catch it. The message points at
`HybridJavaScriptInterface.java` as the working example:

```
T:Java.Interop.ExportAttribute;[Export] pulls in Java.Interop.Export dynamic features that are not trimming or AOT friendly. Declare an abstract class in src/Core/AndroidNative and override it instead, see src/Core/AndroidNative/maui/src/main/java/com/microsoft/maui/HybridJavaScriptInterface.java
```

Adding the ban flagged the one remaining offender,
`RefreshViewWebViewScrollCapture.ScrollCaptureState.SetCanScrollUp()`:

```
src/Core/src/Platform/Android/RefreshViewWebViewScrollCapture.cs(209,4): error RS0030:
The symbol 'Java.Interop.ExportAttribute' is banned in this project: [Export] pulls in
Java.Interop.Export dynamic features that are not trimming or AOT friendly. ...
```

So it is fixed the same way #24744 did: a new
`RefreshViewJavaScriptInterface` abstract class in the `maui.aar` Java
sources, with `ScrollCaptureState` deriving from it. The
`[RequiresUnreferencedCode("Java.Interop.Export uses dynamic
features.")]` suppression on `SetCanScrollUp()` is no longer needed and
is removed.

Note the base type is deliberately an **abstract class** and not an
interface. #24952 reverted `HybridJavaScriptInterface` from an interface
back to a class because Java does not inherit method annotations from
interfaces — the generated JCW silently lost
`@android.webkit.JavascriptInterface` and the JavaScript bridge stopped
working. The same applies here.

The remaining `[Export]` usages in the repo are all
`Foundation.ExportAttribute` (Apple), which is a different type and is
unaffected by this ban.

### Issues Fixed

None; this is a proactive lint rule plus the one cleanup it surfaced.

### Testing

Verified locally by building `src/Core/src/Core.csproj` for
`net10.0-android36.0`:

- **Before the fix** — build fails with `error RS0030` at
`RefreshViewWebViewScrollCapture.cs(209,4)`, confirming the new
banned-symbol entry is actually enforced.
- **After the fix** — `Microsoft.Maui.dll` builds clean, including the
Gradle step that compiles the new Java file into `maui.aar`.

No behavior change is expected at runtime: the exported Java method name
is still `setCanScrollUp`, and `[JavascriptInterface]` remains on the C#
override, matching the shipping `HybridWebViewHandler` pattern.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7fb11a38-1848-4bb2-8b5c-7853dcad56bb
<!-- 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
- Restrict CI-fixer human-PR dedup searches to PR titles and bodies, and
require an explicit ownership reference before stopping triage.
- Add a shared CI-fix triage policy and hermetic Vally capability
scenarios for ownership, stale failures, safe de-flaking, and attempt
limits.
- Regenerate both CI-fixer workflow locks with gh-aw v0.82.14.

## Testing
- `gh aw compile .github/workflows/ci-status-fix.md`
- `gh aw compile .github/workflows/ci-status-fix-net11.md`
- `vally lint .github/skills/ci-fix --eval-spec
.github/skills/ci-fix/tests/eval.vally.yaml --strict`
- Focused actionlint validation of the generated locks (baseline gh-aw
expression diagnostics excluded).

---------

Co-authored-by: PureWeen <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d41db557-d1b5-45e0-ba14-f5a71cf61f0a
Copilot-Session: 8eac356d-a7ec-4451-a4bc-ad6d2cd88023
… preview8) (#36803)

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

The `release-readiness` skill's `Get-MilestoneHygieneChecks` derived the
roll-forward milestone for a preview cycle by naively incrementing the
preview number:

```powershell
$expectedTitlesNext = @(".NET $major.0-preview$($cycleNum + 1)")
```

So surveying `preview7` told the release captain to create a **`.NET
<major>.0-preview8`** milestone. **.NET does not ship a preview8.** The
pre-release train is:

```
preview1 → preview2 → … → preview7 → rc1 → rc2 → GA
```

This surfaced during an **ad-hoc SR-lane run against the net11
`preview7` branch** — `Get-ReleaseReadiness.ps1 -SrBranch
release/11.0.1xx-preview7` — where the report recommended creating `.NET
11.0-preview8`. The **automated preview lane**
(`Get-PreviewReadiness.ps1` → `Test-PreviewMilestoneExists`) never had
this bug: it validates only the *current* preview's own milestone and
never derives a next-cycle title. This fix therefore hardens the SR
lane's defensive preview-handling — see the reachability note in
`SKILL.md` — rather than changing automated preview-lane behavior.

#### Evidence (from this repo)

| Major | Last preview | Then |
|-------|--------------|------|
| .NET 9 | `9.0.0-preview.7.24407.4` | `9.0.0-rc.1.24453.9` →
`9.0.0-rc.2.24503.2` |
| .NET 10 | `10.0.0-preview.7.25406.3` | `10.0.0-rc.1.25424.2` →
`10.0.0-rc.2.25504.7` |

Matching milestones: `.NET 10.0-preview7` (due 2025-08-01) → **`.NET
10.0-rc1`** (due 2025-08-21) → `.NET 10.0-rc2`. No `preview8` milestone
exists in any major since .NET 6.

There was also a **second, worse instance of the same bug**: in
`candidate` mode the ordinal is incremented before deriving the
*current* title too, so a candidate off `preview7` reported its own
current cycle as `preview8` — a milestone that can never exist, which
would render as a permanent spurious `BLOCKED` row.

### Changes

`.github/skills/release-readiness/scripts/Get-ReleaseReadiness.ps1`
- Add `Get-PreviewTrainMilestoneTitle` — a pure ordinal →
milestone-title mapper (`1..7` → previews, `8` → `rc1`, `9` → `rc2`,
`10+` → `$null`). `$script:FinalPreviewNumber` is the single constant to
change if the cadence ever moves (.NET 5 shipped 8 previews; 7 has held
since .NET 6).
- Use it for **both** the current- and next-cycle titles.
- Skip the next-cycle check entirely after `rc2` instead of inventing an
`rc3`.
- Widen the stale-milestone filter to `(preview|rc)\d+` — preview and rc
are one continuous pre-release train, so a stale `rc1` is the same
housekeeping debt as a stale `preview6`. **(Review refinement:** the
filter now also excludes `$expectedTitlesNext`, so a
slipped-but-upcoming `rc1` — the survey's own next-cycle target — isn't
mislabeled "already-shipped debt", which had contradicted the "create
it" advice from the next-cycle check.**)**
- **(Review refinement)** `Get-MilestoneHygieneChecks` now emits
`UNKNOWN` — rather than a silent `return @()` — for a nonsensical sub-1
preview ordinal (e.g. a `release/<major>.0.1xx-preview0` branch),
preserving the lane's documented "never silently skips" contract. The
legitimate past-`rc2` case stays a silent skip (GA has no milestone in
this naming convention).

`.github/skills/release-readiness/SKILL.md`
- New **Pre-release train cadence (no `preview8`)** section with the
tag/milestone evidence above.
- Updated the `Milestone for next cycle` / `Stale open milestones`
ship-check rows.
- Documented that **`preview7` is the effective feature/API-lock gate**:
because no eighth preview exists, work that misses the preview7 cut does
not roll into "the next preview" — RC is normally API-locked, so in
practice it slips to the next major. Reports on a preview7 branch should
treat still-open public-API PRs as a *decide-now* item.
- **(Review refinement)** Added a **reachability note** clarifying that
the `preview→rc` mapping fires only in the SR lane when driven with a
preview-shaped branch; an in-flight survey of a cut `release/*-rc1`
branch produces no milestone checks at all (rc branch shapes are skipped
by the parser).


`.github/skills/release-readiness/scripts/Find-ReleaseReadinessTrackers.ps1`

**(Review refinement — this file was originally reported as needing no
change; that was wrong.)** Lane 4 does read `PreReleaseVersionIteration`
from the survey ref rather than incrementing, and it does no-op once the
label flips from `preview` to `rc`. But **the no-op is the bug, not the
safeguard.** The same preview→rc discontinuity this PR fixes for
milestone naming applies here: the pre-release train continues into
`rc1`/`rc2`, so once the survey ref is bumped past the final preview the
`PreLabel -eq 'preview'` guard stops matching for the entire rc window
and **no rc tracker is ever proposed**.

Verified against this repo rather than assumed: `release/10.0.1xx-rc1`'s
`Versions.props` carries `rc`/`1`, and rc branches and tags use naming
exactly parallel to previews (`release/<major>.0.1xx-rc<N>`,
`<major>.0.0-rc.<N>.<build>`).

- Lane 4 now recognises the rc phase explicitly and **warns** with an
actionable message.
- It deliberately does **not** emit an rc tracker, because the rest of
the preview lane is still preview-only and an rc tracker would break
downstream rather than help: `Get-PreviewReadiness.ps1`'s branch parser
hard-`throw`s on any ref that isn't `release/<major>.0.1xx-preview<N>`,
and rc branches/tags don't match the strict preview regexes — so Lane
3's in-flight detection and the already-cut / already-shipped dedup
would never fire and the same rc candidate would be re-proposed forever.
The inline comment records exactly what full rc support requires, so the
follow-up is scoped rather than rediscovered.
- The fix therefore targets the genuinely dangerous half: **the
silence.** This case previously fell into the same `No active preview
cycle` line a major legitimately in SR phase prints, so a release
captain could not distinguish "nothing to do" from "rc1 needs a tracker
and you won't get one".

### Tests

Added 25 assertions (**M17–M23**, plus **M20b / M20c / M20d / M22c**
from review) to `Test-ReleaseReadiness.ps1`:

- `preview7` → next cycle is `rc1`, and explicitly **not** `preview8`
- `preview7` + `rc1` both present → no check emitted
- `preview6` → still `preview7` (cadence below 7 unchanged)
- candidate mode off `preview7` → current `rc1`, next `rc2`
- **(M20b)** candidate off `preview7` with `rc1` *missing* →
current-cycle `BLOCKED` naming `rc1` (not `preview8`) — the
negative-case guard for the newly-reachable rc current-cycle check;
mutation-verified to catch a mutant that neuters `BLOCKED` for every
`-rc\d+$` title
- **(M20c / M20d)** `preview0` ordinal → `UNKNOWN`; past-`rc2` ordinal →
silent skip (0 checks)
- `rc2` → no roll-forward check (GA follows)
- **(M22b / M22c)** a stale `rc2` (neither current nor next) is flagged;
a slipped next-cycle `rc1` is **not** flagged as stale debt
- pure-function mapping for ordinals 0, 1, 7, 8, 9, 10 and major-number
substitution

Subsequent adversarial-review rounds added further coverage and fixes:

- **(M22 / M22b)** negative coverage for Check 3b — it must stay silent
when the past-due milestone is not the roll-forward target.
- **`Get-PastDueOpenMilestones`** — extracted so Check 3 and Check 3b
cannot drift apart on what "past due" means.
- **`Sort-Object -Stable`** — PowerShell's default `Sort-Object` is
*not* stable (ties are only preserved with `-Top`/`-Bottom`/`-Stable`);
since sorting now happens before each caller's discriminator, stability
is what makes the new ordering equivalent to the old. Divergence only
begins around 17 elements, because .NET falls back to a stable insertion
sort below ~16 — so the guarding fixture is padded past that threshold.
- **(M22e / M22f)** ordering is now pinned in two separate scenarios
because neither catches the other's mutant: M22e uses all-tied `due_on`
(kills the missing-`-Stable` mutant but cannot see direction), M22f uses
distinct dates (kills `-Descending`).
- **Dual-tracker E2E gate** — this assertion ran against the live repo
and had two independent preconditions (branch cut *and* survey ref
bumped) but only checked the first, so it failed for the whole
legitimate interval between them. It also derived its expected tracker
as `shipped+2`, i.e. it was asserting the very `preview8` naming this PR
removes. It now reads the survey ref's actual iteration and derives the
expectation from it.
- **(rc window)** synthetic scenario for the Lane 4 fix above, **plus a
negative control** so a naive "always warn" cannot satisfy it.

```
Passed: 1124   Failed: 0
```

Every fix is **mutation-verified** — reverting each one fails its own
assertion and no others. Two mutants were checked in both directions for
the rc-window change (reverting to silence fails the warning assertions;
forcing the condition to `$true` fails the negative control). One
surviving mutant is left deliberately: `-lt` → `-le` on the grace
cutoff, which requires exact datetime equality to distinguish and is
pre-existing.

The 5 pre-existing milestone scenarios that could have regressed (M11,
M12, M13, M15) all still pass — notably M15, which asserts an `rc`
*branch shape* is still skipped (that's a separate, intentional
behaviour and out of scope here).

### Issues Fixed

None filed — found during an ad-hoc SR-lane run against the net11
`preview7` branch (`Get-ReleaseReadiness.ps1 -SrBranch
release/11.0.1xx-preview7`).

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: kubaflo <kubaflo@users.noreply.github.com>
Copilot-Session: 63594848-5aab-4ffa-8cb0-a64823163037
Copilot-Session: d00747b7-96f3-4e7a-8dfb-e3a48db04b2d
Copilot-Session: 7f87d6b9-cc21-4952-81c7-787a8585ce11
<!-- 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!

Updates `github-merge-flow-release-11.jsonc` to point the `net11.0`
merge flow at `release/11.0.1xx-preview7` now that preview6 has been
cut.

## Changes

- **`github-merge-flow-release-11.jsonc`**: `MergeToBranch` updated from
`release/11.0.1xx-preview6` → `release/11.0.1xx-preview7`

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: PureWeen <5375137+PureWeen@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 28, 2026 15:11
@kubaflo
kubaflo temporarily deployed to copilot-pat-pool July 28, 2026 15:11 — with GitHub Actions Inactive
@github-actions

Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

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

curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 36883

Or

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

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This pull request reverts the behavior changes from #35632 on the .NET 10 servicing line, restoring the prior cross-platform behavior of auto-tinting SwipeItem.IconImageSource for contrast/legibility (and removing the associated test artifacts and baselines that were added to validate the newer behavior).

Changes:

  • Restores prior icon tinting behavior on Android and iOS by applying contrast-based tinting to swipe item icons again.
  • Reverts Windows swipe item icon mapping back to ToIconSource() (and removes the async icon loading helper introduced in #35632).
  • Removes the Issue23074 HostApp page, shared UI test, and the added SVG test asset used to validate the now-reverted behavior.

Reviewed changes

Copilot reviewed 6 out of 23 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/Core/src/Handlers/SwipeItemMenuItem/SwipeItemMenuItemHandler.Android.cs Reverts to applying a color filter based on GetTextColor() for swipe item icon drawables.
src/Core/src/Handlers/SwipeItemMenuItem/SwipeItemMenuItemHandler.iOS.cs Reverts to template rendering + tinting for swipe item icons rather than preserving original raster colors.
src/Core/src/Handlers/SwipeItemMenuItem/SwipeItemMenuItemHandler.cs Reverts Windows source mapping to use ToIconSource() directly instead of async image-service loading.
src/Core/src/Handlers/SwipeItemMenuItem/SwipeItemMenuItemHandler.Windows.cs Removes the previously-added async LoadFileIconAsync helper and related usings.
src/Controls/tests/TestCases.HostApp/Issues/Issue23074.cs Removes the HostApp repro/validation page added for the reverted behavior.
src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue23074.cs Removes the screenshot-based UI test added for the reverted behavior.
src/Controls/tests/TestCases.HostApp/Resources/Images/cancel_red.svg Removes the test SVG asset added for the reverted behavior.

Comment on lines +124 to 131
if (item.Source is IFontImageSource fontImageSource && fontImageSource.Color != null)
button.TintColor = fontImageSource.Color.ToPlatform();
else
{
button.TintColor = null;
var tintColor = item.GetTextColor();
if (tintColor != null)
button.TintColor = tintColor.ToPlatform();
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks — this PR is a deliberate revert of #35632, so it intentionally restores the prior SwipeItem icon-tint code. You're right that the restored else branch only assigns button.TintColor when GetTextColor() is non-null, so a stale tint can persist — but that's the pre-#35632 behavior being restored, not a defect introduced by this revert. #35632 had actually addressed exactly this (it used AlwaysOriginal rendering for raster images and set TintColor = null on the non-font path); since that change is what's being reverted, the unconditional/explicit-reset handling should ride along with a forward re-fix of #35632 rather than be layered onto the revert, so this PR cleanly restores the known-prior state.

@kubaflo

kubaflo commented Jul 28, 2026

Copy link
Copy Markdown
Contributor Author

Closing in favor of #36887.

This branch was cut from main but targets inflight/candidate. Because main is 42 commits ahead of inflight/candidate, GitHub was trying to merge all of those unrelated commits along with the revert, which is where the "43 commits / 100 files changed" and the four conflicts came from. None of the conflicting files (ShellFlyoutLayoutManager.cs, Issue36154.cs, MauiWebView.cs) have anything to do with SwipeItem — resolving them here would have meant making unrelated integration decisions, including silently dropping #33335, which is on inflight/candidate but not on main.

#36887 applies the same revert directly on top of inflight/candidate: one commit, 23 files, zero conflicts, and identical content.

@kubaflo kubaflo closed this Jul 28, 2026
kubaflo added a commit that referenced this pull request Jul 28, 2026
…ross platforms (#35632)" (#36887)

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

> Supersedes #36883, which was branched off `main` while targeting
`inflight/candidate`. That mismatch dragged in 42 unrelated `main`-only
commits and produced four spurious conflicts in files that have nothing
to do with `SwipeItem`. This branch is built directly on
`inflight/candidate`, so it is a clean single-commit diff.

### Issue Details

This reverts #35632 ("Fix SwipeItem IconImageSource color handling and
rendering across platforms") from the .NET 10 servicing line.

#35632 stopped auto-tinting `SwipeItem.IconImageSource` for PNG/SVG
sources, so those icons now render in their own colors instead of a
contrast color derived from the item background. It shipped in 10.0.90
(SR9) and is causing #36766 — an SVG icon whose fill is `#212121` now
renders black on a black swipe item in dark mode, i.e. effectively
invisible.

The change is a reasonable direction, but it is too breaking for a
servicing release:

- **It removes a legibility guarantee with no replacement.**
`GetTextColor()` picks white or black from background luminosity. #35632
removed that for PNG/SVG but left it in place for the item's label text,
so the text is still contrast-corrected while the icon is not.
- **There is no opt-in.** #23074 was labelled `proposal/open` and asked
for *more configuration*; what shipped was a behavior change with none.
An affected app's only options today are pinning to 10.0.80 or
re-authoring every SVG per theme.
- **It compounds with #36271** (also SR9), which makes `BackgroundColor`
correctly follow `AppThemeBinding`. Before SR9 the stale light
background accidentally preserved contrast; together the two changes
produce black-on-black.
- **The prior behavior was the Xamarin.Forms behavior**, not an
inconsistency — Xamarin tinted every icon unconditionally on both
Android
([`SwipeViewRenderer.cs#L858`](https://github.com/xamarin/Xamarin.Forms/blob/main/Xamarin.Forms.Platform.Android/Renderers/SwipeViewRenderer.cs#L858))
and iOS
([`SwipeViewRenderer.cs#L713`](https://github.com/xamarin/Xamarin.Forms/blob/main/Xamarin.Forms.Platform.iOS/Renderers/SwipeViewRenderer.cs#L713)).

### Description of Change

`git revert` of c78acfe, restoring the previous behavior on all
platforms:

- **Android** — `SetColorFilter(GetTextColor(), SrcAtop)` applied to
every drawable again
- **iOS/Mac** — `AlwaysTemplate` rendering mode on every image again,
with `TintColor = fontImageSource.Color ?? GetTextColor()`
- **Windows** — `MapSourceAsync` back to `ToIconSource()`
(`BitmapIconSource`, whose `ShowAsMonochrome` defaults to `true`); the
`LoadFileIconAsync` helper is removed

The `Issue23074` host-app page, shared test, `cancel_red.svg` and the
`SwipeItemFontAndSvgIconsRenderCorrectly` snapshots are removed with it,
and the SwipeView snapshots are restored to their pre-#35632 baselines.

The revert is scoped strictly to #35632. `MapVisibility` on the Windows
handler — added on `inflight/candidate` after #35632 — is untouched.

**Conflict resolution note:**
`TestCases.iOS.Tests/snapshots/ios/VerifyCollectionViewContentWithIconImageSwipeItem.png`
conflicted because #36202 re-saved it for iOS 18 after #35632 landed.
That test's swipe item has `BackgroundColor = #6A5ACD` (luminosity ≈
0.40 → white), so with this revert `groceries.png` is tinted solid white
again and the pre-#35632 baseline is the correct content. If iOS 18 CI
shows drift unrelated to the tint, this one snapshot may need a re-save
from the CI artifact.

### Follow-up

The behavior change itself is good and should ship — just in .NET 11
rather than servicing, paired with an explicit opt-in API so users get a
real migration path instead of a silent rendering change in a patch
release. That is #36884, which keeps the #35632 behavior and adds
`SwipeItem.IconColor`.

### Issues Fixed

Fixes #36766

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: cb2a11ab-30ba-4020-836a-3acccb5f58cc
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Android][Regression] SwipeItem IconImageSource becomes black on black background in Dark Mode

7 participants