Skip to content

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

Merged
PureWeen merged 31 commits into
net11.0from
merge/main-to-net11.0
Jun 28, 2026
Merged

[automated] Merge branch 'main' => 'net11.0'#36139
PureWeen merged 31 commits into
net11.0from
merge/main-to-net11.0

Conversation

@github-actions

Copy link
Copy Markdown
Contributor

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

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

  • PureWeen
  • kubaflo
  • devanathan-vaithiyanathan
  • jfversluis
  • dependabot[bot]
  • akoeplinger

Instructions for merging from UI

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

merge button instructions

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

Instructions for merging via command line

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

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

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

After PR checks are complete push the branch

git push

Instructions for resolving conflicts

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

Instructions for updating this pull request

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

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

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

akoeplinger and others added 30 commits June 15, 2026 22:11
)

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

Several request-interception device tests were running an
`[InlineData("https://echo.free.beeceptor.com/...")]` row on Windows and
Android Helix queues even though that external service is known to be
flaky (tracked in #33927). The sibling tests in the same files already
skip that scenario; these four were missed:

-
`BlazorWebViewTests.RequestsCanBeInterceptedAndCustomDataReturnedForDifferentHosts`
-
`BlazorWebViewTests.RequestsCanBeInterceptedAndCancelledForDifferentHosts`
-
`BlazorWebViewTests.RequestsCanBeInterceptedAndCaseInsensitiveHeadersRead`
-
`HybridWebViewTests_Interception.RequestsCanBeInterceptedAndCancelledForDifferentHosts`

Reflection on the built `Microsoft.Maui.Controls.DeviceTests.dll`
(net10.0-windows10.0.19041.0) confirmed each of these methods had a
`Microsoft.Maui.TheoryAttribute` with **no** `Skip` and the
`https://echo.free.beeceptor.com/` `InlineData` attached — they would
attempt a real outbound TLS request from the Helix worker whenever
interception did not fire.

### Fix

Split the single `[Theory]` into two: one inside the `#if !ANDROID &&
!WINDOWS` block (paired with the `app://echoservice/` row) and one
inside the `#if !IOS && !MACCATALYST` block carrying `Skip = "Flaky due
to external service dependency (echo.free.beeceptor.com). See
https://github.com/dotnet/maui/issues/33927"` (paired with the
`https://` row).

This matches the convention already used by the three other sibling
methods (`CustomDataReturned`, `HeadersAdded`,
`CaseInsensitiveHeadersRead` in `HybridWebViewTests_Interception.cs`).

Importantly, **iOS / MacCatalyst coverage is preserved** — only the
`https://` rows are skipped. The `app://echoservice/` rows are fully
self-contained (the OS cannot resolve the `app://` scheme, so the
request never touches the network — it is satisfied entirely by the
`WebResourceRequested` handler inside the test).

### Per-TFM safety check

The custom `Microsoft.Maui.TheoryAttribute` has `AllowMultiple = false`,
and the `#if` guards make the two `[Theory]` attributes mutually
exclusive across every TFM in `MauiDeviceTestsPlatforms`:

| TFM | `[Theory]` (app://) | `[Theory(Skip)]` (https://) |
|---|---|---|
| net10.0-android | excluded | included |
| net10.0-windows10.x | excluded | included |
| net10.0-ios | included | excluded |
| net10.0-maccatalyst | included | excluded |

### Issues Fixed

Related to #33927.

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

Restricts `/review rerun` eligibility so PRs are only queued for rerun
when there is new PR-author activity after the latest AI Summary or
previous rerun checkpoint:

- new non-command comments from the PR author
- new commits / head changes

Reviewer or maintainer reminder comments no longer satisfy the rerun
evidence check.

### Issues Fixed

Prevents `/review rerun` from applying `s/agent-ready-for-rerun` when
only a reviewer/maintainer comment was added after the latest AI
Summary.

---------

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 `Skill Validation Results` PR comment to match the visual
style used by AI Summary and Test Failure Review comments:

- stable marker plus `## Skill Validation Results` title
- PR author/commit context
- status badges for overall, static checks, LLM evaluation, skills, and
agents
- a single expandable session with commit metadata
- existing static-check and LLM-evaluation details preserved inside the
session

### Issues Fixed

No issue filed.

### Validation

- Extracted and syntax-checked the `actions/github-script` post-comment
JavaScript with `node --check`
- `git diff --check`

---------

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

Adds a deterministic, evidence-backed release-readiness skill that
produces a single "Is `release/X.Y.Zxx-srN` (or preview) ready to ship?"
report for .NET MAUI release branches — both **Servicing Releases (SR)**
and **Previews**, in both **in-flight** and **candidate** (pre-cut)
modes.

Supersedes #35754.

## What it does

`Get-ReleaseReadiness.ps1` walks the SR branch, classifies open
`regressed-in-*` issues against branch contents, computes the source-PR
list (handling cherry-pick number swaps + non-main forward-flow), and
rolls up an "is this ready to ship?" verdict with a **Blocking** summary
hoisted to the top of the report.

Posts/refreshes a single `[Release Readiness]` GitHub tracking issue per
release lane (idempotent via a semantic hash marker — only reposts when
something meaningfully changed). See **[issue #35876
(SR8)](#35876 for a live
example.

## Ship-readiness checks

A release captain sees these surface as 🟢 READY / 🟡 WATCH / 🔴 BLOCKED /
⚪ UNKNOWN rows. All BLOCKED rows roll up into the **Blocking** summary
at the top.

| Check | Catches |
|-------|---------|
| **Versions.props bump** | SR cycle hasn't been bumped on the SR branch
|
| **Versions.props servicing flip** | `PreReleaseVersionLabel=servicing`
+ `StabilizePackageVersion=true` not applied — branch silently builds
prerelease packages |
| **Bug template lists SR version** | Users can't file bugs against the
new version |
| **Main bumped to next SR cycle** | Post-SR-cut PRs on main would
falsely claim to ship in the SR being shipped |
| **BAR default-channel mapping** | SR branch not wired to `.NET <band>
SDK` in BAR — caught the real SR8 outage |
| **BAR build for SR HEAD** | No published build at the SR HEAD commit |
| **Milestone for current cycle** | Fixed issues have nowhere to land |
| **Milestone for next cycle** | Open issues can't roll forward when
current ships |
| **Stale open milestones** | Already-shipped releases accumulating
untriaged issues (scoped to same major + same cycle type, 7-day grace) |
| **CI Failure Scanner signals** | Fresh ci-scan issues filed in the
last 24h |
| **Known Build Errors** | Open KBE issues that may explain background
CI noise |

Each check that needs external tooling (darc, gh, milestone API)
degrades to **UNKNOWN** with the exact verification command embedded —
the report never silently skips.

## Expected ship date

Header line surfaces the deadline. Cadence is patch-aware:
- `PatchVersion` ends in 0 (`80`, `90`, `100`…) or `0` (previews) → 2nd
Tuesday of the month
- Anything else (`81`, `82`, `91`…) → **ASAP** hotfix, no cadence

## Custom agent

`.github/agents/release-readiness-agent.agent.md` wraps the skill —
handles regression-label confirmation, runs the script, then uses
**WorkIQ** + **maestro MCP** to:
- Patch UNKNOWN BAR rows live (e.g. when darc isn't on CI's PATH)
- Add narrative context for `rejected-from-sr` PRs (chat history, review
feedback)
- Present the final READY / Conditionally Ready / Not Ready verdict with
citations

## Testing

```bash
pwsh .github/skills/release-readiness/tests/Test-ReleaseReadiness.ps1
# 447 pass / 0 fail
```

Dogfooded live against SR7 + SR8 + the .NET 11 preview lane. Caught
real-world bugs:
- **SR8** missing from BAR default-channel mappings (verified via
`maestro_default_channels` MCP)
- `.NET 10 SR6` + `.NET 10 SR7` milestones open with 76 + 63 open
issues, past due
- `.github/ISSUE_TEMPLATE/bug-report.yml` missing `10.0.80` entry

## Methodology gotchas (documented in `references/methodology.md`)

1. **Cherry-pick number swap** — SR backports get NEW PR numbers; can't
naively grep source PR numbers
2. **Timeline cross-references** — `closedByPullRequestsReferences`
returns empty for most MAUI issues; must walk `gh api
.../issues/N/timeline` cross-referenced events
3. **Forward-flow / non-main merges** — a fix can merge into
`inflight/current` only, not `main` (real example: PR #35609)

## Files

- `.github/skills/release-readiness/SKILL.md` — skill entry point +
reference docs
- `.github/skills/release-readiness/scripts/Get-ReleaseReadiness.ps1` —
main orchestrator (deterministic, no MCP)
- `.github/skills/release-readiness/tests/Test-ReleaseReadiness.ps1` —
447-assertion test suite
- `.github/skills/release-readiness/references/methodology.md` — gotchas
and patterns
- `.github/agents/release-readiness-agent.agent.md` — MCP-enriched agent
wrapping the skill

---------

Co-authored-by: bot <bot@test>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: VSC Agent <vsc-agent@example.com>
…35942)

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

Migrates the `skill-validation.yml` workflow from the legacy
`dotnet/skills` binary (`skill-validator check` + `skill-validator run`)
to
**[@microsoft/vally-cli@0.6.0](https://github.com/nicknow-ms/vally)**.
All 5 skill-eval suites are ported and validated green in CI.

## What Changed

### Workflow (`skill-validation.yml`)
- Replaced `skill-validator` install/check/run steps with `vally lint
--strict` and `vally run --eval-spec`
- Added **hermeticity negative-control gate** that verifies the sandbox
doesn't have unauthorized network access (rate-limit auth detection)
- Added `workflow_dispatch` manual trigger with `skills` and `runs`
inputs for on-demand evaluation
- Changed fixture fetch depth from `--depth=1` to `--depth=2` so `git
diff HEAD^ HEAD` works in worktree environments
- Removed all `skill-validator` references and legacy `eval.yaml` files

### Eval Specs Ported (all in `.github/skills/<skill>/tests/`)
| Skill | File | Stimuli | Status |
|-------|------|---------|--------|
| code-review | `eval.capability.vally.yaml` | 9 capability scenarios |
✅ 9/9 |
| code-review | `eval.vally.yaml` | 2 regression scenarios | ✅ 2/2 |
| code-review | `hermeticity.vally.yaml` | 1 negative control | ✅ |
| agentic-labeler | `eval.vally.yaml` | 3 labeling scenarios | ✅ |
| try-fix | `eval.vally.yaml` | 2 fix scenarios | ✅ |
| verify-tests-fail-without-fix | `eval.vally.yaml` | 2 verification
scenarios | ✅ |
| evaluate-pr-tests | `eval.vally.yaml` | 2 evaluation scenarios | ✅ |

### Key Design Decisions
- **Structural graders** (output-matches, output-not-contains) verify
hard behavioral requirements (e.g., never approve via API, verdict
markers present)
- **LLM prompt graders** (scale_1_5) assess quality and depth with
calibrated thresholds
- Regression stimuli use **frozen git worktrees** pinned to
known-regressing commits — no network calls, fully reproducible
- Capability stimuli target **real merged PRs** to test against actual
code review scenarios

## Validation

Final CI run
[#27635665319](https://github.com/dotnet/maui/actions/runs/27635665319):
**11/11 stimuli pass, 0 failures**.

Iteratively validated across 9 CI runs, fixing:
- Fixture fetch depth (parent commit needed for `git diff`)
- Structural floor regex (added 🔴 marker, broadened to accept
`Verdict`/`Finding`)
- Merged-PR prompt engineering (agents short-circuit reviews on merged
PRs)
- Environment constraints (Vally sandbox lacks GH_TOKEN — adjusted
rubrics accordingly)
- LLM judge threshold calibration (structural graders verify
correctness; LLM judges assess quality)

## Removed
- All `eval.yaml` files (legacy skill-validator format)
- `skill-validator` binary installation steps
- `--allow-repo-traversal` flag usage (Vally worktrees provide full repo
access natively)

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…compile all to v0.79.8 (#35951)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

## Summary

Adds top-level `environment: gh-aw-agents` gating to the 4 gh-aw
workflows that have write capabilities or uncapped inference spend,
following the [gh-aw best
practice](https://github.github.com/gh-aw/reference/cost-management/):
*"Gate any write-capable or spendy agentic workflow behind such an
environment."*

Uses a **single shared environment** (`gh-aw-agents`) since the AzDO
federation secrets are also used by `review-trigger.yml`, so
per-workflow secret isolation isn't achievable.

Also brings **all 7** gh-aw workflow lock files to the current compiler
(v0.79.8 / AWF 0.27.2).

**Validated:** triggered `ci-status-main` on this branch — activation ✅,
agent job running ✅ (confirms `COPILOT_GITHUB_TOKEN` from environment is
accessible).

## Changes

### Commit 1: Environment gating + deprecated field migration

| Workflow | Write surface |
|----------|---------------|
| `rerun-review-scanner` | Labels, reactions, AzDO pipeline triggers,
federation secrets |
| `ci-status-main` | Creates up to 5 tracking issues/run |
| `ci-status-net11` | Creates up to 5 tracking issues/run |
| `daily-repo-status` | Creates issues + closes older ones |

All 4 now use `environment: gh-aw-agents`. Also migrates the deprecated
`max-effective-tokens: -1` → `max-ai-credits: -1` in both CI scanner
workflows.

### Commit 2: Lock freshness

Recompiles `agentic-labeler.lock.yml` and
`copilot-review-tests.lock.yml` to current gh-aw v0.79.8 / AWF 0.27.2.
No source `.md` changes — lock-only refresh.

### Commit 3: Fix copilot-evaluate-tests + recompile

Fixes `workflow_dispatch.inputs.pr_number.required: true` → `false` —
v0.79.8 correctly rejects `required: true` when `slash_command:` is also
configured (auto-dispatch can't fill required inputs). The workflow
already falls back to `github.event.issue.number` from slash command
context.

## Intentionally NOT gated

| Workflow | Reason |
|----------|--------|
| `agentic-labeler` | Uses `roles: all` for community auto-labeling;
gating would require approval per issue/PR |
| `copilot-evaluate-tests` | Comment-only (max 1), already role-gated to
`[admin, maintain, write]` |
| `copilot-review-tests` | Same as above |

## Environment setup (already done ✅)

The `gh-aw-agents` environment has been created with:
- ✅ `COPILOT_GITHUB_TOKEN` — Copilot inference auth
- ✅ `AZDO_TRIGGER_TENANT_ID` — AzDO Workload Identity Federation
- ✅ `AZDO_TRIGGER_CLIENT_ID` — AzDO Workload Identity Federation
- No required reviewers (scheduled automation would stall)
- No branch restrictions yet (can be added post-merge for `main` +
`net11.0`)

---------

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!

## Problem

The milestone-drift automation (`Fix-MilestoneDrift.ps1`) maps a commit
found on an SR release branch to a milestone using **only the branch
name** — `release/10.0.1xx-sr7` → `.NET 10 SR7`. But a single SR release
branch ships **many servicing drops** over its lifetime (`10.0.70` =
SR7, `10.0.71` = SR7.1, `10.0.72` = SR7.2, …), so the base SR is too
coarse.

A revert/hotfix that lands **after** the base SR shipped actually goes
out in a later sub-patch. Milestoning it as the base SR is wrong — and
can even **downgrade** an already-correct SR7.1 issue back to SR7.

### Concrete case that motivated this

- PR #35694 is a backport to `release/10.0.1xx-sr7`; its commit is
contained only in tag `10.0.71` → it ships in **SR7.1**.
- It directly links the issue via `Fixes #35584`.
- Before this change the script resolved #35694 → **SR7** (branch name),
which would *downgrade* issue #35584 from SR7.1 → SR7.

## Root cause

`Find-ReleaseBranchForCommit` resolved the milestone via
`ConvertBranchToMilestone` (branch-name only), which has no notion of
sub-patches.

## Fix (general — no special-casing)

Add `Get-RefinedReleaseMilestone`: for a commit found on an **SR**
branch, resolve the milestone from the **earliest SR-family tag**
(`X.0.{sr}{sub}`) that actually contains the commit (git ancestry).
Rules:

- **Earliest release wins** — return the earliest family tag that
contains the commit.
- If no family tag contains it yet (the drop isn't tagged), use the
**next sub-patch** after the latest shipped family tag — **clamped to
the SR family** so it never crosses into the next SR (an exhausted SR7
at `.79` falls back to base SR7, never predicts SR8).
- **Non-SR** milestones (preview/rc/GA) are returned unchanged.

It's wired into both match paths of `Find-ReleaseBranchForCommit`. The
PR-number grep fallback now captures the **oldest** on-branch SHA
(`--reverse`, so a later revert that re-mentions `(#NNN)` can't hijack
the result) and is hardened against stderr noise (`2>$null` + strict
40-hex SHA filter).

Result: #35694 → **SR7.1**, so its existing `Fixes #35584` link marks
the issue **SR7.1**. The existing earliest-release-wins guard reconciles
the issue regardless of merge order.

Note: PR #35625 (the same revert on `inflight/current`) intentionally
stays **SR9** — a PR's milestone tracks the physical branch it merged
into; the *issue* converges to the earliest customer-facing release
(SR7.1).

## Verification

- ✅ Dry-run #35694 → `.NET 10 SR7.1` (was SR7); issue #35584
already-correct (no downgrade).
- ✅ Regression dry-runs unchanged: #34620 → SR6, #35016 → SR6, #30132 →
preview3.
- ✅ Pester suite: **162 passed, 0 failed** (9 new unit tests for the
helper, incl. the family-boundary clamp).

## Review

Reviewed with three independent models (GPT-5.5, Gemini 3.1 Pro, Claude
Opus 4.8). Consensus on correctness and contained blast radius
(refinement only ever moves *within* one SR family). Their concrete
findings — boundary clamp, stderr hardening, oldest-match grep, and a
dead parameter — were all addressed in this PR.

---------

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

Follow-up to #35951 — extends `environment: gh-aw-agents` gating to the
**remaining 4 workflows** that were not included in the initial PR:

| Workflow | Type | Change |
|----------|------|--------|
| `agentic-labeler.md` | gh-aw | Added `environment: gh-aw-agents` |
| `copilot-evaluate-tests.md` | gh-aw | Added `environment:
gh-aw-agents` |
| `copilot-review-tests.md` | gh-aw | Added `environment: gh-aw-agents`
|
| `review-trigger.yml` | Regular GHA | Added `environment: gh-aw-agents`
to `trigger-review` job |

## Why

After #35951 merged, repo-level secrets (`COPILOT_GITHUB_TOKEN`,
`AZDO_TRIGGER_TENANT_ID`, `AZDO_TRIGGER_CLIENT_ID`) were deleted in
favor of environment-scoped secrets on the `gh-aw-agents` environment.
These 4 workflows need the `environment:` reference to access those
secrets.

## Details

- All 3 gh-aw workflow locks recompiled with `gh aw v0.79.8`
- `environment: gh-aw-agents` verified on agent + safe-outputs +
threat-detection jobs in all lock files
- `review-trigger.yml` is a regular GHA workflow — environment added at
job level, no compile needed
- Pre-existing compile warnings (agentic-labeler `pull_request_target`,
copilot-evaluate-tests `slash_command` + `bots:`) are unchanged and
intentional

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

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

When a maintainer comments `/review`, `/review rerun`, or `/review
tests` on a PR, the command comment lingers and clutters the
conversation. This change **hides the command comment as resolved**
(collapses it) **once the command is recognized and the commenter is
authorized** (i.e. once we accept and act on it). Unauthorized or
invalid attempts are left fully visible.

### Why hide instead of delete?

The rerun scanner reconstructs review/rerun state by replaying the PR's
comment history through the **REST list endpoint**
(`Resolve-RerunEligibility.ps1`, `Query-RerunReadyPRs.ps1`,
`Get-LatestRerunCommentBefore`). **Deleting** the command comments would
erase that durable checkpoint — re-qualifying unchanged commits and
dropping `--branch`/`--platform` options on later reruns.

Minimizing (GraphQL `minimizeComment(classifier: RESOLVED)`) collapses
the comment in the web UI but **keeps it in the REST comment history**,
so the scanner keeps working. This addresses the data-loss findings from
review without losing the decluttering benefit.

### Changes

| Command | Workflow | Where it's hidden |
|---|---|---|
| `/review` | `review-trigger.yml` (`trigger-review`) | after the AzDO
pipeline is triggered (`trigger_azdo == success`) |
| `/review rerun` | `review-trigger.yml` (`mark-rerun-ready`) | after
eligibility resolution, only when `eligible == 'true'` |
| `/review tests` | `copilot-review-tests.md` (gh-aw) | pre-activation
step |

All three call `minimizeComment(input: { subjectId: <comment node_id>,
classifier: RESOLVED })`.

**`review-trigger.yml`**
- `trigger-review`: hides the `/review` comment as the last step, gated
on `steps.trigger_azdo.outcome == 'success'` so a lock-skip or failed
trigger leaves the command (and its `--branch`/`--platform` options)
visible for retry. The job already has `issues: write`.
- `mark-rerun-ready`: hides the `/review rerun` comment **after**
`Resolve-RerunEligibility.ps1` runs and only when a rerun was actually
triggered (`eligible == 'true'`). Ineligible reruns keep the comment
fully visible.

**`copilot-review-tests.md` (gh-aw)**
- Keeps `on.permissions: issues: write` so the deterministic
pre-activation job token can minimize the comment (the AI agent job
stays read-only).
- The `github-script` pre-activation step minimizes the `/review tests`
comment only when the command is exactly `/review tests` (`should_run`),
the event is `created` (not `edited`), **and** the commenter is an
authorized collaborator (`write`/`maintain`/`admin`).
- Recompiled `copilot-review-tests.lock.yml` in the same commit (gh-aw
v0.77.5). `frontmatter_hash` updated; `body_hash`, the concurrency
block, and the read-only agent-job permissions are unchanged.

### Token / permissions

No special token is required. Minimizing uses the same `issues: write`
scope deletion did, via the default `github.token`. (Minimizing is the
same moderation tier as the previous deletion — if the token could
delete the comment, it can minimize it.)

### Safety
- **No double-hide** — each command activates exactly one minimize path
(`/review tests` is gated on the exact-match that `review-trigger.yml`
explicitly skips).
- Minimizing only runs on `issue_comment` `created` events (never
`workflow_dispatch`, never `edited`).
- A failed minimize emits a `::warning::` and never fails the
review/rerun/tests trigger.
- History is preserved: the REST comment list still returns minimized
comments, so the rerun scanner and option/checkpoint recovery are
unaffected.

### Validation
- `gh aw compile` → 0 errors / 0 warnings; lock diff verified (only the
step body + `frontmatter_hash` change; concurrency intact; agent job
still `issues: read`).
- `review-trigger.yml` and the regenerated lock parse as valid YAML.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…anches from the tracker matrix (#35971)

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

Follow-up to #35807. Two independent release-readiness fixes.

---

## Fix 1 — Surface p/0-labelled PRs as Preview release blockers

### Summary

The Preview readiness engine (`Get-PreviewReadiness.ps1`) only treated
**p/0 issues** as release blockers. **p/0-labelled PRs** targeting a
preview/candidate branch were silently bucketed into the generic
"Release branch PRs" WATCH count and rendered as "Needs review or
triage" rows — never hoisted, never blocking.

The root cause is structural: the p/0 blocker path used `gh issue list
--label p/0`, which **by design never returns PRs**. So p/0 PRs were
invisible to the blocker logic.

This was observed live on the **net11.0 preview6** tracker (#35866),
where #34758, #35626, and #34600 (all `p/0`, base `net11.0`) appeared
only as generic WATCH rows instead of blockers.

### What changed

Carves p/0-labelled PRs out of the generic human-PR bucket — the label
data is **already fetched** by `Get-OpenPullRequests`, so no extra API
call — and:

- adds a **BLOCKED `P/0 release-branch PRs`** check (parallel to the
p/0-issues check) so the overall verdict turns red when one is open;
- itemizes each p/0 PR as a **`🔥 P/0 PR`** row in the hoisted **🔴
High-priority items** section (with base ref + age + per-PR next
action);
- **excludes** the new check from the **🔴 Blocking** summary (its PRs
are already enumerated in the hoist) — exactly matching the p/0-issues
treatment;
- updates the WATCH note + hoist header/intro text from 3 → 4
high-priority categories.

A PR whose base **is** the survey ref is release-relevant by definition,
so — unlike issues — no title/milestone relevance filter is applied.

### Testability

Adds a small **StrictMode-safe `Test-IsP0Pr`** helper plus a
**dot-source guard** on the engine (mirroring
`Find-ReleaseReadinessTrackers.ps1`) so the predicate can be unit-tested
without invoking the full git/gh-backed report flow.

---

## Fix 2 — Drop stale below-watermark SR branches from the tracker
matrix

### Summary

The Lane 1 in-flight detector (`Find-ReleaseReadinessTrackers.ps1`)
treated **tag-absence** as the sole in-flight signal. Abandoned hotfix
leftovers like **SR2** (patch 21) and **SR3** (patch 33) — which never
published their stable tags and sit far below the shipped watermark
(**SR7** patch 71) — were still emitted as trackers. The workflow then
spun up a **no-op matrix job** per branch: the per-job activity gate
skipped issue creation, but the job still ran.

### What changed

Adds a secondary **`Test-IsStaleSrBranch`** disambiguator applied **only
after** `Test-IsBranchInFlight` returns true. A branch is stale when
**both**:

- its patch is **strictly below** the highest shipped patch, **and**
- it has had **no commits** within the activity window (idle).

Tag-existence stays the **primary** signal; the idle requirement
preserves the out-of-order / security-hotfix case — a real reset branch
below the watermark has recent commits and is therefore **not** dropped.
Freshly-cut live SRs sit at/above the watermark and are never affected.

Dropping these at the detector removes them from the workflow matrix
**entirely**. Verified safe: SR2/SR3 have no open tracker issues, so
nothing is stranded (only SR8/SR9/preview6 have open trackers).

---

### Tests

`Test-ReleaseReadiness.ps1`:
- **12** new unit assertions for `Test-IsP0Pr` (predicate: p/0
present/absent, missing/null/empty labels, hashtable-shaped labels, null
PR; carve-out semantics: p/0 subset selected, generic bucket excludes
them).
- **7** new unit assertions for `Test-IsStaleSrBranch` (below-watermark
idle → stale; above/equal watermark → not stale; below-watermark but
active → not stale; no shipped tags → never fires).
- Live-repo E2E expectations updated: net10 now surfaces **2** SR
trackers (SR8 + SR9) instead of 4.

```
Passed: 517   Failed: 0
```

---------

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

Removes `environment: gh-aw-agents` from the `trigger-review` job in
`review-trigger.yml`.

## Why

PR #35974 added `environment: gh-aw-agents` to `review-trigger.yml`,
which changed the GitHub OIDC token subject from
`repo:dotnet/maui:ref:refs/heads/main` to
`repo:dotnet/maui:environment:gh-aw-agents`. The managed identity
(`Testing-MI-gh2zdo`) behind `AZDO_TRIGGER_CLIENT_ID` has no federated
credential for that environment subject, so every `/review` command
fails with:

```
AADSTS700213: No matching federated identity record found for presented
assertion subject 'repo:dotnet/maui:environment:gh-aw-agents'
```

The `AZDO_TRIGGER_*` secrets have been re-added at the repo level. Once
the federated credential is updated (requires Azure access to the
managed identity), the environment gating can be re-added.

## What changed

- Removed `environment: gh-aw-agents` from the `trigger-review` job (1
line)
- All gh-aw workflows remain gated — only `review-trigger.yml` (regular
GHA) is affected

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ive assertions, add deterministic fixture coverage (#36004)

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

Follow-up to #35971. De-flakes a pre-existing time-bomb in the
release-readiness skill's **own** test suite
(`.github/skills/release-readiness/tests/Test-ReleaseReadiness.ps1`).
Skills-only change — no framework code touched.

### The time-bomb

The suite had four **live, wall-clock-dependent** assertions that
hardcoded `hasRecentActivity = $true` against real release branches
(SR8, SR9, the active-SR `foreach` loop, and preview6).

The detector (`Find-ReleaseReadinessTrackers.ps1`) computes
`hasRecentActivity` from `Get-RecentCommitCount`, which runs `git log
<branch> --since=7.days` and returns `(count > 0)`. So those assertions
are only true *while the real branch has had a commit in the last 7
days*. The moment a servicing branch goes quiet for 7 days — a
**normal** end-of-cycle state — the assertion flips red.

On **2026-06-18** this actually happened: SR8's last commit (the SR7→SR8
merge #35810) landed 2026-06-11, so `--since=7.days` returned 0 and the
two SR8 assertions went red. They self-heal on the next commit, but
nondeterministic red in a suite whose entire selling point is
determinism is a credibility bug.

### What changed

- **Removed the wall-clock-dependent live assertions.** The end-to-end
detector run now asserts only that `hasRecentActivity` is a real
`[bool]` the detector emitted — never a date-dependent value.
- **Added genuinely deterministic coverage of the recency-window math**
via a synthetic fixture: a throwaway temp git repo with commits at
controlled dates (`GIT_AUTHOR_DATE`/`GIT_COMMITTER_DATE` at now−6d /
now−8d / now−30d), then calls the **real** `Get-RecentCommitCount`
(dot-sourced) against it and asserts exact counts for the 7/10/60/1-day
windows plus the `origin/`-prefixed ref form. Zero network, zero
dependence on "today"; the temp repo is cleaned up in a `finally`.
- **Corrected the misleading comments** that equated "active SR" with
`hasRecentActivity = true`. An active SR can legitimately idle for >7
days; `hasRecentActivity` is a 7-day-window signal, not a synonym for
"active".

### Verification

Full suite is green: `pwsh -NoProfile -File
.github/skills/release-readiness/tests/Test-ReleaseReadiness.ps1` →
**Passed: 552, Failed: 0** (was 545/2 before, with the two SR8 reds).
The new fixture assertions also pass under `-SkipE2E` (offline),
confirming they're network-independent.

> Note: the `maui-pr` framework pipeline intentionally skips for
skills-only PRs — that's expected, not a failure.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…den comment posting (#36003)

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

### The bug

The **Skill Validation** workflow's `Post results comment` job was
failing on its `Post comment` step with:

```
ReferenceError: agentCount is not defined
    at eval (... actions/github-script/v7 ...)
##[error]Unhandled error: ReferenceError: agentCount is not defined
```

The `github-script` step builds a badge array that references
`agentCount`:

```js
badge('Skills', String(skillCount), '8250df'),
badge('Agents', String(agentCount), '0969da'),   // ❌ agentCount never defined/produced
```

…but `agentCount` was **never defined** in the script and **never
produced** as an artifact, whereas `skillCount` is defined (reads
`static-results/skill-count.txt`). The script threw while constructing
the comment body — *before* any API call — so the results comment was
**never posted**.

This was introduced on 2026-06-16 in commit `1c0c0eb200` (#35713, "Style
skill validation results comment") and has silently broken the results
comment on **every** Skill Validation run since.

It is a real, deterministic workflow bug — not a permissions issue (the
job already has `pull-requests: write` + `issues: write`) and not a
merge/close race (the failure is a JS `ReferenceError`, not a 403).

### The fix

Self-contained to `.github/workflows/skill-validation.yml`:

1. **Producer** — In the existing `Save results artifact` step (the one
that writes `skill-count.txt`/`spec-count.txt`), add an agent count
written to `agent-count.txt` in the same `sv-results/` dir, flowing
through the same `static-check-results` upload/download wiring:
   ```bash
agent_count=$(find .github/agents -mindepth 1 -maxdepth 1 -name '*.md'
-type f 2>/dev/null | wc -l | tr -d ' ')
   echo "$agent_count" > sv-results/agent-count.txt
   ```
2. **Definition** — In the `Post comment` github-script step, define
`agentCount` mirroring `skillCount`/`specCount` exactly (read
`static-results/agent-count.txt` inside a try/catch that falls back to
`'?'`), placed alongside the existing definitions so it's in scope
before the badge array.
3. **Hardening** — Wrap the badge + body construction in a `try/catch`.
On any failure it logs via `console.error` and `core.warning` (no silent
swallowing) and posts a minimal **plain-text fallback** body (keeping
the `<!-- skill-validation-results -->` marker so the upsert still
finds/updates the comment). The results comment now **always** posts
even if the badge formatting breaks.

### Validation

- YAML parses (`yaml.safe_load`).
- `agentCount` is defined (script line ~898) before its only use in the
badge array (line ~1178).
- The embedded github-script JS passes `node --check` (balanced braces /
valid scope) when wrapped in an async function (it uses top-level
`await`, which github-script permits).

The embedded JS can't be executed locally (depends on the
`github`/`context`/`core` runtime), so dynamic behavior wasn't run;
logic was reviewed by hand.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…R lane parity with Preview) (#36006)

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

### The gap

The release-readiness skill has two report generators. The **Preview
lane** (`Get-PreviewReadiness.ps1`) already surfaces open PRs carrying
the `p/0` label as release **blockers**. The **SR lane**
(`Get-ReleaseReadiness.ps1`) did **not**: it derived blocking only from
ship-checks (`BLOCKED`) and Tier-1 `regressed-in-*` **issue**
classifications. Open PRs were listed purely informationally.

Consequence: a `p/0`-labelled PR targeting an SR branch was never
flagged as blocking on the SR tracker issue. Concretely, PR #35970
(`Revert PR #33584…`, base `release/10.0.1xx-sr8`, label `p/0`) did
**not** show as blocking on the SR8 tracker issue #35876.

### What changed

- **Ported `Test-IsP0Pr`** from the Preview lane into
`Get-ReleaseReadiness.ps1`. It is StrictMode-safe and accepts both the
production `gh --json` PSCustomObject shape and the
IDictionary/hashtable shape used by test mocks.
- **Added `Get-P0PrChecks`**, which emits a single `P/0 release-branch
PRs` ship-check — `BLOCKED` (naming each offending PR, e.g. `#35970`)
when any open `p/0` PR targets the SR branch, `READY` otherwise.
- **Merged the check into `shipChecks`** in the main flow, reusing the
already-fetched open-PR list so there is **no extra `gh` call**. Because
it's a standard `BLOCKED` ship-check, it is automatically hoisted into
the top-of-issue `🔴 Blocking` summary and escalates the verdict to **Not
Ready** — no verdict or renderer changes were needed.
- **Added deterministic synthetic-fixture unit tests** for both
functions (no network, no wall-clock dependence).

### Notes

- This is a PowerShell-only `.github/skills/**` change; the framework
`maui-pr` pipeline intentionally skips for skills-only PRs.
- Discovered while working on the separate deflake PR #36004.

---------

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

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ments once authorized (#36021)

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

Follow-up to #35895, which switched the `/review`, `/review rerun`, and
`/review tests` command-comment cleanup from delete to GraphQL
`minimizeComment(classifier: RESOLVED)`. In practice the command
comments were **still left visible** in several cases. This PR makes all
three reliably collapse **once the command is recognized and the
commenter is authorized — regardless of the command's result.**

### Root causes (observed on #30311)

1. **`/review tests` — permission bug.** The gh-aw
`copilot-review-tests` pre-activation job that minimizes the comment
only had `issues: write`. The comment lives on a **pull request**, so
`minimizeComment` needs `pull-requests: write`; with only `issues:
write` it failed with `Resource not accessible by integration` (run
`27824496263`) and the comment stayed visible. #35895's assumption that
"minimizing requires the same `issues:write` scope that deletion did" is
incorrect for PR conversation comments.

2. **`/review rerun` — eligibility gate.** The `mark-rerun-ready` hide
step was gated on `eligible == 'true'`, so an **ineligible** rerun (e.g.
`no-new-comments-or-commits`) left the comment fully visible.

3. **`/review` — trigger-outcome gate.** The `trigger-review` hide step
was gated on `trigger_azdo.outcome == 'success'`, so a **lock-skip** or
a **failed AzDO trigger** left the comment visible.

### Changes

**`copilot-review-tests.md` (gh-aw)**
- Add `pull-requests: write` to the pre-activation job
(`on.permissions`) so it can minimize a PR comment. The AI agent job
stays read-only.
- Recompiled `copilot-review-tests.lock.yml` with gh-aw `v0.79.8`; only
`frontmatter_hash` and the pre-activation permission change —
`body_hash` is unchanged.

**`review-trigger.yml`**
- `/review rerun` and `/review` now minimize the command comment
whenever the actor is authorized and the command was recognized, no
matter the downstream outcome.
- Each job's "Check actor permission" step gets an `id: auth`; the hide
step is gated on `!cancelled() && github.event_name == 'issue_comment'
&& steps.auth.outcome == 'success'`. `!cancelled()` lets the hide run
even after an upstream step failed (failed trigger / ineligible rerun /
errored eligibility), while the `steps.auth` gate keeps **unauthorized**
commenters' comments fully visible.

### Safety / scope
- **Unauthorized comments are never hidden** (the `steps.auth.outcome ==
'success'` gate, and the internal collaborator check in the `/review
tests` script).
- **Transparent to the rerun scanner.** `Resolve-RerunEligibility.ps1` /
`Query-RerunReadyPRs.ps1` / `Get-LatestRerunCommentBefore` key on
comment `id`, body and `created_at` — never on `isMinimized` — and
minimized comments are still returned by the REST list endpoint.
Verified there are no `isMinimized` references in those scripts.
- A failed minimize emits a `::warning::` and never fails the
review/rerun/tests trigger.
- The only outcome not covered is a **cancelled/timed-out run**
(`!cancelled()` skips on interruption); every completed outcome is
covered.

### Validation
- `gh aw compile` → 0 errors / 0 warnings; recompiling produced no stray
diff.
- `review-trigger.yml` parses as valid YAML.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ferences and drop invalid authorAssociation gh field (#36029)

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

### Problem

The `[Release Readiness]` tracker issues were rendering `gh` warnings
embedded in their bodies, two distinct root causes:

**1. Cross-repo timeline cross-references (e.g. SR8 tracker #35876).**
`Get-IssueTimelinePrs` walked a regression issue's `cross-referenced`
timeline events and collected the source PR number **without checking
which repository the PR lives in**. Real examples found live:
- regression #35584 ← PR **#102** in `zhollis21/AniSprinkles` (an
unrelated personal app)
- regression #35771 ← PR **#24** in `praveenkumarkarunanithi/maui` (a
fork)

Looked up against `dotnet/maui` these 404 (`gh pr view 24 ... Could not
resolve to a PullRequest`), and the warning gets written into the
tracker issue. Worse, a foreign PR whose number *happens* to exist in
dotnet/maui (e.g. #877 from `DIPSAS/DIPS.Mobile.UI`) silently
mis-matches an unrelated dotnet/maui PR as a "fix candidate" with no
warning at all.

**2. Invalid `gh pr list` field (e.g. SR9 tracker #35867).**
`Get-CandidatePrChecks` requested `gh pr list --json
number,title,author,authorAssociation,updatedAt,url`, but
`authorAssociation` is **not a valid `gh pr list` projection field**
(it's REST-only). The whole query failed (`Unknown JSON field:
"authorAssociation"`), surfacing a warning and silently degrading the
maintainer spoof-gate.

### Fix

- `Get-IssueTimelinePrs`: drop any cross-reference whose
`repository.full_name` ≠ the target repo. The timeline API populates
`repository.full_name` for same-repo references too, so legitimate
dotnet/maui fix PRs are preserved. This fixes both the noisy 404
warnings and the silent wrong-repo mis-matches.
- `Get-CandidatePrChecks`: remove `authorAssociation` from the `gh pr
list` projection and fetch `author_association` per title-matched
candidate via `gh api repos/{repo}/pulls/{n}` (cheap — candidate matches
are almost always 0–1). Fail closed: an unreadable association excludes
the PR so a `Candidate`-titled spoof can't slip through.

### Tests

Adds 8 deterministic, offline (gh-stubbed) regression assertions:
cross-repo timeline filtering (keeps same-repo, drops foreign #24/#102
and non-PR events; foreign-only → 0 candidates) and the REST
author-association spoof-gate (MEMBER accepted, CONTRIBUTOR excluded,
spoof-only reports exclusion). Offline suite: **492 passed / 0 failed**.

Scope check: the sibling Preview engine (`Get-PreviewReadiness.ps1`) has
neither code path, so no change is needed there.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…d newlines + unescaped pipes) (#36031)

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

### Problem

The `[Release Readiness]` tracker issues render markdown tables built
from upstream-controlled content — issue/PR **titles** dropped into
pipe-delimited rows (`| #link | <title> | <…> |`). Several kinds of
malformed (or hostile) title corrupt those rows:

1. **Embedded newlines.** Some `ci-scan` issues have a title containing
a **literal newline** — observed live on issue #35957, whose real GitHub
title spans two physical lines and ends with `(maui-pr-uitest\n[Content
truncated due to length]`. An embedded `\r\n` splits the row across two
physical lines, so the title tail + trailing cells land on a line that
no longer contains the issue link. This was visible on the live
trackers: **net10-sr9 #35867** (2 broken rows) and **net11-preview6
#35866** (3 broken rows).
2. **Unescaped pipes.** A literal `|` in a title (common — e.g. `Fix A |
B`) injects an extra column. The preview engine already escaped pipes
everywhere via its shared `Format-MarkdownCell`, but on the **SR** side
cells were escaped ad-hoc — several embedded titles with **no newline
collapse at all**.
3. **Escape-the-escaper pipe breakout.** A title may legally contain a
literal `\|` (backslash immediately followed by a pipe). Escaping only
the pipe turns that into `\\|`, which GitHub-flavored Markdown renders
as a literal `\` followed by an **active** column delimiter — so the row
still breaks out. Both engines had this latent bug.
4. **Raw `<`/`>` (HTML injection / display loss) on the SR side.** SR
dropped titles in raw, so a title like `Crash <!--` could inject an
HTML-comment opener, and a legitimate `List<T>` (or engine-authored
placeholder text like `Bump <PatchVersion> …`) was silently swallowed by
GitHub as an unknown HTML tag and never displayed.

The ultimate root cause of (1) is upstream (the CI Failure Scanner
producing a multi-line title), but a readiness engine should defensively
sanitize any external content it embeds into its own tables.

### Fix

- **`Get-ReleaseReadiness.ps1`** — introduce a single null-safe
**`Format-MarkdownTableCell`** helper and route **every** SR site that
embeds upstream-controlled text through it. This covers the ci-scan
rows, the **Open PRs Targeting `<srBranch>`**, **regression
classification**, **🔴 Blocking summary**, **🧹 Cleanup**, **📥 Open Fix
PRs Inbound**, and **Ship-readiness checks** tables, **plus the
candidate-PR bulleted list**. The helper:
  - collapses `[\r\n]+` → space (hazard 1),
- escapes each `|` → `\|` and **doubles only the backslash run
immediately preceding that pipe** (via a single `(\\*)\|` regex pass),
so a pre-existing `\|` becomes `\\\|` (renders a literal `\|`, no
breakout — hazards 2 & 3). The doubling is **scoped to pipe-adjacent
runs** rather than every backslash, so a title's other backslash escapes
(`\[link\](url)`, `\*not emphasis\*`) are preserved verbatim and not
de-escaped into active Markdown. No-pipe-adjacent-backslash titles are
unchanged (`a | b` → `a \| b`).
- escapes `<`/`>` → `&lt;`/`&gt;` (hazard 4), **matching the preview
engine** for SR↔Preview parity.
- **`Get-PreviewReadiness.ps1` (`Format-MarkdownCell`)** — the newline
collapse plus the same **pipe-adjacent** backslash handling so the
preview engine is immune to the `\|` breakout too.

**On `<`/`>` escaping (now consistent across both engines):** escaping
angle brackets to entities has **zero visual cost** — `&lt;T&gt;`
renders as `<T>` — so `List<T>` fidelity is preserved while raw HTML
injection is neutralized (`<!--` → `&lt;!--`). It also fixes a latent
display bug: engine-authored `NextAction` text such as `Bump
<PatchVersion> in eng/Versions.props` was previously rendered raw and
**swallowed by GitHub as an unknown HTML tag**, so the Release Captain
saw `Bump in eng/Versions.props`; it now displays correctly. SR is
additionally hash-freeze-immune (it emits its own hash at the **top** of
the body, extracted with `head -n1`) and its human-notes markers are
matched **full-line-anchored**, so escaping `<>` is defense-in-depth
layered on top of those backend invariants rather than the sole
protection. (`.Trim()` only touches leading/trailing whitespace.)

### Tests

Deterministic, offline assertions:

- **`Format-MarkdownTableCell` / `Format-MarkdownCell` unit tests** —
pipe escaping, LF/CRLF-run collapse, newline+pipe together, null/empty →
empty string, whitespace trim; **angle brackets escaped to `&lt;`/`&gt;`
(both engines, parity)**; **literal `\|` does NOT break out** (→ `A \\\|
B`); **non-pipe backslash preserved** (`C:\dir` unchanged) and
**author-escaped non-pipe Markdown not de-escaped** (`\[link\](url)`
unchanged) for both engines; **`<!--` opener neutralized** to `&lt;!--`.
- **SR ci-scan row** — an embedded-newline title renders as a **single**
physical row with its tail + age intact.
- **SR tables (end-to-end `Format-MarkdownReport`)** — a piped+newline
title in the **Open PRs Targeting**, **regression classification**, **🔴
Blocking summary**, **📥 Open Fix PRs Inbound**, and **Ship-readiness
checks** tables each stays on one physical row, pipe escaped, trailing
column intact; the BLOCKED ship-check next-action with `<PatchVersion>`
renders entity-escaped (so GitHub actually displays it).
- **Human-notes marker-forgery regressions (security)** — a title
embedding `…\n<!-- …:human-notes:begin -->\n…` in a **table cell** and
in the **candidate-PR list** must leave **exactly one** anchored
begin-marker in the rendered body (the legitimate one), proving a
hostile title cannot forge a second notes region.
- **Preview engine** — `Format-MarkdownCell` collapses LF/CRLF runs and
preserves the existing pipe / angle-bracket escaping contract.

The discriminating assertions were verified **red on the pre-fix
scripts** and **green after** (and the surgical-scoping assertions were
verified red against the earlier global-doubling commit). Offline suite:
**566 passed / 0 failed**; full E2E: **632 / 0**.

### Scope / follow-ups (intentionally out of this PR)

- Backtick (inline-code) is intentionally **not** escaped: doing so
would degrade the very common legitimate case of code-quoted titles like
`` `CollectionView` ``, and an unescaped backtick is a cosmetic-only,
non-structural concern (it cannot create a new column, inject HTML, or
forge a human-notes marker, all of which require `|`/`<`, which **are**
escaped).
- Null-safety of `.title.Length` under `Set-StrictMode -Version Latest`
is **pre-existing** (titles are non-null by GitHub API contract) and
intentionally deferred to a focused follow-up rather than mixed into
this rendering PR.
- The SR "Reverts" table's "Reverts commit" column shows `?` for every
row (the `This reverts commit <sha>` body-regex never resolves).
Pre-existing and unrelated; noted for a future pass.
- Filing an upstream issue against the CI Failure Scanner for the
malformed (multi-line) titles is worth doing separately so the trackers
receive clean input at the source.

---------

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

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

### Problem

The `/review rerun` scanner never dispatched a single AzDO run in
production. Investigation across recent scheduled runs showed the agent
correctly deciding `decision=trigger` for open PRs, yet **every**
dispatch was aborted. Two independent bugs were responsible:

1. **Only one decision per run was ever processed.** gh-aw custom
safe-output jobs run exactly once per scan. The agent was instructed to
call the `trigger_rerun_review` tool once *per candidate*, so every call
after the first was silently dropped by gh-aw's "max 1 item"
enforcement. Even when several PRs were eligible, at most one reached
the dispatch script.

2. **A false "PR not found" guard cancelled dispatches for open PRs.**
`Test-GhApiPrNotFound` classified any gh error text containing "Not
Found"/"Gone" (e.g. transient proxy/auth bodies) as a deleted PR, so the
script logged `PR #N no longer exists; skipping stale decision` and
bailed — for PRs that are demonstrably open.

### Fix

1. **Batch all decisions into one tool call.** The agent now calls
`trigger_rerun_review` **exactly once per run**, passing a single
`decisions` JSON array with one object per candidate PR.
`Get-AgentItems` expands the array (`Expand-RerunDecisionItems`) into
individual decisions, with back-compat for the legacy scalar shape. This
processes *all* eligible PRs in a scan instead of just one.

> Note: gh-aw v0.77.5 does **not** support `max: N` on a custom
`safe-outputs.jobs.<name>`, so batching into one array-typed input is
the only way to lift the one-per-run cap.

2. **Harden the not-found guard.** `Test-GhApiPrNotFound` now requires
an explicit `HTTP 404`/`410` status. The fetch block logs the raw gh
error and performs a second confirmation probe before skipping — it
fails loud (throws) rather than silently cancelling a dispatch when the
cause is ambiguous.

### Tests

- 32 Pester tests pass (`Invoke-RerunReviewTrigger.Tests.ps1`),
including:
- 5 new tests for batched `decisions` parsing (JSON string array, object
array, multi-item aggregation, legacy scalar pass-through, empty/null
payloads).
- A regression test ensuring bare "Not Found"/"Gone" text without an
HTTP 404/410 status is **not** misclassified.
- `gh aw compile rerun-review-scanner` succeeds (0 errors/warnings); the
regenerated `.lock.yml` is committed and embeds the new `decisions` tool
schema.

### Files

- `.github/scripts/Invoke-RerunReviewTrigger.ps1` — batched decision
expansion + hardened guard + raw-error logging/re-probe.
- `.github/scripts/Invoke-RerunReviewTrigger.Tests.ps1` — new coverage.
- `.github/workflows/rerun-review-scanner.md` — single batched
`decisions` tool schema + updated agent prompt.
- `.github/workflows/rerun-review-scanner.lock.yml` — recompiled.

---------

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

<!-- 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 SR release-readiness tracker overcounts the regressions header when
**exactly one** regression candidate exists. The live `.NET 10 SR9`
tracker ([#35867](#35867)) renders:

```
## Regression Candidates — 13 issues scanned
```

…even though only **one** issue
([#35615](#35615)) was actually
scanned. The summary table, tiers, and verdict all correctly show 1 —
only the header is wrong.

### Root cause

The header is built from `$regs.Count`:

```powershell
$regs = $Data['regressions']
... "## Regression Candidates — $($regs.Count) issues scanned"
```

Regression results are **hashtables**. `Get-RegressionCandidates`
returns its `$results` accumulator, and when exactly one candidate
matches, PowerShell **unwraps the single-element array on return**, so
`$Data['regressions']` arrives as a lone hashtable rather than a
1-element array. `.Count` on a hashtable returns its **key count** (13 —
`createdAt, confidence, milestone, state, closedAt, evidence,
candidateFixPrs, labels, stateReason, classification, recommendedAction,
issue, title`), not 1.

- **N = 0** → `@()` → `.Count` = 0 ✅ (already correct)
- **N = 1** → scalar hashtable → `.Count` = 13 ❌ (this bug)
- **N ≥ 2** → real array → `.Count` = element count ✅ (already correct)

### Fix

Force array context so `.Count` always reflects the candidate count:

```powershell
$regs = @($Data['regressions'])
```

One line. The sibling SR headers (`$blockingItems`, `$cleanupItems`,
`$openFixRows` are all `List[hashtable]`) and the preview engine
(`Get-PreviewReadiness.ps1`, which uses `List`/`@()`-wrapped
collections) are **not** affected — this is the only header fed the raw
`regressions` value.

### Tests

Added a **discriminating** regression test in
`Test-ReleaseReadiness.ps1` that reproduces the production unwrap by
assigning the regression result as a **scalar hashtable** (not `@(...)`,
which would mask the bug) and asserts the header reports `1 issues
scanned`, plus an N=2 guard for the already-correct path. A precondition
assertion locks in that the value is a scalar hashtable so a future edit
can't silently neuter the test.

- ✅ Verified the new test **fails pre-fix** (renders the key count) and
**passes post-fix**.
- ✅ Offline suite: **569 passed / 0 failed**.
- ℹ️ Full E2E: 627 passed / 3 failed — the 3 failures are
**pre-existing** (live-`gh` E2E tests: `sr-source-prs.txt`, candidate
JSON, `-InheritFromPriorSr` validation), reproduced identically on
pristine `main` (624/3) and unrelated to this change. They pass in CI's
`release-readiness.yml` Validate job, which has a proper `gh` token.

### Scope

Separate, focused follow-up off `main` — unrelated to the table-escaping
fix in #36031 (already merged). No behavior change beyond the header
count.

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

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

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

## 14.13.1

### What's Changed
- Fixed loading of animated AVIF image as MagickImageCollection (#​2000)
- Fixed determining the number of frames when reading animated AVIF
images (#​2005)
- Fixed loaded of indexed color PSD file (#​2007)
- Another fix when reading JPEG compressed TIFF files. (#​2016)

### Related changes in ImageMagick since the last release of Magick.NET:
- Stack overflow in fx operation
(GHSA-rcr6-g7jc-f57g)
- Heap Buffer Over-Write of a single byte in the JP2 encoder
(GHSA-533m-3wf6-c33v)
- Use-After-Free in MSL decoder
(GHSA-5r4x-w6p5-222q)
- Infinite Loop in the MIFF decoder can lead to CPU exhaustion
(GHSA-7gg8-qqx7-92g5)
- Heap Buffer Over-Write in IPL decoder when reading multiple images of
different dimensions
(GHSA-36wm-hprc-mcf5)
- Heap Buffer Over-Write in MIFF encoder when using LZMA compression
(GHSA-jcqp-6r6f-3mfx)

### Library updates:
- ImageMagick 7.1.2-23 (2026-05-17)
- aom 3.14.0 (2026-05-12)
- openexr 3.4.11 (2026-04-30)
- libhwy 1.4.0 (2026-04-23)
- lcms 2.19.1 (2026-05-06)
- openjph 0.27.3 (2026-05-14)

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

## 14.13.0

### What's Changed
- Added `PixelDifferenceCount` to `ErrorMetric`.

### Related changes in ImageMagick since the last release of Magick.NET:
- Corrected the patch that was made earlier to fix reading JPEG
compressed TIFF images (#​1993)
- Call CloseBlob on the correct image to prevent the blob from remaining
open (#​1997)

### Library updates:
- ImageMagick 7.1.2-21 (2026-04-21)
- harfbuzz 14.2.0 (2026-04-20)
- libpng 1.6.58 (2026-04-15)
- libraqm 0.10.5 (2026-04-11)
- libraw 0.22.1 (2026-04-06)
- libxml2 2.15.3 (2026-04-15)
- openexr 3.4.9 (2026-04-17)
- openjph 0.27.0 (2026-04-14)

**Full Changelog**:
dlemstra/Magick.NET@14.12.0...14.13.0

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

[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=Magick.NET-Q8-AnyCPU&package-manager=nuget&previous-version=14.12.0&new-version=14.13.1)](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>
…#35927)

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

Two new agentic workflows that walk open CI-failure tracking issues
filed by the existing scanners and open draft `[ci-fix]` PRs against the
matching branch:

- `.github/workflows/ci-status-fix.md` — processes `[ci-scan]` issues,
opens PRs against **`main`**.
- `.github/workflows/ci-status-fix-net11.md` — processes
`[ci-scan-net11]` issues, opens PRs against **`net11.0`**.

They are the natural counterpart to the existing `ci-status-main.md` /
`ci-status-net11.md` detection workflows: one pair identifies, the other
proposes a fix. **No KBE / Build Analysis integration** — just identify
→ auto-fix PR, as requested.

Also includes two small, surgical prompt edits to both scanner files so
the fixers can trust what they emit.

## Why two workflows instead of one

The fixer logic is identical for both branches; the split is forced by a
gh-aw transport constraint, not by behavior.

gh-aw always generates a "transport patch" for its `create-pull-request`
safe-output **relative to a single static `base-branch`**, and
`max-patch-size` is hard-capped at **10 MB** by the gh-aw schema
(raising it past 10 MB is a compile error). The `main` ↔ `net11.0`
divergence is ~22 MB / ~1,000 files, so a one-file `net11.0` fix built
against a `main` base produces a ~22 MB transport patch and is
unconditionally rejected (file-count guard, then size).

Because `base-branch` is one static value per workflow, each base needs
its own workflow. With `base-branch: net11.0`, gh-aw builds the
transport patch relative to `net11.0`, so the patch is just the fix's
own delta. This was validated live (see below): the net11.0 fixer opened
a clean **1-file** draft PR against `net11.0`.

## Design highlights

**Each workflow is hard-pinned to exactly one base branch, enforced at
three layers.**

1. **gh-aw declarative gate**:
`safe-outputs.create-pull-request.base-branch` pins the base (`main` /
`net11.0`), and `allowed-base-branches` (`[main]` / `[net11.0]`) makes
gh-aw reject any other base.
2. **Prompt rule**: the agent only processes the matching label
(`ci-scan` / `ci-scan-net11`) and checks out `origin/<branch>` (Step
5.2) before authoring, so the transport patch and the downstream push
are both exactly the one-file fix delta.
3. **Self-check before emission**: the agent greps its own PR body for
`Target branch: <branch>` and confirms `base` matches; mismatch aborts.

**Iterative, capped at 5 attempts per tracking issue.** Attempt count
comes from a live GitHub PR search for `"Refs: dotnet/maui#<N>"` in
closed-unmerged `[ci-fix]` PRs (GitHub is the durable store — no per-run
state needed). After the 5th closed-unmerged attempt the workflow stops
and defers to humans (the open tracking issue is the hand-off surface).
A dedicated `[ci-fix][needs-human]` hand-off PR is planned but
**currently deferred** (Step 6 records a skip and emits no PR). Each
attempt reads prior closed PRs' approaches and close comments and must
propose a substantively different approach.

**"Is it actually fixed?" check.** Before any fix attempt, the agent
fetches the latest completed build of the failing pipeline on the target
branch and `grep -F`s the issue's failure signature against the leaf-log
output. Zero hits → silently skips ("appears fixed in latest build").
Tracking issue closure stays a human decision.

**De-flake capability for intermittent test failures.** A flakiness
probe classifies a reproducing failure as (a) infra → skip, (b)
test-quality → de-flake PR, or (c) product-masking → product fix /
hand-off. A de-flake replaces sleeps/races with condition waits and
tightened assertions; it **never** adds `[Ignore]` / `[Retry]`, weakens
assertions, or bumps timeouts.

**Visual-regression filter is the first gate.** Silently skips any issue
whose title, body, error message, or failed task names match
`screenshot` / `snapshot` / `visual diff` / `baseline image` /
`VerifyScreenshot` / etc. gh-aw can't judge visual diffs and must never
modify baseline images.

**Never mutes a test.** Stages with `[ActiveIssue]`, `Skip = "..."`,
`[SkipOnPlatform]`, csproj `<*Incompatible>` / `<ExcludeFromTestRun>`,
or edits to baseline images under `TestAssets` / `Snapshots` /
`Baselines` are detected and rejected. If the only candidate fix is a
mute, the run records a skip and stops.

**MAUI area bounds.** Compile / XAML breaks are in bounds (≤ 20 lines,
single file when possible). Device-test and UI-test failures (past the
visual-regression gate) become `help`-only PRs or de-flakes. Handler
lifecycle, threading, safe-area, perf hot-paths, Gradle/Maven feed, and
infra failures are skipped — too risky for an autonomous fix.

**Outputs only via `safe-outputs`.** Tracking issues are locked so no
comments are possible. `draft: true`, `max: 3` PRs per run,
`environment: gh-aw-agents` gating on the write-capable job,
`allowed-files` restricts to `src/Core/**`, `src/Controls/**`,
`src/Essentials/**`, `src/BlazorWebView/**`, `src/TestUtils/**`,
`src/Templates/**`, `**/PublicAPI.Unshipped.txt` (which already excludes
`.github/**`).

## Validated live

The net11.0 workflow was run end-to-end against a real `[ci-scan-net11]`
issue (#35981, a flaky `DropEventCoordinates` iOS 18.5 drag-and-drop
test). It opened draft PR **#36027** targeting `net11.0` with a clean
**1-file** de-flake (reset-between-retries + a tightened
positive-coordinate assertion; no banned mute/retry patterns) and
correct body markers (`Refs`, `Target branch: net11.0`, `Attempt 1/5`,
`Flake class: test-quality`). #36027 is left open as a genuine candidate
fix for maintainers to review — it proves the `base-branch: net11.0`
split produces a small, in-cap transport patch.

## Two small scanner edits (so the fixers can rely on what they emit)

Both `ci-status-main.md` and `ci-status-net11.md`:

1. **Mandatory `Build ID: <integer>` line** in the issue body template.
The fixer requires it as a field gate (skipping any issue missing it)
and cites it as the *original failing build* in its PR audit trail; the
existing `Build: <URL>` line is opaque to grep. (The reproduce-check
itself re-fetches the *latest* build of the pipeline.)
2. **Match-count gate** requiring the scanner to verify its own primary
error substring actually appears in the fetched failure log before
filing, and embed the result as a second hidden marker:
   ```
   <!-- ci-scan-match-count: N hits in failure.log -->
   ```
Issues with 0 matches are not filed. This blocks hallucinated signatures
from ever entering the fixers' work lists. The substring is treated as
untrusted data — it is written to a pattern file via a fresh per-run
random-delimiter single-quoted heredoc and matched with `grep -F -f`
(never interpolated into a shell command), mirroring the injection-proof
pattern the fixers use.

## Lifecycle and stop conditions

| State | Action |
|---|---|
| Open `[ci-fix]` PR already exists for the issue | Skip — human owns
the PR |
| Merged `[ci-fix]` PR exists | Skip — fix already landed |
| Open human PR (non-`agentic-workflows` label) references the issue |
Skip — human is on it |
| `attempt_count < 5` and signature still reproduces | Open attempt N+1
|
| `attempt_count >= 5` | Stop and defer to humans; never retry
(dedicated `[ci-fix][needs-human]` PR deferred — see Step 6) |
| `attempt_count` search inconclusive (API error / `incomplete_results`)
| Skip — cannot safely confirm the cap |
| Latest build no longer reproduces the signature | Skip — "appears
fixed" |
| Issue body missing required fields (`Build ID`, fingerprint, error
block) | Skip — scanner needs prompt update |
| Only candidate fix is a mute | Skip |
| Only candidate fix modifies visual baselines | Skip |
| No novel approach producible vs prior attempts | Skip — defer to next
tick |

## Files

- **NEW**: `.github/workflows/ci-status-fix.md` — main-branch fixer
(`base-branch: main`)
- **NEW**: `.github/workflows/ci-status-fix.lock.yml` — generated by `gh
aw compile`
- **NEW**: `.github/workflows/ci-status-fix-net11.md` — net11.0-branch
fixer (`base-branch: net11.0`)
- **NEW**: `.github/workflows/ci-status-fix-net11.lock.yml` — generated
by `gh aw compile`
- **EDIT**: `.github/workflows/ci-status-main.md` — `Build ID` line +
match-count gate
- **EDIT**: `.github/workflows/ci-status-net11.md` — `Build ID` line +
match-count gate

`gh aw compile` passes cleanly on both new workflows (0 errors, 0
warnings).

## Things this PR explicitly does NOT do

- Does **not** integrate Build Analysis / KBE in any form.
- Does **not** add a feedback / KPI workflow (could be a follow-up if
maintainers want one — the marker blocks in PR bodies are designed to
make it easy).
- Does **not** read PR review comments as instructions — the integrity
gate filters them and the agent never treats them as authoring input.
- Does **not** close tracking issues — closure stays a human decision.
- Does **not** modify any production source code in this PR;
workflow-only change.

---------

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

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

Each `[Release Readiness]` tracker now opens with a **nightly dogfood
feed freshness banner** for that release's lane, so a release captain
can tell at a glance whether dogfooders are validating *current* bits or
testing stale builds. A fresh nightly is expected daily; when one stops
appearing, the tracker should say so loudly.

This is internal release-readiness tooling
(`.github/skills/release-readiness/`) — no product/runtime code changes.

### What it looks like

- ✅ fresh (`< 3` days): `**Nightly dogfood feed:** ✅ \`dotnet11\` (net11
preview) — latest \`11.0.0-preview.6.26322.3\` built today.`
- ⚠️ aging (`3–6` days): blockquote with age + publish date.
- ❌ stale (`≥ 7` days): blockquote alarm — e.g. (live, SR8 band today):
`❌ Nightly dogfood feed is STALE — 11 days … Latest build
\`10.0.80-ci.main.26310.5\` published 2026-06-11 … builds appear to have
stopped`.
- Muted one-liners for *unknown* (feed query failed) and *no matching
build* (band naming changed) — never a false alarm.

### How it works

- **New shared helper `scripts/NightlyFeed.ps1`** (single source,
dot-sourced by both engines + the test harness):
- `Get-NightlyFeedFreshness` — queries the lane's Azure Artifacts feed
(`dotnet10`, `dotnet11`, …) and returns the newest build whose version
matches a **band prefix**, selected by `catalogEntry.published`. The
feed orders versions by *version number, not date*, and mixes build
families on one feed, so freshness **must** come from publish timestamps
scoped by a version band. The network call is **fail-open** (any error →
`$null`) and takes an injectable `-Fetcher` so it's fully unit-tested
offline.
- `Format-NightlyFeedBanner` — **pure, deterministic** renderer (caller
passes `-Now`); tiers fresh/aging/stale + muted unknown/no-match.
Thresholds are parameters (default 3/7 days).
- **SR engine** (`Get-ReleaseReadiness.ps1`): on full (`all`) runs, maps
the SR lane to `dotnet<Major>` + the `<Major>.0.<Patch>` band —
in-flight SR → the SR branch's band; candidate → main's band — queries
freshness, and renders the banner under the **Generated** line.
Band-**number** matching is deliberate: it's resilient to family-keyword
churn (an SR8 `.80` build is tagged `ci.main`, *not* `ci.inflight`, so a
keyword match would miss it).
- **Preview engine** (`Get-PreviewReadiness.ps1`): maps the preview to
`dotnet<Major>` + the `<Major>.0.0-preview.<N>` band (iteration read
from `Versions.props` at the survey ref), renders the banner under
**Overall status**.
- **Defensive load**: both engines dot-source the helper guarded by
`Test-Path` + `Get-Command`; a missing/unloadable helper degrades to *no
banner* rather than crashing the unattended nightly tracker job. The
freshness query is wrapped in try/catch and gated to non-test code
paths, so existing E2E tests stay network-free.

### Testing

- **26 new offline assertions** for the helper: banner tiers, `unknown`
/ `matched=$false`, future-publish clamp, custom thresholds,
deterministic publish date; and `Get-NightlyFeedFreshness` with a mocked
`-Fetcher` covering newest-by-date (not version) selection, band-prefix
filtering, fail-open on throw, and paged-registration `@id` follow-up.
Plus SR render-path wiring assertions (banner appears after
**Generated**; absent when the key isn't set).
- **Offline suite: 592/0.**
- **Live validation** against the real feeds (2026-06-22): `dotnet10
^10.0.90-` → fresh today; `dotnet10 ^10.0.80-` → STALE 11d; `dotnet11
^11.0.0-preview.` → fresh today.
- Full suite is 602 passed / **2 pre-existing env-specific failures** in
the *unmodified* `Find-ReleaseReadinessTrackers.ps1` E2E (its git-root
guard fail-closes when run from a `/tmp` worktree without `-Repo`);
identical on baseline, unrelated to this change.

### Follow-ups (out of scope)

- The companion `Nightly-Builds` wiki page is stale (mislabels which
branch feeds `dotnet9`/`dotnet10`, missing `dotnet11`); a corrected
draft is being reviewed separately.

---------

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

Updates `eng/scripts/get-maui-pr.sh` and `eng/scripts/get-maui-pr.ps1`
so users can still apply PR package artifacts when the aggregate
`maui-pr` build is red because of unrelated CI legs, as long as the
package-producing artifacts exist for the current PR commit.

### Changes

- Treat a red aggregate `maui-pr` build as a warning instead of an
immediate abort.
- Keep `PackageArtifacts` as the hard gate before downloading/applying
packages.
- Filter AzDO fallback builds to the current PR head/merge context using
`triggerInfo.pr.sourceSha`, `sourceVersion`, and the PR merge SHA.
- Warn when `Pack macOS` or `Pack Windows` timeline records do not
report success.
- Update troubleshooting text to refer to completed `maui-pr` builds
with `PackageArtifacts` rather than green checks.

### Validation

- `bash -n eng/scripts/get-maui-pr.sh`
- PowerShell parser validation for `eng/scripts/get-maui-pr.ps1`
- `git diff --check`
- Local throwaway MAUI projects under
`/Volumes/NieuwVolume/maui-pr-artifact-verification-20260616101523`:
- PR `#35805`: red aggregate build `1461390`, `PackageArtifacts`
present, pack jobs succeeded; Bash and PowerShell scripts applied
package `10.0.80-ci.pr35805.26312.37`; `dotnet restore` succeeded.
- PR `#35923`: green aggregate build path applied package
`10.0.80-ci.pr35923.26315.57`; `dotnet restore` succeeded.
- PR `#35626`: missing `PackageArtifacts` failed before mutating the
project.
  - PR `#999999`: nonexistent PR failed cleanly during PR lookup.
- Wrong-SHA harness for PR `#35805`: refused to use older completed
builds when none matched the requested head/merge commit.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… VS Live Property Explorer (#36063)

### Issue details:
After PR #33584 (BindableObject property access micro-optimizations),
Visual Studio's Live Property Explorer stops showing any property values
for MAUI controls. The feature becomes completely blank.
 
### Description of changes:
PR #33584 removed GetLocalValueEnumerator(), LocalValueEnumerator, and
LocalValueEntry from BindableObject as "unused dead code" — a grep of
the MAUI codebase confirmed zero internal callers. However, Visual
Studio's Live Property Explorer calls GetLocalValueEnumerator() via
reflection at runtime to enumerate locally-set bindable property values
on live objects. With these types removed, the reflection call fails
silently and the panel shows nothing.
 
This changes restores all three types, adapted to the new
Dictionary<int, BindablePropertyContext> storage introduced by #33584 —
the enumerator now iterates .Values (the BindablePropertyContext objects
directly) and reads context.Property to expose the BindableProperty,
since the dictionary key is now an int rather than the property itself.

**Tested the behavior in the following platforms.**
- [ ] Android
- [x] Windows
- [ ] iOS
- [ ] Mac

| Before  | After  |
|---------|--------|
| **Windows**<br> <video
src="https://github.com/user-attachments/assets/df3a3448-c79c-4457-8901-f2a075087df4"
width="300" height="600"> | **Windows**<br> <video
src="https://github.com/user-attachments/assets/2dcbdb35-2336-44bd-9c8b-baf1f9b64b4a"
width="300" height="600"> |

---------

Co-authored-by: Gerald Versluis <gerald.versluis@microsoft.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!

### Description of Change

Adds a guide for Microsoft maintainers and community contributors
explaining the automated PR review workflow:

- `/review`
- `/review <platform>`
- `/review rerun`
- `/review tests`

The guide also explains the `maui-copilot` pipeline flow, AI Summary and
Test Failure Review comments, local `/review tests` usage,
troubleshooting, and related implementation files.

### Companion review-output changes

Beyond the documentation, this PR also refines the review-comment output
to keep it consistent with the guide and with the project's
review-symbol conventions:

- **`Find-RegressionRisks.ps1`** — distinct colorless severity glyphs in
the regression markdown (`✗` REVERT / `⚠` OVERLAP / `●` CLEAN).
- **`post-ai-summary-comment.ps1`** — `Test-PhaseContentIsNoOp`
recognizes the `●` (and legacy `🟢`) regression no-op markers so empty
sections stay suppressed; **Next Steps** renders below **Review
Sessions**.
- **`post-inline-review.ps1`** — inline-comment marker uses a generic
`(multi-model)` label instead of a hardcoded model roster.
- **`pr-preflight.md`** — review-symbol set aligned (`✗`/`⚠`/`ℹ`).

Producer/consumer pairs (e.g. the regression no-op markers) are kept in
lock-step and covered by `Post-AISummaryComment.Tests.ps1`.

### Issues Fixed

No issue filed.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: kubaflo <kubaflo@users.noreply.github.com>
…plementing AzDO (#36080)

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

## Problem

The `/review rerun` scanner (`rerun-review-scanner`) dispatched **zero**
AzDO reviews after #35955, and the few it should dispatch would target
the wrong branch. Two independent bugs:

### Bug 1 — every dispatch aborted with a spurious 404

In the **gh-aw safe-output job**, the `gh` CLI returns `HTTP 404` for
`repos/dotnet/maui/pulls/N` — even with `pull-requests: write` on a
public repo. #35955 misread these as transient and "hardened" the
not-found guard, so it now faithfully *confirms* the bogus 404 and skips
every PR. Evidence it is not a permission/token problem: the
`pre_activation` job (only `Metadata: read`) reads the same PRs fine,
and the built-in `safe_outputs` job (octokit) succeeds in the same run.

### Bug 2 — custom review branches silently downgraded to `main`

The candidate builder decided whose `/review -b <branch> -p <platform>`
to trust using the comment's `author_association`. Under the Actions
`GITHUB_TOKEN`, a maintainer whose org membership is private reads as
`CONTRIBUTOR` (not `MEMBER`), so their command was dropped and the rerun
fell back to the `main` pipeline. A live scan confirmed it dispatched
four net11 (`feature/enhanced-reviewer`) PRs on `main`.

## Fix — do exactly what a maintainer `/review` does

**Bug 1:** instead of re-implementing PR validation + OIDC + the AzDO
trigger inside the safe job, the scanner now **dispatches the same
`review-trigger.yml` workflow `/review` runs**, via `workflow_dispatch`.
That workflow owns PR validation, the `s/agent-review-in-progress` lock,
platform inference, OIDC, and the AzDO trigger. (`workflow_dispatch` via
`GITHUB_TOKEN` always creates a run — it is exempt from Actions
recursion-prevention.)

- `Invoke-RerunReviewTrigger.ps1` is now pure: validate batched
`decisions` against `candidates.json`, emit `actions.json`. No
`gh`/AzDO/OIDC/lock/rate-limit I/O.
- A `github-script` (octokit) step performs all GitHub writes — octokit
works in the safe-job context where the `gh` CLI does not. `trigger` →
`createWorkflowDispatch(review-trigger.yml,{pr_number,platform,pipeline_ref})`
+ 👍; `skip` → 👎 + remove the queue label.
- Permissions: `+actions:write`, `−id-token:write`; dropped the
`AZDO_TRIGGER_*` secrets from the job.

**Bug 2:** authorize `/review` options by a **live
collaborator-permission lookup** (`collaborators/<user>/permission` →
write/maintain/admin) — the exact call `review-trigger.yml`'s auth step
makes. It only needs `metadata: read` (every token has it) and reflects
current access. **No new secret or permission.**

- `Resolve-RerunEligibility.ps1`: add `Test-ReviewOptionLoginTrusted`
(cached per login); `Get-LatestReviewCommandOptions` computes trust
through it. Removed the `author_association` gate.
- `Query-RerunReadyPRs.ps1`: drop the `author_association` helpers; pass
`-Owner/-Repo`.

## Validation

- **69 Pester tests pass** (36 dispatch + 33 resolver), incl. a
regression test that an `author_association=NONE` command is still
honored when the login has write access.
- **Live, real (non-dry) scan**: the safe job validated all decisions
with **no 404s** and octokit performed real `createWorkflowDispatch`,
producing two `review-trigger.yml` runs that triggered real AzDO
`maui-copilot` builds (HTTP 200, Run IDs 14459427 & 14459428).
- **Real-data check for Bug 2**: PR #34564's history now resolves to
`pipelineRef=feature/enhanced-reviewer` (author `kubaflo`,
`author_association=CONTRIBUTOR`) instead of `main`, using the live
permission lookup.

## Files

- `.github/scripts/Invoke-RerunReviewTrigger.ps1`,
`.github/scripts/Invoke-RerunReviewTrigger.Tests.ps1`
- `.github/scripts/Resolve-RerunEligibility.ps1`,
`.github/scripts/Resolve-RerunEligibility.Tests.ps1`
- `.github/scripts/Query-RerunReadyPRs.ps1`
- `.github/workflows/rerun-review-scanner.md` + recompiled `.lock.yml`
- `.github/docs/agent-labels.md`

---
🔍 _This PR was created by an AI agent (GitHub Copilot CLI) on behalf of
@kubaflo._

---------

Co-authored-by: kubaflo <kubaflo@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ts doc (#36067)

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

This is a **tooling/agent-infrastructure change only** (everything is
under `.github/` plus the local `/review tests` runner) — no product
source or public API changes.

It converges the automated `/review tests` workflow (the
`review-test-failures` skill) with the interactive
`azdo-build-investigator` skill so that **both deliver the same end
result** — a CI **merge-readiness verdict** plus a **base-branch
baseline failure review** — while removing the duplicated MAUI CI
knowledge that was copy-pasted across several files and at real risk of
drifting.

The two skills can't share *tooling* (the `ci-analysis` plugin that
powers `azdo-build-investigator` is a stdio MCP server, which the gh-aw
runtime can't run), so "minimal duplication" is achieved by sharing
**docs**, not tools.

## Architecture: "shared knowledge, two roles"

One canonical facts doc; every consumer references it instead of
re-stating the facts.

- **New `.github/docs/maui-ci-facts.md`** — single source of truth for
pipeline names/IDs (`maui-pr` 302, `maui-pr-devicetests` 314,
`maui-pr-uitests` 313), AzDO data sources, the XHarness exit-0 blind
spot, test-count deduplication, the **baseline-comparison rule**,
visual-baseline/platform-mismatch guidance, Gradle/CFSClean signatures,
the common-failure-pattern table, and the **merge-readiness criteria**.
Its header lists every consumer, kept bidirectionally accurate.

## What changed

| Area | Change |
| --- | --- |
| `review-test-failures/SKILL.md` | References the facts doc; adds an
**overall merge-readiness verdict** and **baseline reasoning** + an `On
base?` column. |
| `azdo-build-investigator/SKILL.md` | Slimmed (~106→68 lines) to
reference the facts doc; keeps its unique value (ci-analysis-first, the
outdated-`maui-public` correction, escalation to `helix-investigation`).
|
| `Gather-TestFailureContext.ps1` | Extends the deterministic gatherer
with **per-test base-branch baseline extraction + comparison**
(`failures.baseline`, `baselineMatchCount`, `baselineSummary`,
`alsoFailsOnBaseline`). |
| `copilot-review-tests.md` (+ lock) | Output template gains a
**Baseline** badge, an `On base?` column, and merge-readiness
verdict/colors. |
| `Review-Tests.ps1` | Local runner: merge-readiness verdict→color map +
a Baseline badge from `failures.baselineMatchCount`. |
| `ci-status-main.md` / `ci-status-net11.md` (+ locks) | Removed
duplicated pipeline-ID table, "key points" bullets, failure-pattern
table, and dedup prose — now reference the facts doc; added a facts-doc
existence check to the connectivity probe. |

## Validation

- Both PowerShell scripts AST-parse cleanly.
- `gh aw compile` of all three workflows: **0 errors**, and a second
recompile is **idempotent** (no further lock diff) — the compiled
`.lock.yml` files are in sync with their `.md` bodies. (gh-aw
`{{#runtime-import}}`s the body and pins a `body_hash`, so body edits
surface as a hash-only lock diff.)
- Grep sweep confirms **no inline copies** of the canonical
pipeline/failure-pattern tables remain outside the facts doc, and the
facts-doc consumer list exactly matches the set of files that reference
it (bidirectional).

## Intentionally out of scope (follow-up)

A parallel "repo-health" analysis flagged a couple of broader items left
untouched here: the pipeline name→ID table is still duplicated in
`copilot-instructions.md` and `trigger-azdo-pipeline-setup`, and there
are some dead `pr` agent references in `copilot-instructions.md`. Those
are the next concentric ring of cleanup and aren't required for this
convergence.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Reset patterns:
- global.json
- NuGet.config
- eng/Version.Details.xml
- eng/Versions.props
- eng/common/*
Resolve modify/delete conflict on legacy eval.yaml by taking main's
deletion (#35942 migrated skill-eval suite from skill-validator to
Vally; eval.vally.yaml replaces it). All eng/versioning and
auto-generated files retain net11.0 values.

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

Copy link
Copy Markdown
Contributor Author

🚀 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 -- 36139

Or

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

@github-actions

Copy link
Copy Markdown
Contributor Author

Skill Validation Results

@github-actions[bot] — new skill validation results are available based on this last commit: c0dbe05.
To request a fresh validation after new comments or commits, comment /evaluate-skills.

Overall Passed Static Passed LLM Skipped Skills 20 Agents 6

Skill Validation Resultsc0dbe05 · [automated] Merge branch 'main' => 'net11.0' · 2026-06-25T18:29:07Z

✅ Static Checks Passed

Skills: 20 | Eval specs linted: 7

Full lint output
── .github/skills/agentic-labeler/tests/eval.vally.yaml
npm warn deprecated prebuild-install@7.1.3: No longer maintained. Please contact the author of the relevant native addon; alternatives are available.
✔ .github/skills/agentic-labeler/tests/eval.vally.yaml is valid
── .github/skills/code-review/tests/eval.capability.vally.yaml
✔ .github/skills/code-review/tests/eval.capability.vally.yaml is valid
── .github/skills/code-review/tests/eval.vally.yaml
✔ .github/skills/code-review/tests/eval.vally.yaml is valid
── .github/skills/code-review/tests/hermeticity.vally.yaml
✔ .github/skills/code-review/tests/hermeticity.vally.yaml is valid
── .github/skills/evaluate-pr-tests/tests/eval.vally.yaml
✔ .github/skills/evaluate-pr-tests/tests/eval.vally.yaml is valid
── .github/skills/try-fix/tests/eval.vally.yaml
✔ .github/skills/try-fix/tests/eval.vally.yaml is valid
── .github/skills/verify-tests-fail-without-fix/tests/eval.vally.yaml
✔ .github/skills/verify-tests-fail-without-fix/tests/eval.vally.yaml is valid

⏭️ LLM Evaluation: Skipped

💡 LLM evaluation was not run for this external PR.
A repository contributor can post /evaluate-skills on this PR to trigger full evaluation.

🔍 Full results and investigation steps

@PureWeen

Copy link
Copy Markdown
Member

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

@azure-pipelines

Copy link
Copy Markdown
No pipelines are associated with this pull request.

@PureWeen

Copy link
Copy Markdown
Member

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

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 2 pipeline(s).

@PureWeen
PureWeen merged commit 03dd7bd into net11.0 Jun 28, 2026
127 of 151 checks passed
@PureWeen
PureWeen deleted the merge/main-to-net11.0 branch June 28, 2026 15:34
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 29, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants