Revert "Fix SwipeItem IconImageSource color handling and rendering across platforms (#35632)" - #36883
Revert "Fix SwipeItem IconImageSource color handling and rendering across platforms (#35632)"#36883kubaflo wants to merge 43 commits into
Conversation
…scoped event triggers (#36409) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## Why The `[Release Readiness]` tracker issues (SR9 #35867, preview7 #36138, preview6 #35866) were refreshed once per weekday morning, so they drifted stale as the day progressed. This keeps them fresher without spamming watchers, and surfaces staleness explicitly when a body is frozen by the idempotent no-op. ## What **1. Cadence + freshness banner** (`release-readiness.yml`, `NightlyFeed.ps1`, both engines) - Schedule `30 8 * * 1-5` → `30 8-20/3 * * *` (every 3h, 08:30–20:30 UTC, all 7 days). - New pure helper `Format-ReportFreshnessBanner -GeneratedAt -Now [-StaleHours 4]` renders `🕐 Report generated N ago` and appends `⏳ …data may be stale (older than 4h)` past threshold. Fail-open on null/unparseable; clamps clock skew. Wired into both the SR and preview reports. **Derived at render time from the generation timestamp and deliberately excluded from `Get-ReportSemanticHash`** so it never churns the idempotent no-op. **2. Same-tracker writer serialization** (`release-readiness.yml`) - Added a JOB-level `concurrency: group: release-readiness-tracker-${{ matrix.canonicalKey }}` (`cancel-in-progress: false`) on `per-tracker-report`. Same-tracker writers now serialize across ALL event kinds — the old top-level group keyed on `event_name` let two different-event runs race the same `gh issue edit` and clobber Release Captain Notes. Different trackers still run in parallel. - Top-level `cancel-in-progress` → `${{ github.event_name == 'pull_request' }}` (only PR validation cancels; writer runs are never cancelled mid-edit). The existing re-read-live-body-before-edit + malformed-marker skip guards are preserved as defense-in-depth. **3. Scoped base-repo event triggers** (`release-readiness.yml`) - Added `issues` (labeled, closed), `milestone` (created, closed), and `push` (main, net11.0, release/**). **No `pull_request_target`.** - Detect step maps each event to a scope filter (reusing existing BRANCH_FILTER plumbing + new MAJOR_FILTER): push→pushed branch, issues→majors from `regressed-in-<major>*` labels, milestone→major in title, dispatch/schedule unchanged. Untrusted text (label names, milestone/issue titles) flows ONLY via `env:` and is parsed with jq/grep — never interpolated into a `run:` block. Org gate `github.repository == 'dotnet/maui'` prevents fork activation. `issues: write` stays on the writer job only. ## Tests - New hash-stability test: renders the report twice with different `fetchedAt`, asserts the banner text differs but the `release-readiness-hash` marker is identical (proves the banner is not hashed). - 12 new `Format-ReportFreshnessBanner` unit tests (fresh/stale/singular/plural/ISO-string/null/unparseable/clock-skew/custom-threshold). - Full suite green (838/0 in a networked env). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: PureWeen <223556219+Copilot@users.noreply.github.com>
…36410) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## Why The release-readiness regression classifier could report a **CLOSED** issue as an active `open-on-main` regression (Tier 2 — "wait for main merge, then backport"). That's contradictory: an unmerged OPEN PR cannot have closed a completed issue. It happens when a giant still-open "Candidate" changelog PR `Fixes`-lists dozens of issues — its OPEN state gets attributed to an already-completed issue. Real-world: issue #35615 (CLOSED/COMPLETED) surfaced under `open-on-main` in the SR9 tracker while candidate PR #35716 was still open. ## What `Classify-RegressionCandidate` now enforces: **never emit `open-on-main` for a CLOSED issue.** When the aggregated best verdict is exactly `open-on-main` and the issue is CLOSED: 1. First try the same comment-prose recovery the empty-candidate path uses — a merged fix verifiably present on the SR wins → `closed-fix-unlinked` (Tier 3, "no ship risk; add a closing reference for traceability"). 2. Otherwise fall to the honest `no-fix-yet` (Tier 3 for a CLOSED issue via the existing `Get-OverallVerdict` downgrade) — the automation can't pin a verified fix on this SR and the open candidate hasn't merged. The shared recovery logic is extracted into a new `Resolve-ClosedFixUnlinked` helper, called from both the empty-`strongPrs` CLOSED path and the new guard, preserving the fix-phrase gate, merged-on-SR gate, revert guards, and tooling-only skips exactly. **Strictly scoped:** only `open-on-main` + CLOSED is contradictory. Every other verdict (`merged-on-main-no-backport`, `backport-in-progress`, `rejected-from-sr`, `in-sr-*`, `needs-human-review`) is unchanged even for CLOSED issues — those remain legitimately actionable (the SR may still need the backport). Genuinely-OPEN issues still get `open-on-main`. ## Tests Three new unit tests in `Test-ReleaseReadiness.ps1`: 1. CLOSED issue + OPEN candidate on main + no comment fix → `no-fix-yet`, proven non-blocking (🟢) via `Get-OverallVerdict`. 2. CLOSED issue + OPEN candidate + comment-cited merged fix on SR → `closed-fix-unlinked` (recovery wins). 3. Regression guard: OPEN issue + OPEN candidate → stays `open-on-main`. Full suite green (829/0). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: PureWeen <223556219+Copilot@users.noreply.github.com>
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! > [!NOTE] > 🤖 **AI-generated PR.** These workflows, and this description, were produced with AI assistance. Please review carefully before merging. ## Summary Adds two [gh-aw](https://github.com/github/gh-aw) agentic workflows that proactively **find** and **fix** managed, cross-platform memory leaks in MAUI — turning the AI-driven leak-hunting flow several contributors already run by hand (scan → repro → measure → file → fix) into a repeatable, reviewable pipeline. **Design principle: only empirically-proven leaks.** The scanner files an issue **only** when a plain `dotnet test` demonstrates the leak; the fixer opens a PR **only** with a red→green regression test proving the fix. There is no "you're missing a test" / coverage-gap mode — every artifact is backed by a passing/failing test. **Key property:** neither workflow needs an emulator/simulator or a MAUI source build to *detect* a leak — the leak signature is proven by a `dotnet test` against the **shipped `Microsoft.Maui.Controls` NuGet package** on the plain library TFM, so detection runs on a standard GitHub-hosted runner. Only 4 files are added — the workflow source (`.md`) and its compiled artifact (`.lock.yml`) for each: ``` .github/workflows/daily-leak-hunter.md + .lock.yml .github/workflows/leak-fixer.md + .lock.yml ``` --- ## 1. `daily-leak-hunter` — the scanner (files `[leak-scan]` issues) **Trigger:** `schedule: every 12h` + manual (`workflow_dispatch`). Files **only empirically-proven `[leak-scan]` issues** — up to **8 per run**. 1. **Sweeps every focus area** of the managed surface (`src/Core/src`, `src/Controls/src/Core`, `src/Essentials/src`) in one run — it does not stop after the first find. 2. Each focus area is **seeded with proven MAUI leak signatures** (from the community's known-leak catalog) so the hunt targets where leaks actually live: shared publisher → strong `CollectionChanged`/`PropertyChanged` (e.g. `Picker.ItemsSource`, `TableRoot`, `SelectedItems`, `GradientStops`), shared `ICommand` → `CanExecuteChanged` (`ListView.RefreshCommand`, `SwipeItemView.Command`, `BackButtonBehavior.Command`), VSM state triggers → `DeviceDisplay.MainDisplayInfoChanged`, and static/`ResourceDictionary` roots. 3. For each candidate it writes a standalone control / leaky / mitigation xUnit repro (referencing the shipped package, no source build) and measures retention with `WeakReference` + a forced GC. All candidates go in **one test project** (one `[Fact]` each, one restore/run). 4. It files a `[leak-scan]` issue **only for each leak the test confirms** — the leaky scenario retains while **both** the control and the mitigation release. A false positive is treated as worse than a quiet run; unconfirmed candidates are dropped. **If a run proves nothing, it files nothing** (no fallback mode). **De-dup & safety:** skips a leak already covered by one of *its own* open `[leak-scan]` issues; never touches product or test code (read-only + `create-issue`); `noop: report-as-issue: false`. --- ## 2. `leak-fixer` — the fixer (opens draft `[leak-fix]` PRs) **Trigger:** `schedule: every 12h` + manual (`workflow_dispatch`). At most **one action per run**, with de-dup + a 3-attempt cap. It picks the **higher-priority** of two tracks: ### Track C — respond to review feedback (checked first) Before doing new work, it checks whether one of *its own* open `[leak-fix]` PRs (**hosted on this repo** — fork-hosted heads it can't push to are left for a human) has an **unaddressed `CHANGES_REQUESTED` review**. If so it works on that PR: **applies** the valid requested changes (pushes a commit, re-validated so the PR's own test still holds) and/or **posts a comment pushing back** on any request that is wrong, would regress behaviour, or asks for a mute. A loop-guard (act only on a review newer than the PR's last commit *and* the workflow's last comment) prevents re-processing the same review. ### Track A — `[leak-scan]` runtime leak → `[leak-fix]` PR For the selected proven leak it: 1. Writes a focused regression test in `Controls.Core.UnitTests`. 2. Builds MAUI **from source** and confirms the test **FAILS on `main`** — proving it catches the leak. 3. Implements the minimal, idiomatic managed fix — a weak subscription / teardown mirroring the existing `WeakEventManager` / `WeakNotify*Proxy` patterns. 4. Rebuilds and confirms the **same test now PASSES**, no neighbouring regressions. 5. Opens a **draft `[leak-fix]` PR** with `Fixes #N` and the red→green evidence. ### Safety - Enforces red→green **in both directions** — a fix without a demonstrated failing-then-passing test is rejected. - **Never** mutes / skips / disables a test; rejects its own attempt if the only thing that goes green is a mute — **including when a review asks for one** (it pushes back with a comment instead). - **One action per run** — Track C review-response *or* one new Track A `[leak-fix]` PR, never both. - Writes only via scoped safe-outputs (agent job is read-only); PR branches are limited to `leak-fix/**`, changes to managed `src/**` (+ `PublicAPI.Unshipped.txt`). - Skips cleanly if already fixed on `main`, out of scope (needs a device fix), or attempt-capped. --- ## Validated end-to-end on **dotnet/maui itself** (pre-merge) Both workflows were executed on this repo's own Actions infrastructure (via short-lived `push`-triggered test branches, since `workflow_dispatch` only lights up once a workflow is on `main`). Real outputs, all on **dotnet/maui**: - **Multi-leak in one run** — a single hunter run filed **5** distinct proven `[leak-scan]` issues via the catalog-seeded sweep: #36343 `SwipeItemView.Command`, #36344 `ListView.RefreshCommand`, #36345 `Shell BackButtonBehavior.Command` (all `ICommand.CanExecuteChanged`), #36346 `Picker.ItemsSource`, #36347 `IndicatorView.ItemsSource` (`CollectionChanged`). #36344 and #36345 are leaks not previously tracked upstream. - **Proven-only** — a later run filed `[leak-scan]` #36350 `CollectionView.SelectedItems` and (correctly) **nothing else**, having de-duped the already-filed leaks. - **Track A fix** — #36309 `[leak-fix] Fix ResourceDictionary MergedDictionaries memory leak` (regression test red→green + managed fix). - **Track C review-response** — on #36253 the fixer independently re-read the code, agreed with the reviewer's findings, validated the reviewer's `WeakEventManager` approach (24/24, red→green), and posted the concrete fix. --- ## Notes for reviewers - Everything the workflows file/open is **AI-generated** and clearly labelled as such; treat them as high-quality drafts for human review. - The workflows are self-contained (`.md` source + compiled `.lock.yml`); merging them enables the `schedule` triggers on `main`. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Updated [Magick.NET-Q8-AnyCPU](https://github.com/dlemstra/Magick.NET) from 14.13.1 to 14.14.0. <details> <summary>Release notes</summary> _Sourced from [Magick.NET-Q8-AnyCPU's releases](https://github.com/dlemstra/Magick.NET/releases)._ ## 14.14.0 ### What's Changed - Renamed `ExifParts` to `ExifIfds` and renamed `ExifProfile.Parts` to `ExifProfile.AllowedIfds` and mark the old names as obsolete. - Store the exif ifd in the ExifTag to make prevent marking a tag as duplicate when it is found in another ifd (#2017) - Fixed Regression: Clip() doesn't take the correct bounding box (#2019) - Fixed Regression: ColorType is no longer persisted (#2020) - Fixed Native DLLs (Magick.Native-Q16-*.dll) appear at project root in Solution Explorer on .NET Framework 4.8 (#2029) ### Related changes in ImageMagick since the last release of Magick.NET: - Heap Buffer Underwrite in Floyd-Steinberg depth dithering (GHSA-2hhq-c99x-492r) - Stack Overflow in MVG decoder (GHSA-h36c-3666-h489) - Infinite Loop in subimage-search with crafted image (GHSA-5v62-8fq6-cp9m) - Policy Bypass in DCM decoder could result in image with invalid dimensions (GHSA-8pj9-6897-74xc) - Policy Bypass can read disallowed files (GHSA-xcjm-wqff-m669) - Heap Buffer Over-Write in MAT decoder on 32-bit systems (GHSA-4v89-6mgq-6rgc) - Policy Bypass can trigger out-of-Memory condition (GHSA-q62c-h75r-2xhc) - Heap Buffer Over-Write in ICON decoder due to incorrect loop (GHSA-g22q-f7gc-5jhr) - Use-After-Free when allocation in CheckPrimitiveExtent fails (GHSA-px7q-ggqj-hcf2) - Null Pointer Dereference in distort operation when passing incorrect arguments (GHSA-p9rq-q46c-g4x6) - Memory Leak in wand option parser when providing invalid arguments (GHSA-j989-f892-2335) - Heap Buffer Over-Write in SF3 encoder when writing multi-frame image (GHSA-44cp-c3ww-9rv5) ### Library updates: - ImageMagick 7.1.2-25 (2026-06-04) - aom 3.14.1 (2026-05-22) - libde265 1.1.0 (2026-05-26) - openexr 3.4.12 (2026-05-25) - libheif 1.23.0 (2026-05-29) **Full Changelog**: dlemstra/Magick.NET@14.13.1...14.14.0 Commits viewable in [compare view](dlemstra/Magick.NET@14.13.1...14.14.0). </details> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/dotnet/maui/network/alerts). </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…empt human hand-off) (#36317) > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## What this changes Today the `ci-status-fix` agentic workflows (`main` + `net11.0`) open **one** `[ci-fix]` PR per failing-CI tracking issue and then **hand off to a human forever** — nobody re-checks whether the fix actually turned CI green, and if it didn't, the loop never tries again. This PR turns them into a **self-watching loop**: on each scheduled poll the workflow re-reads the CI of the PR it already opened, and — when the failure is caused by its own fix — pushes a **fresh follow-up commit onto the same PR**, up to **10 attempts**, with **no human intervention between attempts**. It stays **one PR per issue, forever** (never a second PR), and stops + hands off to humans only after 10 attempts. Round 1 keeps a human in the loop for exactly one thing: typing `/azp run maui-pr` to kick CI on each new commit (a `GITHUB_TOKEN` push doesn't fire CI). Everything else — watch, classify, re-fix — is autonomous. Auto-CI-triggering is deferred to Phase 2 (see the `GH_AW_CI_TRIGGER_TOKEN` note under **Validation & operation**). The loop also **responds to maintainer review feedback** (Track C): when a human maintainer (OWNER/MEMBER/COLLABORATOR relationship) formally requests changes on the open PR, it applies the valid findings and pushes back on the rest — one push + one comment — rather than sitting idle waiting for a human to also make the edit. ## How it works ```mermaid flowchart TD A[Scheduled poll every 12h] --> B[pre_activation job:<br/>Query-CiFixPRs.ps1 prefetch] B --> C{Open ci-fix PR<br/>for this issue?} C -- No --> D[FRESH: open ONE draft PR<br/>seed marker 1/10] C -- Yes --> E{Watch state machine} E -- Maintainer (OWNER/MEMBER/<br/>COLLABORATOR) requested changes<br/>gate 0, highest priority --> M[Track C: apply valid findings,<br/>push back on rest —<br/>one push + comment] E -- Human commented / pushed / reviewed --> F[Skip — defer to human] E -- CI still pending --> G[Wait, re-check next poll] E -- CI green --> H[Surface + comment, don't advance] E -- CI red --> I{Classify red on<br/>the PR's OWN build} I -- Unrelated flake --> J[Annotate + comment,<br/>don't burn an attempt] I -- Caused by the fix & attempt < 10 --> K[ADVANCE: push follow-up commit<br/>to SAME branch, bump marker N+1/10] I -- attempt = 10 --> L[Hand off: needs-human] ``` ### 1. Deterministic prefetch — `.github/scripts/Query-CiFixPRs.ps1` (new) Runs in a pre-agent `pre_activation` job (not by the model), so it never executes PR-controlled code. It lists open `ci-fix/**` PRs and emits JSON per PR: number, head ref/SHA, `refsIssue`, `isDraft`, settled/overall CI conclusion, per-leg failures, a `humanEngaged` flag (reviews/comments/non-bot pushes), and the parsed `<!-- ci-fix-attempts: N/10 -->` marker. The agent consumes this via `needs.pre_activation.outputs.ci_fix_candidates` — no blind re-querying. ### 2. Attempt counter = a body marker Each PR body carries `<!-- ci-fix-attempts: N/10 -->`. FRESH seeds `1/10`; every ADVANCE bumps it via `update-pull-request`. If the marker is ever missing, the agent reconstructs the count from the bot commits already on the branch. ### 3. Keep-ONE-PR advance (`push-to-pull-request-branch`) When a red build is classified as caused by the fix, the agent checks out the **existing** PR branch at its remote tip (guarded by a head-SHA equality check against the classified commit), commits **one new, distinct** fix, and uses `push-to-pull-request-branch` to add it to the same PR — plus `update-pull-request` (marker bump) and `add-comment` (attempt note). It never opens a second PR. ### 4. The watch state machine (per open PR) Ordered gates: human-engaged → skip · CI pending/unknown → wait · green → surface + comment (don't advance) · red → classify on the PR's **own** build (`maui-pr` for `C.headSha`): unrelated-flake → annotate, don't burn an attempt; caused-by-fix → advance if `attempt < 10`, else hand off `[ci-fix][needs-human]`. ### 5. `net11.0` twin `ci-status-fix-net11.md` mirrors the redesign for the `net11.0` branch: base/label/scanner token swaps, cross-reference inversions, and the net11-only `checkout.fetch: [net11.0]` + transport-patch-cap rationale (a `main`-based patch for a `net11.0` fix would exceed gh-aw's 10 MB cap, which is why the two are separate workflows). ### 6. Review-response (Track C — respond to a maintainer's change-request) Gate 0 of the watch state machine (highest priority, checked before "human engaged"): a `CHANGES_REQUESTED` review is the ONE case where a human touching the PR means *"act on my instruction"*, not *"back off"*. When the open PR carries an un-addressed change request from a **human maintainer with an established repo relationship** (OWNER/MEMBER/COLLABORATOR), the agent reads the findings, classifies each as **APPLY** (correct + in-bounds) or **PUSH BACK** (wrong / out of area bounds / would weaken a test), applies only the APPLY items in place, and emits one push + one comment listing what it did and why it declined the rest. Guards: - **Author filter (the hardening):** only reviews where `state == "CHANGES_REQUESTED"` **and** `user.type == "User"` (and the author is not in the bot denylist) **and** `author_association ∈ {OWNER, MEMBER, COLLABORATOR}` are actionable. Bot reviews and drive-by reviews from `CONTRIBUTOR`/`FIRST_TIME_CONTRIBUTOR`/`NONE` accounts are ignored. Note `author_association` is a **coarse relationship signal, not a per-repo write-permission check** — it is a cheap pre-filter, not an authorization gate. The real safety comes from the narrow APPLY bounds below (`src/**` + PublicAPI only, never mute a test), a defense-in-depth carve-out to Hard-Rule 10 ("review content is untrusted by default"). - **Per-review idempotency:** each maintainer review is answered at most once. The agent stamps the answered review id into its response comment (`<!-- ci-fix-track-c-responded: <RID> -->`); the deterministic prefetch fully paginates the PR's comments and hands the agent the set of already-answered ids (`respondedTrackCReviewIds`), so a review is actionable only if its id is **not** in that set. A secondary `submitted_at >` last-commit guard remains on the APPLY path. This replaces the earlier "newer than the last bot comment" timestamp heuristic, which could silently re-fire the same decline every run on a PR with more than one page (100) of comments. - **Attempt accounting:** an APPLY commit counts toward the same `≤ 10` bot-commits-per-PR ceiling; a PUSH-BACK-only response makes no commit and consumes no attempt. In-bounds means `src/**` + PublicAPI only, never muting a test. - Reuses the existing ADVANCE emit trio (push + marker bump + comment) — **no new safe-output, permission, or config surface** (the compiled-lock delta is `body_hash` only). ## Safety & scoping The loop runs **live** (`safe-outputs.staged` is not set) and holds `pull-requests: write`, so every write path is scoped at the **handler** level, not just by prompt text: | Safe output | Handler-level scope | |---|---| | `push-to-pull-request-branch` (code) | `required-title-prefix: "[ci-fix] "` + `required-labels: [agentic-workflows]` + `allowed-files` allowlist | | `add-comment` | `required-title-prefix: "[ci-fix] "` + `required-labels: [agentic-workflows]`, `discussions: false` | | `update-pull-request` | `title: false` → `allow_title:false` (no retitles); body-marker edits only | | `create-pull-request` | `[ci-fix]` title prefix + `agentic-workflows` label; `allow-empty` intentionally unset | - **Reads / triggers are integrity-gated** — `min-integrity: approved` filters PR/issue content to trusted authors (OWNER/MEMBER/COLLABORATOR) before the agent ever sees it. - **Review-response is relationship-gated (Track C):** the sole path that treats review *content* as an instruction requires a `CHANGES_REQUESTED` review from a human (`user.type == "User"`, not in the bot denylist) whose `author_association ∈ {OWNER, MEMBER, COLLABORATOR}` — a coarse relationship pre-filter, **not** a per-repo write-permission check — and even then may only touch `src/**` + PublicAPI and may never mute a test. Bot and outside/first-time-contributor reviews stay non-actionable. - **`update-pull-request` caveat (documented inline in both twins):** gh-aw v0.79.8's compiler silently drops `required-title-prefix`/`required-labels` from *this one* handler — verified against the compiled `.lock.yml`, unlike `add-comment` / `push-to-pull-request-branch` which do emit them. So it can't be prefix-locked the same way; we remove the sharpest capability instead (`title: false`), leaving only body-marker edits on an already `min-integrity:approved` target. - **Keep-ONE-PR / no duplicates:** `create-pull-request` does not set `allow-empty`, and the fixer dedups by `Refs: dotnet/maui#<N>` + issue number (the `ci-scan-fingerprint` marker is *optional* and never the dedup key), so a re-poll advances the existing branch instead of spawning a second — or empty — PR. - **No cost guardrail:** `max-ai-credits` / `max-daily-ai-credits` are `-1` (unlimited). A live auto-fixer must not silently stall mid-loop on a budget cap — a deliberate maintainer trade-off, not an oversight. ## Validation & operation (round 1) 1. **Scoped dispatch:** Actions → "CI Failure Fixer (main)" → Run workflow → `issue_number` (e.g. `36180`) drives one issue; empty runs the full scheduled sweep. A `dry_run` input gives a live-but-write-free canary. 2. **Exercise the commit:** when the loop pushes, a maintainer types `/azp run maui-pr` (+ the gated `maui-pr-uitests` / `maui-pr-devicetests` legs when relevant). A bare `/azp run` does **not** count as human engagement, so the loop keeps watching. 3. **Open item — `GH_AW_CI_TRIGGER_TOKEN`:** a bot `push-to-pull-request-branch` uses `GITHUB_TOKEN`, which does **not** re-fire the AzDO `maui-pr` webhook build — that's why the manual `/azp run` exists in round 1. A provisioned PAT/OIDC trigger token (Phase 2) would remove that human step; **until then the token is a harmless no-op** and the `/azp run` step is the expected round-1 behavior. ## Files | File | Change | |------|--------| | `.github/scripts/Query-CiFixPRs.ps1` | **new** — deterministic prefetch | | `.github/workflows/ci-status-fix.md` (+`.lock.yml`) | keep-one loop + watch state machine + Track C review-response + scoped safe-outputs | | `.github/workflows/ci-status-fix-net11.md` (+`.lock.yml`) | net11.0 mirror | Both `.lock.yml` were recompiled in the same commit as their `.md` source (per pipeline security rules). No `cgmanifest.json` / `templatestrings.json` changes. --------- Co-authored-by: PureWeen <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ption-wiring & feed-drift checks (evolve #36268) (#36213) <!-- 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 Makes the local ask **"run release readiness skill to see if net11 preview6 is ready"** consult the *authoritative* official-preview build **and** verify the preview branch is actually ship-wired — not just public CI/regression health. Three files: **1. `release-readiness/SKILL.md` — net-new bridge (the star of this PR).** A new **Preview: authoritative blessed-build source** subsection so the `release-readiness` skill, after its public survey, runs the access gate and — when the caller has access **and** the plugin is enabled — invokes the private **`dotnet-release-tracker`** plugin for the blessed build / BAR id + stage, then combines that with the CI/regression verdict. It branches on the gate token (`AVAILABLE_ENABLED` → use the plugin; `AVAILABLE_NOT_ENABLED` → offer the opt-in; `ACCESS_ON_INACTIVE_ACCOUNT` → advise an account switch; `NO_ACCESS` → **public-feed fallback**: report the latest build on the public Preview N channel as a *labeled candidate* that may not be the official/blessed build, without naming the private tool) and adds a **"Blessed ≠ green"** caveat so the blessed build never masks open `regressed-in-*` blockers. DRY — it cross-references dependency-flow's tier table / opt-in / guardrails rather than duplicating them. **2. `dependency-flow/` gate — evolves the version already merged in #36268.** The deterministic classifier `scripts/Get-PreviewReleaseReadiness.ps1` emits: ``` RELEASE_TRACKER_STATUS = NO_ACCESS | ACCESS_ON_INACTIVE_ACCOUNT | AVAILABLE_NOT_ENABLED | AVAILABLE_ENABLED ``` It checks (1) GitHub read access to the private marketplace repo that hosts the internal **.NET Release Tracker** plugin and (2) whether that plugin is enabled locally. It fetches **no** release data and always exits `0`. This PR carries improvements over the version on `main`: - **JSONC-tolerant** enabled-plugin parser — the strict `ConvertFrom-Json` on `main` chokes on the `//`-commented opt-in snippet the skill itself documents; - `$USERPROFILE` support (Windows user scope) alongside `$HOME`; - **multi-account advisory** — when the active `gh` identity can't read the repo but a logged-in *inactive* account can, the gate emits `ACCESS_ON_INACTIVE_ACCOUNT` and advises `gh auth switch --user <account>` instead of a false-positive `AVAILABLE` (the plugin loads under the *active* identity). Only fires when access is confirmed on some account, so a true no-access caller still gets a silent `NO_ACCESS`; - `-ReleaseRepo` / `-PluginId` / `-Json` parameters and a public-safe `.NOTES` contract; - try/catch hardening so an unexpected terminating error still emits the safe `NO_ACCESS` default; - the *"why a special source"* / Preview 6 (#35364) trap prose in `SKILL.md`. > **Relationship to #36268.** #36268 ("public-safe preview release readiness gate") already merged the first version of this gate. This PR is a **forward-evolution** of those two files, **plus** the net-new release-readiness bridge — it does **not** revert any shipped behavior. In particular the plugin opt-in stays **user-scope only** (`~/.copilot/settings.json`); there is no committable project-scope enablement, so forks and no-access users are never silently opted in. The "comment-only on GitHub" guardrail is retained. **3. Preview wiring checks — subscriptions + feed drift + component pins (net-new).** A preview can pass CI and even have a blessed build yet still not be *ship-wired*. Three **public** (BAR/Maestro + git) checks close that gap: - **Check A — subscriptions wired?** Confirm `release/11.0.1xx-previewN` has its default-channel mapping **and** the baseline three subs (android + macios + dotnet on `.NET 11.0.1xx SDK Preview N`). Branch cut + default-channel present but **zero subs** = a start-of-preview flow gap → surfaced as an **FYI note** (not a ship blocker); the skill still knows how to remediate via the existing **combined-PR pattern** (DRY, honoring its confirm/draft-PR gate). - **Check B — feed matches the branch?** Compare the latest build promoted to the `.NET 11.0.1xx SDK Preview N` channel (`maestro_latest_build`) against `origin/release/11.0.1xx-previewN` HEAD. Branch ahead of the promoted build = stale feed → flag. - **Check C — component pins coherent?** Report which `dotnet/android`, `dotnet/macios`, and `dotnet/dotnet` (VMR) builds MAUI bundles (version + SHA from `eng/Version.Details.xml`) and confirm they **match the inflight `netN.0` branch the preview was cut from**. Match = clean cut ✅; divergence or an off-band pin (macios/dotnet missing the `-net11-pN`/`preview.N` stamp) → flag. The `.NET Release Tracker` exposes **only** SDK/runtime-level data, so there is **no** "blessed" per-component android/macios build to look up — this is git+BAR only. "Behind the latest component build" is *expected* for a cut branch (don't flag it); android's `-ci.main.NN` scheme is normal for net11 and validated against inflight rather than alarmed on. Mechanics (exact MCP/`darc`/git commands, interpretation tables, remediation, and **live net11 Preview 6 worked examples**) live in a new **"Wiring checks: is Preview N actually plumbed?"** subsection (Checks A/B/C) in `dependency-flow/SKILL.md` (its Maestro/subscription domain); `release-readiness/SKILL.md` gets a short orchestration hook that cross-references it and folds the results into the preview report. **4. Preview generator — scope Maestro PRs to the target branch (net-new bug fix).** `scripts/Get-PreviewReadiness.ps1` (the deterministic generator the GitHub Action runs to author the `[Release Readiness]` preview tracker, e.g. #35866) was listing Maestro / dependency-flow PRs that target `netN.0` (the **inflight** branch) inside the preview tracker's own "Maestro / dependency-flow PRs" section. Once a preview is **branched**, those `netN.0` bumps belong to the inflight branch's own readiness, not the preview tracker. `Get-CategorizedPullRequests` now computes the Maestro bucket from `$TargetPRs` (the survey ref) **only** instead of target + inflight, so `netN.0` (inflight) Maestro PRs land in no rendered bucket and are intentionally dropped from a branched preview tracker. Non-Maestro inflight PRs still surface unchanged in the Inflight-human bucket. In **candidate** mode the survey ref *is* `netN.0` and the inflight list is empty, so target-only is correct there too. Unit tests (`tests/Test-ReleaseReadiness.ps1`, precedence + AutomationNull null-safety) updated to assert target-only scoping, including a new assertion that an inflight Maestro PR appears in no bucket. **5. Surface human-authored dependency-bump PRs in High-priority items + drift-proof SR E2E tests (net-new).** Two follow-ups in `scripts/Get-PreviewReadiness.ps1`: - **Dependency-bump detection was author-only.** The component-bump PR that *is* the release (e.g. #36433 — `rmarinho`, "Bump dotnet/dotnet (BAR 321614), dotnet/android (BAR 321622) and dotnet/macios (BAR 321780)", head `update-321614`, no labels) was authored by a human, so the old `-match "dotnet-maestro"` author filters missed it and it fell into the generic release-branch bucket instead of **High-priority items**. A new `Test-IsDependencyFlowPr` helper now flags a PR as dependency-flow if it matches *any* of: `dotnet-maestro` author **OR** a `Bump dotnet/(dotnet|android|macios|runtime|sdk|…) … (BAR NNN)` title **OR** an `update-<id>` head ref. The three maestro bucket filters were rewired to use it, and the high-priority row kind was renamed `📦 Maestro PR` → `📦 Dependency-flow PR`. Merge-up PRs (`[automated] Merge branch …`, head `merge/…`) are intentionally *not* matched. - **Human-notes block repositioned.** The blessed-build / wiring / component-pin notes now render directly under **High-priority items** (previously below the Target section), so the authoritative-build context sits next to the items it qualifies. - **Drift-proof SR E2E tests.** The end-to-end tests in `tests/Test-ReleaseReadiness.ps1` run the *real* detector against the live repo and had pinned a specific SR as the not-yet-cut candidate; when that SR shipped/cut the fixtures rotted (7 stale failures). They now **derive** the in-flight/candidate split structurally from the detector output (≥1 SR, exactly one candidate numbered one past the highest in-flight SR, clean partition, regression-label formula mirrored from `New-RegressionLabelList`), so they survive every future SR cut/ship without a per-cut edit. **6. Action-owned best-effort component-build section (net-new).** The authoritative *blessed* build lives in the private **.NET Release Tracker** (`dotnet/release`), which the GitHub Action's repo-scoped `GITHUB_TOKEN` **cannot** reach — so on an automated run that row can only come from a maintainer's local notes (spliced into the preserved human-notes block). To give the Action *something* to say on its own, `scripts/Get-PreviewReadiness.ps1` now emits a **best-effort** component-build section sourced from the branch's own `eng/Version.Details.xml` (a **public** git source always readable in CI). A new `Get-BranchComponentPins` reads the `dotnet/dotnet` (VMR/SDK), `dotnet/android` and `dotnet/macios` anchor pins (version + commit SHA) and renders a `🏷️ Preview N component build — branch pins (best-effort)` table. It is **explicitly labeled NOT a confirmed blessed build** — it reports what's *currently bundled on the branch* and points maintainers to the **Release Captain Notes** block (filled locally with tracker access) for the authoritative designation. The section renders **outside** the human-notes markers so it **self-refreshes** on every automated re-run (verified: after #36433 merged, the pins advanced to the post-bump build automatically), and it surfaces an open component-bump PR (e.g. #36433) as a *pending advance* when one is still open. `Get-BranchComponentPins` handles the `[xml]` attribute-vs-child gotcha (`Name`/`Version` are attributes; `Uri`/`Sha` are child elements), prefers the most representative dependency name per repo with a `Uri`-based fallback, and returns `$null` (no throw) when the file can't be read/parsed. Adds 9 unit assertions. Full suite: **794 passed / 0 failed**. ### Why During the Preview 6 cycle (see #35364), two same-band VMR builds (e.g. `…26325.125` vs `…26326.122`) looked interchangeable. Public BAR/Maestro data can enumerate candidate builds but **cannot, on its own, identify which staged build releases.dot.net has *blessed* as the official preview**. That authoritative signal lives in the internal release tracker. This change lets developers *with access* get the authoritative answer automatically from the `release-readiness` skill, while developers *without access* fall back to the **public preview-feed candidate** — the latest build promoted to the public Preview N channel, explicitly labeled as possibly-not-the-official build — with the private *tool* never named or implied. The wiring checks add the complementary *"is the branch even receiving flow, and is its feed current?"* signal — validated live: net11 Preview 6 is branched with a promoted build **but has no subscriptions authored yet** (Preview 5's set was never rolled forward), exactly the gap Check A surfaces (as an FYI). ### Privacy / safety The plugin is **double-gated** (GitHub read access to load it + an authorized Azure AD identity to pull data), so referencing it from this public repo is safe. The change deliberately: - contains **no** Azure AD resource ids / `api://…` audiences, backend hostnames, or internal endpoint paths — only the sanctioned *marketplace pointer* (repo name + plugin name); - performs **no** fetch-and-exec of remote code; - defaults to `NO_ACCESS` for any unconfirmed-access case, so the agent **never** reveals the private plugin *tool* to users who can't use it — the NO_ACCESS path now emits an honest, public-source-labeled preview-feed candidate (public data), which reveals nothing about the gated tooling — the multi-account advisory only fires when access is *confirmed* on some logged-in account, and never prints a token; - keeps the opt-in **user-scope** (personal `~/.copilot/settings.json`), so forks and no-access users are unaffected; - the wiring checks read only **public** BAR/Maestro + git data and never mutate config — remediation is opt-in and routes through the documented confirm/draft-PR gate. ### Testing `scripts/Get-PreviewReleaseReadiness.ps1` was exercised across all states locally with `pwsh` (token **and** `-Json` forms): | Scenario | Result | |----------|--------| | Real access probe (`dotnet/release`), plugin enabled in `~/.copilot/settings.json` (JSONC w/ comments) | `AVAILABLE_ENABLED`, exit 0 | | Real access probe, plugin not enabled | `AVAILABLE_NOT_ENABLED`, exit 0 | | Active identity lacks access, but a logged-in inactive account has it | `ACCESS_ON_INACTIVE_ACCOUNT` + `gh auth switch --user <account>` advice, exit 0 (and `GH_TOKEN` restored after probing) | | Same user settings with `: false` | `AVAILABLE_NOT_ENABLED` (correctly not matched), exit 0 | | Nonexistent repo (no account can read) | `NO_ACCESS`, exit 0 | The wiring checks (items **3A/3B**) were validated against **live Maestro/BAR + git** for net11 Preview 6: `maestro_subscriptions(targetBranch="release/11.0.1xx-preview6")` → **0 rows** (FYI note correctly surfaced); `maestro_latest_build(".NET 11.0.1xx SDK Preview 6")` → build #321033 @ `6e35dc58d0` == branch HEAD (feed current); Check C (component pins) → dotnet/dotnet `11.0.0-preview.6.26325.125`, dotnet/macios `26.5.11717-net11-p6`, dotnet/android `37.0.0-ci.main.51` all **byte-identical to `net11.0` HEAD** = clean cut. The **Action-owned best-effort component section** (item **6**) is unit-tested (9 assertions over `Get-BranchComponentPins`: parse correctness, name preference, `[xml]` attribute/child handling, unreadable-file → `$null`) and validated end-to-end by dispatching the real GitHub Action against this PR branch — the section rendered on #35866 sourced purely from `eng/Version.Details.xml` and self-refreshed to the post-#36433 pins with no local tracker access. Full suite: **794 passed / 0 failed**. Docs/skill-only change — no product code or public API is affected. --------- Co-authored-by: PureWeen <223556219+Copilot@users.noreply.github.com>
…r) (#36460) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## Description Adds **two net-new** [GitHub Agentic Workflows](https://gh.io/gh-aw) that keep dotnet/maui's own gh-aw setup current. This is **maintenance-only automation** — it does **not** touch the existing 11 gh-aw workflows, product code, or CI. Both are **credential-free** on the write path (they use only the default `GITHUB_TOKEN` via safe-outputs); the Copilot PAT pool is used solely for model **inference**, exactly like every existing MAUI agentic workflow. ### Workflow A — `aw-actions-update.md` ("Action Pin Refresh") Low-risk action-pin refresher. - **Triggers:** weekly `schedule` + `workflow_dispatch`, pinned to `main` (`checkout: ref: main`), fork-guarded. - **What it does:** installs the gh-aw CLI **pinned to v0.80.9** (the same `compiler_version` as the committed locks, so `actions-lock.json` stays consistent with them — no version skew; failing closed if that exact version can't be installed), runs `gh aw update`, then opens a PR **only** when `.github/aw/actions-lock.json` changes (the SHA-pin lockfile for the actions our workflows use). - **Blast radius pinned:** `allowed-files` restricts the write to that single file, and `protected-files: allowed` is scoped to just that one path under `.github/`. Generated `.github/workflows/*.lock.yml` and any source-workflow drift are explicitly discarded (including brand-new **untracked** files, via a scoped `git clean`) and verified out with `git status --porcelain` — this workflow can *only* touch the actions lock. - De-dupes against its **own** open `[actions]` PRs (scoped to `--author "app/github-actions"`); no-ops quietly when there's nothing to update. > **Known behavior (by design, not a defect):** > - The PR only edits `.github/aw/actions-lock.json`. Because each `.lock.yml` embeds its resolved action SHAs, the refreshed pins take runtime effect only after the workflows are **recompiled** (`gh aw compile`) — which is Workflow B's maintainer runbook. Pushing regenerated `.lock.yml` files would require a GitHub-App `workflows: write` token this credential-free workflow deliberately avoids. > - Because the PR is created with the default `GITHUB_TOKEN`, it will **not** auto-trigger CI (GitHub platform rule: `GITHUB_TOKEN` pushes don't fire workflow events). A maintainer may need to nudge CI (e.g., close/reopen the PR or push an empty commit). ### Workflow B — `aw-version-update.md` ("Agentic Workflow Version Auto-Update") gh-aw version updater, **detect → file issue** design (fully automatic, credential-free). - **Triggers:** weekly `schedule` (live) + `workflow_dispatch`, pinned to `main`, fork-guarded. - **What it does:** a **read-only** detector (`permissions: { contents: read, issues: read }`) installs/refreshes the gh-aw CLI **to the latest release** (detecting newer versions is its whole purpose), runs `gh aw upgrade` + `gh aw compile`, and checks whether that produces a non-empty change set (`git status --porcelain`, so brand-new untracked locks are caught). It then hard-resets its worktree so nothing leaks out of the detection run. - **If an upgrade is pending,** it emits exactly **one** `create-issue` — a `[Auto Update]` tracking issue asking a maintainer to run `gh aw upgrade` locally and open the PR. The issue is filed with the default `GITHUB_TOKEN` (`issues: write`, granted to the separate safe-outputs job). Steady state is `noop` (no issue, no noise). - **De-dupes** against its **own** open `[Auto Update]` issues (scoped to `--author "app/github-actions"`), and runs with `min-integrity: approved` so community content stays out of the agent's view. > **Why an issue instead of an automated PR (deliberate design):** `gh aw upgrade` / `gh aw compile` regenerate `.github/workflows/*.lock.yml`, which the default `GITHUB_TOKEN` cannot push (GitHub platform rule) and which would otherwise require a Copilot-licensed / `workflow`-scoped agent token this repo intentionally does **not** provision. Filing an issue keeps the workflow fully automatic and credential-free; a maintainer performs the actual upgrade. There is **no** `create-agent-session`, `GH_AW_AGENT_TOKEN`, or staged-delegation step. Both workflows reuse MAUI's existing Copilot PAT-pool import + `copilot-pat-pool` environment (inference only), carry a fork guard (won't run in forks), and were compiled with **gh-aw v0.80.9** — the same `compiler_version` as all 11 existing locks, so no other lock files are bumped. ## Validation - ✅ `gh aw compile` — **0 errors, 0 warnings** on both. - ✅ `gh aw lint` — clean across all workflows. - ✅ gh-aw security review (gh-aw-guide scanner) — clean on both. - ✅ Scope check — only the 4 new workflow files (2 `.md` + 2 generated `.lock.yml`); the existing 11 workflows are untouched. No auto-generated files (`cgmanifest.json`, `templatestrings.json`) changed. ## Rollout - **Workflow A** can be enabled immediately — low-risk, single-file, human-reviewed PRs. - **Workflow B** is safe to run live on merge — its only possible write is a single tracking issue for a maintainer; the actual upgrade is always human-performed. No secrets to provision. ## Notes for reviewers - No hardcoded PATs; both use the standard `COPILOT_PAT_0..9` pool via the existing `shared/pat_pool.md` import (inference only). - No auto-merge — every PR/issue these produce is human-reviewed/actioned. - `.lock.yml` files are auto-generated; regenerate via `gh aw compile <name>`, never hand-edit. <sub>Co-authored-by: Copilot App</sub> --------- Co-authored-by: PureWeen <223556219+Copilot@users.noreply.github.com>
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## Summary - Reverts the iOS layout changes from #34936 for `Default` and `Fixed` `FlyoutHeaderBehavior`. - Restores the prior overlapping ScrollView frame and top content inset, allowing flyout items to scroll behind a semi-transparent header. - Removes the regression test that asserted the reverted behavior. - After merge, backport this commit to `release/10.0.1xx-sr9` for 10.0.90. Fixes #36249 ## Test plan - `pwsh .github/skills/run-device-tests/scripts/Run-DeviceTests.ps1 -Project Controls -Platform ios -TestFilter "Category=Shell"` (203 passed) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! Fixes #36154. Forward-ports the final implementation and regression coverage from #36231 to `main`, preserving the newer WebView lifecycle handling already present on `main`. The Android SwipeView now yields to a nested WebView while it can scroll in the gesture direction, and handles the gesture at the WebView edge. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## Summary - Advances `main` from the SR9 `10.0.90` cycle to the SR10 `10.0.100` cycle. - Keeps `SdkBandVersion` and prerelease settings unchanged. - Matches the previous cycle bumps in #35433 and #35879. This clears the `Main bumped to SR10 cycle` release-readiness blocker for 10.0.90. _This PR was created by GitHub Copilot CLI on behalf of @kubaflo._ Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…#36461) > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## What this changes Follow-up to #36317 (the self-watching `ci-status-fix` loop). Today, when a `[ci-fix]` draft PR's CI comes back green — or red only on **unrelated** flakes — the loop posts a comment but **leaves the PR as a draft forever**. A maintainer has to notice it, confirm the specific fixed test actually passed, and flip it to ready. In practice these validated-green draft PRs sit unreviewed for weeks. This PR adds a **target-test verification + mark-ready gate (Step 3.6)** to both twins (`main` + `net11.0`). When a draft `[ci-fix]` / `[ci-fix-net11]` PR reaches the green-surface or unrelated-flake branch, the loop now drills into the PR's **own** AzDO test-results for the **specific test(s)** the fix targeted. If every target test is `Passed` on ≥1 leg and `Failed` on none (VALIDATED-GREEN), it: - posts a `🎯 Target test validated green on <headSha>` comment (naming the test + legs + buildId), and - transitions the draft PR to **ready for review**. This is a **state transition only** — it never approves and never merges; a human still reviews and merges. Overall red on **unrelated** legs no longer keeps a validated fix parked as a draft. ## How it works - **Preconditions** (all required): PR `isDraft == true`; it is unmistakably this workflow's own PR (`[ci-fix]`/`[ci-fix-net11]` title prefix **and** `agentic-workflows` label); and it was reached from the green or **unrelated-flake** path (never from caused-by-fix — that path advances an attempt instead). - **T1 — identify target test(s)** from the `[ci-scan]` issue signature + the PR diff. If no specific test can be identified (e.g. a product build-break), it records a skip — build-only fixes are validated by overall-green, which the existing green branch already handles. - **T2 — drill AzDO test-results** for the build(s) on the PR's current head SHA, filtered to the target test's `testCaseTitle`. A test that never ran (e.g. an `/azp`-gated `maui-pr-uitests`/`maui-pr-devicetests` leg that wasn't kicked) is **not** validated — the loop records an honest "not yet executed" skip and does **not** mark ready. No overclaiming: a green *sibling* leg is not the target test. - **T3 — mark ready + report**, guarded by a per-head-SHA idempotency marker and the existing `dry_run` gate (dry-run emits nothing and tallies `would-mark-ready`). ## Safe-output Adds the `mark-pull-request-as-ready-for-review` safe-output to both twins (`max: 3`, `target: "*"`, `required-title-prefix` + `required-labels`). Unlike `update-pull-request`, this output's `required-*` guards **do** survive the gh-aw v0.80.9 compile (verified against the generated locks), so which-PR scoping is enforced at the handler level in addition to the Step 3.6 preconditions and `min-integrity: approved`. No gh-aw version bump is required — the capability already exists at our pinned v0.80.9. ## Enabling fix — the loop's own create-PR commit no longer counts as "human engaged" While validating this feature against #36429 I found the mark-ready path was **unreachable for every loop-owned draft PR**, and traced it to a regression from #36317's own review-hardening. gh-aw's `create_pull_request` builds a PR's initial commit through the GitHub API, which stamps `author=github-actions[bot]` but **`committer=web-flow`**. Commit `2f6b77b330` (in #36317) removed `web-flow` from the prefetch's bot-login denylist so a maintainer "Update branch" would correctly hand the PR off — but that also made `Test-AnyHumanCommitActor`'s committer check read the loop's **own** first commit as human engagement. Result: every freshly opened `[ci-fix]` draft PR computed `humanEngaged=true` from commit #1, so the watch loop skipped it forever — never surfacing green, never marking ready. This regression is live on `main` today (all four open loop-owned draft PRs have `committer=web-flow`). Fix (`Query-CiFixPRs.ps1`): a human **committer** only trips the hand-off when the commit **author** is not one of this workflow's own bot identities (`$LoopBotCommitAuthors`). A human **author** still counts unconditionally, so maintainer direct commits and web-flow-authored "Update branch" merges continue to hand off correctly. Unit-tested across all six author/committer shapes. ## Validation - Both twins recompiled with `gh aw compile` (0 errors / 0 warnings); locks show no action-SHA or `compiler_version` drift (only frontmatter/body hash + the new handler config). - `mark_pull_request_as_ready_for_review` config confirmed present in **both** locks with the correct `[ci-fix] ` / `[ci-fix-net11] ` prefixes and `agentic-workflows` label; the `safe_outputs` job carries `pull-requests: write`. - Twin symmetry preserved (only `[ci-fix]` ↔ `[ci-fix-net11]` / `ci-scan` ↔ `ci-scan-net11` token differences). - **Live dry-run against #36429** (scoped `workflow_dispatch`, `dry_run=true`, this branch): the workflow prefetch now computes `humanEngaged=false` for #36429 (was `true` pre-fix), and the agent's gate walk correctly advances **past** the human-engaged gate to the CI-pending WAIT gate — `checksSettled=false` because #36429's macOS `SafeAreaEdges` leg is still queued. Once that leg settles green, the same run path reaches Step 3.6 and marks the PR ready. Emitted zero writes (dry-run). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: PureWeen <223556219+Copilot@users.noreply.github.com>
…le grouped comments (#36533) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### What this changes The `/review tests` **Test Failure Analysis** workflow classifies whether a PR's CI failures are PR-caused or unrelated. Its deterministic gate computed `legsRegressedVsBase` — the "Likely PR-caused" headline — by comparing each red PR leg against **a single most-recent base build**. Flaky UI-test legs that happened to be green on that one base build produced false **"regressed-vs-base / Likely PR-caused"** positives, so the generated comments carried little signal. This PR makes the regression diff sample **several recent base builds of the PR's own base branch** (`main` or `net11.0`) and only calls a leg a regression when it is green across enough of them and red on none — and switches the LLM engine to Opus. It also **replaces the per-test result table with a skimmable, root-cause-grouped bullet list** (the deep-UI-test-analysis style) so a run with hundreds of failures collapses to a handful of readable groups inside the existing compact badge + collapsible header instead of a giant table. ### Changes - **`Gather-TestFailureContext.ps1`** — new `Get-AggregatedBaseLegMap` aggregator + params `RegressionBaseBuilds=5` and `MinBaseGreenSamples=2`. A leg is a regression only if it is green on **≥ `MinBaseGreenSamples`** base builds **and red on NONE**. Per base build, a leg that failed even one attempt counts RED (a retry that later passed does not clear a base flake). New leg states `flaky-on-base` / `succeeded-on-base-unconfirmed` and new per-failure fields `baseSampleCount` / `baseGreenCount` / `baseFailedCount`. - **Asymmetric conservatism (preserved)** — multi-build sampling widens **only** the false-RED (assert-a-regression) side. The test-level dismissal / false-GREEN side stays single-build-strict on purpose, so this change never turns a real failure green. - **`copilot-review-tests.md` / `.lock.yml`** — engine model `claude-sonnet-4.6` → `claude-opus-4.8`; **replaced only the per-test Markdown table** (an unreadable wall of text on runs with hundreds of failures) with a deep-UI-test-analysis style **root-cause-grouped** bullet list using subtle tokens (`✗ PR-related` / `ℹ Uncertain` / `● Unrelated`). The compact **badge row and the `Test Failure Review: [verdict] - click to expand` collapsible are kept** so the collapsed comment stays a one-glance summary; the badge set now surfaces the key multi-build signal — `Overall` / `Failures` / **`Regressed vs base`** (replacing the old `Platform` badge) / `Baseline on base`. Everything detailed (verdict sentence, grouped bullets, coverage counts, this-PR + base-sampling build links, recommended action) lives inside the collapsible. `img.shields.io` stays in the network allowlist. Lock recompiled (gh-aw v0.80.9). - **`SKILL.md` / `maui-ci-facts.md`** — document the multi-build sampling, the new states/fields, and soften the "green on base is proof" wording to require green across several base builds and red on none. ### Validation Ran the gatherer locally against **PR #36478** (base `main`), before vs after: | | `legsRegressedVsBase` | Verdict | |---|---|---| | **Before** (single base build) | **14** | Not ready | | **After** (5 base builds) | **0** | Needs human investigation | The `ValidateDynamic*` (×9), `CollectionViewInfiniteScroll`, and `Issue17400` legs — each green on 4/5 base builds and red on 1/5 — are now correctly classified as `flaky-on-base` instead of PR regressions. ### Notes - Extracted as a focused, standalone change from the broader `improved-reviewer` work (#36473). - CI-tooling-only change (`.github/`); no framework/runtime code is touched. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… twin) (#36601) > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## Problem The **net11 twin** of the CI Failure Fixer (`ci-status-fix-net11`) has been failing in its `safe_outputs` job on most scheduled runs since ~2026-07-10 (red on 07-10, 07-12, 07-13, 07-14, and 07-15 ×2). Every failure is the same error: ``` Cannot create pull request: patch modifies files outside the allowed-files list (src/AI/tests/Essentials.AI.UnitTests/...) ``` `net11.0` gained a new **`src/AI/`** source tree (Essentials.AI / streaming-JSON) that **does not exist on `main`** (it 404s there). The agent repeatedly finds a flaky `Essentials.AI.UnitTests` test, builds a valid fix, and emits `create_pull_request` — but `src/AI/**` was never added to the enforced `allowed-files` allowlist. The handler rejects the patch, so: - the whole scheduled run goes **red** every time, - that AI-test flake can **never** be filed, and - one create-PR slot is **burned** each sweep. The `main` twin is unaffected because there is no `src/AI/` tree on `main`. ## Fix Add `src/AI/**` to **both** `allowed-files` blocks (`create-pull-request` and `push-to-pull-request-branch`) in **both** twins: - On **net11.0** it unblocks the failing PR creation. - On **main** it is a harmless no-op (no `src/AI/` tree exists there to match) and keeps the two workflow files byte-identical per the established mirror invariant — future-proofing a forward-port of the AI tree. Both `.lock.yml` files were recompiled with `gh aw compile` (0 errors / 0 warnings). The only substantive lock delta is the prepended `"src/AI/**"` entry in the two `allowed_files` arrays (plus the metadata hash line). No other handler config changed — `max` values, `add_labels allowed:[p/0]`, `mark_pull_request_as_ready_for_review`, `protected_files`, `base_branch`, and `title_prefix` are all unchanged. ## Verification - `gh aw compile ci-status-fix` and `gh aw compile ci-status-fix-net11` → **0 errors / 0 warnings** each. - Twin-symmetry invariant preserved (transformed-net11 vs main diff = **124 lines**, the pre-existing cosmetic delta — unchanged by this PR). - `gh aw lint` → no lint issues. - Confirmed via lock diff that the sole config change is `"src/AI/**"` prepended to the two `allowed_files` arrays in each twin. Co-authored-by: PureWeen <223556219+Copilot@users.noreply.github.com>
…Copilot follow-ups from #36213) (#36483) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### What Two small follow-up fixes to the release-readiness reporting skill, closing two **low-severity** edge cases that the GitHub Copilot reviewer flagged on #36213 and that shipped into `main`. Both are docs/skill-only (PowerShell + tests) — no product code, no public API. **1. `Test-PluginEnabled` — minified `settings.json` false negative** `.github/skills/dependency-flow/scripts/Get-PreviewReleaseReadiness.ps1` The enabled-plugin matcher was anchored to the start of a physical line (`(?m)^\s*`). A **minified / single-line** `settings.json` (e.g. `{"enabledPlugins":{"dotnet-release-tracker@dotnet-release":true}}`) therefore failed to match, so an *enabled* plugin was reported as **not** enabled (a false-negative that wrongly degrades to `AVAILABLE_NOT_ENABLED`). It fails safe — it never produces a false *enabled* — but it's still wrong for anyone whose settings file isn't pretty-printed. Fix: anchor the key to a JSON boundary (`{`, `,`, or whitespace) via a look-behind `(?<=[{,\s])` instead of a line start. Comment-avoidance is already handled by the string-aware `Remove-JsoncComments` scrub applied just below, so the line anchor was redundant. **2. `Test-IsSdkBumpPr` — `dotnet-optimization` collision** `.github/skills/release-readiness/scripts/Get-PreviewReadiness.ps1` `'(?i)\bBump\b.*dotnet/(dotnet|sdk)\b'` — the trailing `\b` sits between `t` and `-`, so `Bump dotnet/dotnet-optimization …` was misclassified as an SDK/VMR bump (which would attach a spurious "verify blessed build locally" emphasis). Fix: use the `(?![\w-])` boundary that its sibling matchers already use (`selectPin`, `Get-ComponentFlowSignal`). Practically dormant on maui today (real dep-flow PRs are titled `[netN.0] Update dependencies from…`), but now correct. ### Tests Added hermetic regression guards in `Test-ReleaseReadiness.ps1`: - `Test-PluginEnabled`: minified, pretty, suffix-only-key (no false positive), and absent-entry cases (writes fixtures into a throwaway `HOME`/`USERPROFILE`, restored in `finally`; no `gh`/network). - `Test-IsSdkBumpPr`: `dotnet/dotnet-optimization` does **not** collide → `false`; a real `dotnet/sdk` later in the same title still → `true`. This mirrors the `Get-ComponentFlowSignal` collision guard that already existed — the sibling matcher just never got the parallel assertion (the exact gap this closes). Suite: **853 passed / 0 failed** (`-SkipE2E`). ### Why low-risk Skill/tooling only. Fix 1 only ever *widens* a previously-too-narrow match and still can't produce a false enable; Fix 2 only *narrows* an over-broad match to exclude a hyphenated sibling. Both are covered by new tests that fail against the old patterns. Co-authored-by: PureWeen <223556219+Copilot@users.noreply.github.com>
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## Summary The live manual validation of Action Pin Refresh ([run 29052735587](https://github.com/dotnet/maui/actions/runs/29052735587)) correctly produced a no-op: the runner had gh-aw v0.81.6 preinstalled, but the v0.80.9-compiled workflow needed its matching CLI. `gh extension remove gh-aw` could not authenticate because the agent had only the Copilot inference PAT, and direct binary download was blocked. This follow-up supplies the agent's `GH_TOKEN` from the workflow's existing read-only `${{ github.token }}` permissions, leaving the Copilot PAT limited to inference. It also reads and validates the required gh-aw version from `aw-actions-update.lock.yml` metadata, avoiding manual pin drift when the dedicated version-updater changes the compiler version. ## Scope - `.github/workflows/aw-actions-update.md` - Regenerated `.github/workflows/aw-actions-update.lock.yml` (compiled with gh-aw v0.80.9) The safe-output remains constrained to `.github/aw/actions-lock.json`; permissions and write scope are unchanged. ## Validation - `gh aw compile aw-actions-update` - gh-aw workflow security scanner: `aw-actions-update.md` passed - `gh aw lint .github/workflows/aw-actions-update.lock.yml` reported no lint issues; its local actionlint integration exited 125 due to a tooling error. Co-authored-by: PureWeen <223556219+Copilot@users.noreply.github.com>
…ry inline-findings.json write (#36002) > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## What & why Fixes to the Copilot PR-reviewer pipeline, driven by analyzing **64 recent `maui-copilot` PR-reviewer CI sessions** (most-recent run per PR, last 7 days). Three independent analysis agents mined disjoint batches and **converged on the same top two systemic issues** — strong signal these are structural, not anecdotal. Fixes #1 and #2 are **prompt/instruction-only**; the PR additionally ships **regression-guard evals** for both, plus a **token-auth migration** of the eval harness workflow (see Scope & safety). ### 1. `gh` CLI is unauthenticated by design, but the prompt doesn't say so — ~61/64 sessions The `CopilotReview` task intentionally strips all GitHub tokens (`copilot ... --secret-env-vars=GH_TOKEN,COPILOT_GITHUB_TOKEN,GITHUB_TOKEN`), so `gh pr view` / `gh issue view` / `gh api` always fail inside the agent run. But `pr-preflight.md` still *leads* with those commands, so nearly every session burns 1-3 turns watching them fail and pivoting — and several then **wrongly log an "environment blocker" or lower review confidence**. **Fix:** `pr-preflight.md` now opens with an explicit "Environment & Authentication" note stating that unauthenticated `gh` is **expected, not a blocker** (don't stop, don't reduce confidence), and provides **local-`git` + unauthenticated public-REST (`curl`)** recipes that work in CI. The original `gh` recipes are retained for local `pr-review` runs where a token is present. ### 2. Agent refuses to write the REQUIRED `inline-findings.json` — ~34/64 sessions The expert-review step over-generalizes a host "do not write output files" guardrail and refuses to write `inline-findings.json`, dumping the JSON into chat instead. There is **no fallback** — `post-inline-review.ps1` finds no file (`Test-Path` fails) and **inline review comments are silently dropped** in roughly half of sessions. This is the most damaging correctness issue found. **Fix:** the STEP 5b prompt in `Review-PR.ps1` and the `maui-expert-reviewer` agent now **explicitly authorize and mandate** writing the file, state that the general "don't write review output" guidance does **not** apply to this required artifact, and forbid substituting a chat-text dump (with an orchestrator-writes-it-itself fallback instruction). ## Files - `.github/pr-review/pr-preflight.md` — environment note + local-first / `curl` recipes (#1) - `.github/scripts/Review-PR.ps1` — strengthened STEP 5b inline-findings mandate (#2, prompt string only) - `.github/agents/maui-expert-reviewer.md` — reinforce required file write, no chat-dump (#2) - `.github/skills/pr-review/tests/eval.gh-auth.vally.yaml` — **new** regression guard for #1 - `.github/skills/code-review/tests/eval.inline-findings.vally.yaml` — **new** regression guard for #2 - `.github/workflows/skill-validation.yml` — **token-auth migration** for the eval harness (see Scope & safety) ## Scope & safety - **Fixes #1 and #2 are prompt/instruction text only.** No pipeline control-flow or security-boundary changes — the #1 note merely *documents* the existing token-stripping (reinforces it, never weakens it). `Review-PR.ps1`'s change is confined to a here-string prompt; `pwsh` parse check passes and `$PRNumber` interpolation is preserved. - **`skill-validation.yml` is a token-provisioning migration (not prompt text).** The prior `COPILOT_GITHUB_TOKEN*` secrets were rotated out with the removal of `gh-aw-agents`, so the eval harness now sources Copilot auth from the **`copilot-pat-pool`** environment (`COPILOT_PAT_0..9`, index/run-id modulo selection, masked before `GITHUB_OUTPUT`). This is a **like-for-like** auth-source swap — same `pull_request_target` exposure model as before, no new secret exposure and no security loosening.⚠️ **Merge prerequisite:** the `copilot-pat-pool` environment must be populated with `COPILOT_PAT_0..9` (and must NOT carry required-reviewer/wait-timer protection rules, which would hang the `pull_request_target` job) so eval goes green immediately after merge. ## Evals (regression guards for these fixes) Now that we run [`vally`](https://www.npmjs.com/package/@microsoft/vally-cli) eval suites, each fix ships with a guard that reproduces the exact failure mode it fixes. Both pass `vally lint --strict` and run on this PR (each lives under its skill's `tests/` dir, which flags that skill as changed). - `.github/skills/pr-review/tests/eval.gh-auth.vally.yaml` (#1) — the vally eval step is already tokenless, so it **natively reproduces** the CI condition where `gh` is unauthenticated. The agent must classify that as **expected, not a blocker**, pivot to the local-first `git`/anonymous-REST path, and **not lower its review confidence**. Structural floor: the agent must end with `GH_AUTH_BLOCKER: no` — a *necessary, not sufficient* signal — with an LLM judge scoring the reasoning. - `.github/skills/code-review/tests/eval.inline-findings.vally.yaml` (#2) — pins a worktree to a real regression commit so the agent has a genuine diff, then must **write** `inline-findings.json` (canonical `path`/`line`/`body` schema) to the path the pipeline reads from disk and prove it landed (read back, echo `FILE_OK:[…`). An agent that refuses (`"prohibited"`) and chat-dumps the JSON has no file to echo and fails. An LLM judge scores finding quality, non-refusal, and requires transcript evidence of an actual write tool call (not just a fabricated `FILE_OK:` line). Each suite keeps two graders — one structural floor + one LLM judge. Both floors are *satisfiable by a partial regression* (the prompt hands the agent the giveaway token), so `scoring.threshold` is set to **0.7** (above the house 0.6): with the unweighted `mean(floor, judge_norm)` aggregate, a floor-1.0-but-judge-failing run scores `(1.0 + 0.25)/2 = 0.625`, which 0.6 would **pass** but 0.7 **fails**. This makes the **LLM judge load-bearing** (must reach ≥3/5) rather than letting the spoofable floor decide. Live-validated: good path 1.00, partial-regression 0.625. ## Follow-ups (identified, not in this PR) Same analysis surfaced: PowerShell-vs-bash redirection footguns in `try-fix` recipes; test-result classification keyed off exit code instead of TRX `failed=` count; winners crowned with no regression evidence; gate=FAILED conflating real regressions with wrong-platform/ineffective tests; and the agent re-deriving the true PR diff base each run. These can be addressed in separate PRs. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
> [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## What this adds A reusable, **local-only** dotnet/maui skill — `.github/skills/analyze-sessions` — that analyzes a contributor's Copilot CLI sessions to drive iterative improvements to the **PR-review agent** (and other agents/skills/instruction files). It automates the loop the team has been running by hand: **select → extract → score → judge → cluster → propose → emit-eval**. The emit-eval step is what makes it iterative — every recurring failure mode becomes a `vally` guard-eval, the exact mechanism PR #36002 used by hand, now run over the whole fleet of local sessions. ## Architecture — one engine, two front doors ``` local front door ─┐ -Repository/-Last │ scripts/Get-SessionAnalysis.ps1 (deterministic, NO LLM) -SessionId ─┤ select → extract → score → digest → redact │ • dotnet-replay --summary --json (normalization) CI front door ─┤ • thin raw events.jsonl scan (success/tokens/…) -EventsPath/-Dir ─┘ emits: session-analysis.md + JSON contract │ ▼ redacted digests + ranking agent, in the contributor's OWN session: judge → cluster → propose → emit guard-eval ``` - **Deterministic shared core** (`Get-SessionAnalysis.ps1`, no LLM) does select/extract/score/digest + redaction. It **wraps `dotnet-replay` v0.9.1** for normalization and adds a thin raw `events.jsonl` scan for the signals replay's `--json` omits (per-tool `success`, `outputTokens`, truncations/compactions, aborts, retries, subagent failures). - **Local front door:** `-Repository` / `-Last` / `-SessionId` select from `session-store.db`. - **CI front door:** `-EventsPath` / `-EventsDir` point the *same* engine at already-downloaded AzDO `events.jsonl` artifacts — one engine reused by the existing CI-session pipeline, inside its artifact boundary. - The **judge / cluster / propose / emit-eval** steps run in the contributor's **own Copilot session** (no third-party endpoint), driven by `SKILL.md`. ## Privacy / safety - **Local-only by default** — reads `~/.copilot/…`, writes a report into the session workspace. It **never** opens a gist and **never** POSTs a transcript. - **Redaction on by default** — home paths → `~`, tokens (`ghp_`/`gho_`/`Bearer`/`password=`/`key=`), and emails are stripped from the report **and** any emitted eval. - The LLM-judge runs through the contributor's own auth/quota; cross-machine sharing is explicit, manual, opt-in. ## Deliverables | File | Purpose | |------|---------| | `SKILL.md` | Triggers, 6-phase workflow, judge rubric, learn-from-pr proposal taxonomy, #36002 emit-eval template, privacy model, when-NOT-to-use | | `scripts/Get-SessionAnalysis.ps1` | The deterministic shared core (PowerShell — matches every other repo skill script) | | `references/design-rationale.md` | Cites `dotnet-replay` (+ the `--json` gap), the `events.jsonl` 35-event schema, the privacy model, the two-front-doors architecture, and the hand-run proof-of-concept | | `tests/eval.vally.yaml` | Capability + privacy suite: privacy floor (`SHARE_ACTION: none`), capability (`PROPOSED_EVAL: yes`), and negative-trigger — each a refutation-proof structural floor + LLM judge | ## Verification - Core validated end-to-end against real local maui sessions; ranking is driven by genuine inefficiency (failures, retries, truncations, tokens) rather than calendar span (resumed-session wall-clock is capped for scoring). - Metrics spot-checked against raw `events.jsonl` (tool-failure count, `outputTokens`, compactions all matched exactly). - Both front doors exercised (local DB select **and** `-EventsPath`); `-Json` contract is valid JSON; redaction confirmed against synthetic secrets. - `npx -y @microsoft/vally-cli@0.6.0 lint --eval-spec .github/skills/analyze-sessions/tests/eval.vally.yaml --strict` **passes**. No production code changes — this is additive tooling under `.github/skills/`. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## Summary - Process every prefetched CI-fix watch candidate before broad `ci-scan` discovery, with actionable candidates first. - Keep an open CI-fix PR autonomous until it is closed; eligible `CHANGES_REQUESTED` reviews continue through Track C. - Allow `src/AI/**` so the net11 fixer can address that source subtree, while keeping the main twin behaviorally aligned. - Regenerate both gh-aw lock files. ## Validation - `gh aw compile ci-status-fix` - `gh aw compile ci-status-fix-net11` - PowerShell parser check for `Query-CiFixPRs.ps1` - `git diff --check` - Live prefetch confirms #36404 remains an actionable candidate. --------- Co-authored-by: PureWeen <223556219+Copilot@users.noreply.github.com>
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## Summary - Upgrade the Skill Validation workflow from `@microsoft/vally-cli@0.6.0` to `0.10.0`. - Preserve MAUI's explicit `*.vally.yaml` enumeration because Vally directory discovery recognizes only `eval.yaml` and `eval.yml` by default. - Update all 0.6-specific scoring guidance: these specs intentionally omit `scoring.weights`, retaining Vally 0.10's equal-weight aggregation and existing thresholds. ## Validation - Ran strict lint with `@microsoft/vally-cli@0.10.0` for all 10 MAUI eval specs. - Parsed `.github/workflows/skill-validation.yml` as YAML and ran `git diff --check`. ## Scope This PR is limited to the Vally 0.10.0 upgrade. It intentionally excludes the Trim/AOT fixture-workflow changes from #34962. Co-authored-by: PureWeen <223556219+Copilot@users.noreply.github.com>
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## Summary Add Trim/NativeAOT annotation-chain guidance to the active MAUI expert reviewer and cover it with hermetic Vally scenarios. ## Motivation The HybridWebView NativeAOT investigation showed that IL2026/IL3050 warnings require annotation-chain and target-toolchain analysis. A blanket rule that every suppression is wrong is inaccurate: #34868 uses a documented, narrowly scoped Android NativeAOT ILC workaround, while #34958 demonstrates the structural annotated-helper alternative on `net11.0`. ## What changed - **`maui-expert-reviewer.md`**: expands the Trimming/AOT dimension to require tracing the annotated member, generic/DAM hops, feature guard, reachability, and target analyzer. It distinguishes broad suppression from a documented, scoped toolchain workaround and covers structural-helper/source-generation alternatives. - **Dimension routing**: activates Trimming/AOT review for relevant annotations and IL20xx/IL30xx suppressions, not only direct reflection APIs. - **Hermetic Vally coverage**: uses Vally 0.10 `environment.files` to materialize frozen candidate diffs and the exact supporting source snapshots needed to trace the HybridWebView handler annotations, generic registration DAM hop, and runtime feature guard. No Git history, remote repository, or custom workflow fixture setup is exposed to the reviewer. - **Three discriminating scenarios**: covers the scoped #34868 exception, the #34958 annotated-helper approach, and a reachable-suppression counterfactual that replaces the feature guard with `if (true)` and must be rejected. - **Live-eval reliability**: gives the existing multi-surface prior-review reconciliation scenario a 10-minute cap after passing trials took 4m01s and 4m54s and another was terminated at the former 5-minute cap. ## Evaluation scope The separate `eval.trim-aot.vally.yaml` suite tests technical review reasoning on inert checked-in inputs. Tool-call grading requires inspection of the candidate patch and all annotation-chain sources while rejecting GitHub/network access. The five-run suite retains a `0.9` threshold so the required verdict cannot be masked by the other graders. --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Root Cause The labeler treated agent skills and AI-assisted workflows as generic infrastructure, so it never selected the more-specific `area-ai-agents` label. Its issue-platform guidance also inferred labels too broadly and included the unsupported `platform/tizen` label. ### Description of Change - Routes Copilot CLI agents, agent skills, agentic workflows, evaluations, and AI-assisted development to `area-ai-agents`. - Keeps `area-infrastructure` for generic CI execution, authentication, scheduling, dependency flow, and pipeline plumbing, with an explicit dominant-subject tie-break. - Distinguishes setup concerns such as workload availability and target-framework recognition (`area-setup`) from debugging, editor, build-task, and tooling behavior (`area-tooling`). - Never applies `platform/tizen`, while still selecting the appropriate `area-*` label for Tizen-related content. - Infers issue platform labels only from explicitly named affected platforms; generic claims such as "all platforms" do not infer labels, while an explicit affected-platform list takes precedence. - Expands the active Vally suite from 21 to 25 scenarios, including deterministic regression coverage for `area-ai-agents`, platform exclusion, and exact area selection. - Explicitly activates `agentic-labeler` in every capability scenario and requires labels-only output so the suite measures skill behavior rather than nondeterministic skill discovery or explanatory prose. ### Validation - Rebased onto `main` with `@microsoft/vally-cli@0.10.0` pinned by the Skill Validation workflow. - Full three-trial `agentic-labeler` Vally 0.10.0 evaluation passed at 99.8% (threshold: 85.0%). - JUnit aggregate: 0 failures, 0 errors. - Strict Vally 0.10.0 static validation passed. - Harness hermeticity gate passed. - Skill Validation run: https://github.com/dotnet/maui/actions/runs/29609999793 ### Issues Fixed Follow-up to and replacement for #35570. --------- Co-authored-by: bot <bot@test> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Description of Change Retires automation targeting the unsupported `net10.0` branch: - Removes the scheduled/event-driven `main` → `net10.0` merge workflow and its configuration. - Removes `net10.0` from the daily formatting workflow matrix. - Disables the live merge workflow immediately to prevent replacement PRs while this change is reviewed. The matching dependency-flow cleanup is tracked by [maestro-configuration PR 63025](https://dev.azure.com/dnceng/internal/_git/maestro-configuration/pullrequest/63025), removing the Android, dotnet, and macios subscriptions plus the `net10.0` default-channel mapping. ### Issues Fixed No issue. Retires the automation responsible for generated PRs #36400 and #36641. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…5925) <!-- Please keep the note below for people who find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment whether this change resolves your issue. Thank you! ## What this PR does Adds a scheduled regression-corpus scanner that finds recently merged `i/regression` fixes and drafts a hermetic Vally regression stimulus for the `code-review` skill. When the bad change is statically reviewable, the draft may also propose a small, generalizable `SKILL.md` improvement; downstream Vally evaluation can measure it after a repository contributor triggers `/evaluate-skills`. The manual seed work originally on this branch was superseded by #35942's Vally migration. This PR now contains only the automation that grows the corpus. ## How it works 1. A deterministic PowerShell pre-pass finds recent regression-fix PRs, identifies an explicitly attributed introducing PR, resolves its merge SHA, deduplicates the corpus and pending scanner drafts, and emits bounded candidate data. 2. The agent inspects the introducing merged PR's diff and drafts one hermetic `eval.vally.yaml` entry. The reviewed stimulus contains no live PR or issue context. 3. The only possible draft-PR changes are `.github/skills/code-review/tests/eval.vally.yaml` and `.github/skills/code-review/SKILL.md`; they target `main` from a `regression-corpus/**` branch. ## Rebase and security rework (2026-07-15) - Rebased onto current `main` and regenerated the lock file with gh-aw v0.80.9. - Attribution now requires an explicit `#NNNN` or `PR NNNN` reference, preserves source-text order, and ignores out-of-range identifiers. - Only `OWNER`, `MEMBER`, and `COLLABORATOR` linked-issue comments can supply attribution; public comment text is excluded. - Candidates without a linked regression issue require human attribution instead of generating an invalid eval tag. - Empty GitHub search results produce no candidates rather than a phantom `fixPr: 0` record. - The candidate payload is now structural identifiers only; fetched titles, prose, and file paths are excluded before it reaches the agent prompt. - The scanner deduplicates corpus entries, pending scanner drafts, and accepted candidates from the same run. - The scanner runs only in `dotnet/maui`, uses the repository's gated `copilot-pat-pool`, filters agent GitHub reads at `min-integrity: approved`, and suppresses no-op issues. ## Security review The recompile introduces references to the existing `COPILOT_PAT_0` through `COPILOT_PAT_9` pool, replacing the direct `COPILOT_GITHUB_TOKEN` inference credential. The shared `pat_pool` import selects one credential inside the protected `copilot-pat-pool` environment and passes it only to the Copilot engine; the pre-pass uses only scoped read permissions. The generated lock adds SHA-pinned gh-aw v0.80.9 framework dependencies, including `actions/cache/restore` and `actions/cache/save` v5.0.5, and refreshes the existing GitHub action/container pins. No redirects or unpinned external actions were added. The create-PR safe output is limited to one draft PR, `main`, `regression-corpus/**`, a 256 KB patch, the two files above, and the `agentic-workflows` label. ## Related - #34814 — eval lifecycle and CI integration - #35048 — PR-review improvement epic - #36008 — before/after skill-evaluation presentation - #35977 — worked red-to-green example Draft pending review of the scanner workflow and generated lock. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
<!-- Please keep the note below for people who find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment whether this change resolves your issue. Thank you! ## What this PR does Extends `skill-validation.yml` so skill PRs show a **before→after** eval comparison, not just a pass/fail "after" result. Today the workflow runs each skill PR's Vally evals against the **PR's** reviewer instructions and prints one score column — it proves the eval passes *with* the change ("after" / green), but it never runs the *pre-change* reviewer, so any claimed improvement is asserted, not shown. This adds an advisory **baseline** run and renders a `Before | After | Threshold | Verdict` table (with a 📈/📉 trend) on the PR comment, so a reviewer-instruction change's effect is measured directly. ## How it works - A new **baseline** step reverts **only** the skill's instruction files (`SKILL.md` / `*.md`, **not** `tests/`) to the PR base, runs the same eval specs, and uploads the result. The diff under review is identical in both runs — only the reviewer instructions differ. - The comment job downloads the baseline artifact and switches the table to `Before | After | Threshold | Verdict` when a baseline exists, falling back to the original single-score table otherwise. - **Advisory only** — the baseline never gates; PR status still keys on the authoritative "after" run. - **Auto-skips** when there's no base (manual dispatch), the base commit is unavailable, the skill is new on the branch, or its instructions are unchanged vs base (then before == after). - Same hermetic posture as the after-run: the baseline `env:` carries only `COPILOT_GITHUB_TOKEN` (model auth) — no `GH_TOKEN`/`GITHUB_TOKEN`. Reverting to the base instructions only *reduces* PR-controlled content, so it adds no leak surface. **Cost:** roughly **2×** LLM eval minutes, but only on PRs that actually change reviewer instructions. ## Validation - YAML parses; `actionlint` clean (no errors/warnings); `node --check` passes on the full comment script. ## Context This is the **measurement half** of the regression-improvement loop being built for the `code-review` skill. The other half — the scanner that auto-drafts the eval + proposed reviewer fix — is #35925; #35977 is a live worked example. Split out of #35925 so that PR stays scoped to just the scanner. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### What this is A worked, hermetic regression-corpus example for the `code-review` skill. It pairs a Vally stimulus based on a real lifecycle regression with reviewer guidance that targets the general failure mode. ### Regression captured - **Introducing PR:** #31931 - **Regression:** #35756, fixed by #35803 - **Mechanism:** an early return added to `Page.SendNavigatedTo` suppressed not only duplicate local lifecycle work, but also propagation to the current child when the page's latch was already set. ### Rework - Rebased onto current `main`. - Generalized the guidance: reviewers must distinguish a guard's local duplicate suppression from downstream propagation or side effects, then trace a subsequent call while inputs, recipients, or downstream state may have changed. - Clarified that `**Confidence:**` represents confidence in the safety recommendation, not certainty that an individual failure mechanism exists. An unresolved failure mode must report `**Confidence:** low`. - Hardened the lifecycle eval against its original false pass: a review that identifies the risk but still returns `LGTM` fails the structural floor; semantic analysis remains LLM-judged. ### Validation - `vally lint --eval-spec .github/skills/code-review/tests/eval.vally.yaml --strict` passes locally. - The regression suite is configured for five trials; the CI model evaluation remains the authoritative measurement of the before/after effect. ### Related - #35925 — regression-corpus scanner - #36008 — before/after skill-evaluation reporting --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Description of Change Updates the agentic workflow infrastructure for gh-aw v0.81.6 by applying the generated `gh aw upgrade && gh aw compile` output. Key changes: - Refreshes `.github/aw/actions-lock.json` and generated `.github/workflows/*.lock.yml` files to gh-aw `v0.81.6`. - Renames/updates the agentic workflows agent definition and adds the generated agentic workflow skill files. - Adds the missing local `.github/skills/otel-queries/SKILL.md` target referenced by the new agentic-workflows router for OTEL/trace/telemetry-driven analysis. - Pins gh-aw prompt/reference URLs in `.github/agents/agentic-workflows.md` and designer references to `v0.81.6` instead of floating `main`. - Adds the missing ASCII Charts prompt route and wires `aw-actions-update` safe outputs to depend on `pat_pool`. - Hardens `rerun-review-scanner` by pinning the write-scoped `trigger-rerun-review` safe-output checkout to `main` before running `.github/scripts/Invoke-RerunReviewTrigger.ps1` with `GH_TOKEN`. - Hardens `agentic-labeler` with a source-level safe-output allowlist that permits only `area-*` and `platform/*` labels. gh-aw v0.81.6 validates, sanitizes, and length-bounds label names through its issue-intent normalizer. - Updates workflow source files changed by the compiler, including action pins and rerun/CI scanner workflow sources. - Updates PAT pool validation/docs to use the generated gh-aw setup scripts and Copilot CLI `1.0.65`. - Hardens maintenance workflows by deriving the gh-aw updater pin from `actions-lock.json`, requiring exactly one non-empty setup-cli lock entry with graceful fail-closed fallback, and avoiding `eval` in PAT validation. ### Issues Fixed Fixes #36485 ### Validation - `gh aw upgrade --approve --verbose` - `gh aw compile --approve --verbose` - `gh aw validate --verbose` - YAML parse check for `.github/workflows/validate-pat-pool.yml` - Verified action tags for `actions/checkout@v7.0.0` and `actions/github-script@v9.0.0` - Focused positive/negative checks for gh-aw pinned-version extraction from `.github/aw/actions-lock.json`, including duplicate-entry graceful guard behavior under `set -e` - Static route-target check that `.github/skills/agentic-workflows/SKILL.md` references existing `.github/skills/otel-queries/SKILL.md` - Static check that `.github/agents/agentic-workflows.md` no longer references floating `raw.githubusercontent.com/github/gh-aw/main` prompt URLs - Static checks for OTEL and ASCII Charts route targets, pinned designer reference URLs, and `safe-outputs.needs: [pat_pool]` - Targeted check that `rerun-review-scanner` pins the write-scoped safe-output checkout to `main` in both source and generated lock files - Verified upstream gh-aw v0.81.6 routes `add_labels` through `validateIssueIntentLabels` for type checking, sanitization, and a 128-character limit - Verified the regenerated `agentic-labeler.lock.yml` carries `allowed: ["area-*", "platform/*"]` in both safe-output configuration surfaces ### Platforms Tested - [ ] iOS - [x] Android — not applicable; workflow-only change - [ ] Windows - [ ] Mac --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: PureWeen <5375137+PureWeen@users.noreply.github.com>
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Description of Change #### Root cause `Get-PrNumbersBetweenTags` and `Get-PrNumbersReachableFromTag` treated every parenthesized `(#N)` reference in a commit subject as a merged PR. GitHub squash subjects can contain linked issue references before the actual PR suffix, so preview6 attempted to fetch issues #34716 and #34898 through the pulls API and logged two false 404 errors. #### Fix Add one shared `Get-PrNumbersFromGitLog` helper used by both tag paths. It accepts only the final numeric `(#N)` suffix (with optional trailing whitespace), ignores malformed or non-terminal references, and preserves sorted deduplication. #### Preview6 proof For `11.0.0-preview.5.26304.4..11.0.0-preview.6.26360.8`: - Before: 192 candidate references; false #34716 and #34898 included. - After: 190 candidate PRs; #34716 and #34898 excluded while actual PRs #34719 and #35031 remain. - Real dry run exited 0 and resolved `.NET 11.0-preview6` (#129). - 39 relevant PRs checked, 151 wrong-branch PRs skipped, 15 linked issues checked, and 40 items already correct. - All 14 legitimate milestone corrections remain, with zero report errors. - `-CloseFixedIssues` remained a dry run: two open issues would close and 13 were already closed; no GitHub state was changed. #### Tests - New parser regression selection: 12 tests; restoring the former parser produces 6 failures. - `Fix-MilestoneDrift.Tests.ps1`: 212 passed. - `MilestoneTrigger.Tests.ps1`: 116 passed. #### Non-goals This fixes tag-audit parsing on `main`. It does not address the missed historical preview6 workflow launch: the preview6 tag was created from a net11.0 commit that did not yet contain the already-merged `main` tag-push trigger. Branch-flow/backport policy is intentionally unchanged. ### Issues Fixed N/A — this defect was discovered while auditing the preview6 tag. Co-authored-by: PureWeen <223556219+Copilot@users.noreply.github.com>
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## Summary Updates all repository agentic workflows from gh-aw v0.81.6 to the latest stable v0.82.14 and repairs the PAT-pool source shape that prevented regeneration with the new compiler. ## Root Cause The v0.82.14 compiler emitted invalid generated YAML for the multiline `engine.env.COPILOT_GITHUB_TOKEN` `case()` expressions used by all 14 workflows (`non-map value is specified`). This was a compiler/source-shape incompatibility, not an organization-billing or PAT-authentication failure. Audited v0.81.6 runs showed the existing `copilot-pat-pool` job, Copilot inference, and safe outputs completing successfully. ## Changes - Normalize all PAT-pool `COPILOT_GITHUB_TOKEN` expressions to compiler-safe single-line scalars. - Preserve the environment-scoped PAT pool; do not add `permissions: copilot-requests: write` or org-billed inference. - Apply supported v0.82.14 migrations, including top-level `model` fields and `checkout: false` for the `pull_request_target` labeler. - Add explicit protected-file blocking to code-writing workflows. - Update gh-aw action pins, dispatcher assets, PAT-pool documentation, and the PAT validator. - Regenerate all 14 `.lock.yml` files and `agentics-maintenance.yml` with gh-aw v0.82.14. - Remove the obsolete local agentic workflow designer skill replaced by the v0.82.14 dispatcher route. ## Validation - `gh aw compile --approve --strict --validate --schedule-seed dotnet/maui --verbose` — 14/14 workflows compiled successfully. - Trial-mode compile against `PureWeen/maui` — 14/14 workflows compiled successfully. - `gh aw trial ... --clone-repo PureWeen/maui --dry-run` accepted all 14 workflows without changes. - `gh aw fix` reports no remaining migrations. - All 14 lock files report compiler v0.82.14. - Structural YAML parsing passed for all locks, maintenance, and PAT validation workflows. - PAT-pool preservation checks confirm all workflows still use `COPILOT_GITHUB_TOKEN` and none grant `copilot-requests: write`. Container-backed actionlint, zizmor, and poutine could not run locally because the Docker Desktop daemon was unavailable. --------- Co-authored-by: PureWeen <223556219+Copilot@users.noreply.github.com>
…eed guidance (#36497) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## Summary Release-readiness reports identified the right blockers, but did not always provide enough precise, safe instructions for a release captain or future agent to complete them. This PR makes the SR transition workflows explicit and test-backed. - Require a fix PR to be merged and verified on `main` before recommending `/backport to release/...`. - Document the Arcade backport path and the manual `git cherry-pick -x` conflict fallback. - Document and detect the SR servicing flip: preserve `PatchVersion`, set `PreReleaseVersionLabel=servicing`, and enable stable package versions only on the release branch. - Teach the next-cycle `main` bump as a separate one-file, one-line PR, including the exact title and XML edit. For SR9 → SR10 this is `Update PatchVersion from 90 to 100` and `<PatchVersion>90</PatchVersion>` → `<PatchVersion>100</PatchVersion>`. - Preserve `SdkBandVersion`, `PreReleaseVersionLabel=ci.main`, and `StabilizePackageVersion=false` on `main`, matching the SR7/SR8/SR9 precedent. - **Surface the per-build validation feed for the ship Assessment.** When a promoted BAR build exists for SR HEAD, `Get-MaestroOperationalChecks` now derives and emits the `darc-pub-dotnet-maui-<sha8>` NuGet feed URL (the `Ship Assessment validation feed` check) to paste into the DevDiv ship **Assessment**, plus the `darc get-asset` confirm command. It reports `WATCH` when the build isn't promoted — no default channel → no promotion → no feed → the Assessment has nothing to link (the SR9 miss). - Add focused coverage for backport recommendations, servicing transitions, the triple-digit SR9 → SR10 bump, promoted/unpromoted feed cases, and the valid post-ship/no-in-flight transition before the next SR branch is cut. - Keep preview readiness available when GitHub's GraphQL PR-list endpoint is unhealthy by falling back to bounded REST queries with conservative field mapping and complete merged-PR pagination. ## Release workflow captured | Operation | Target | Required behavior | |---|---|---| | Source fix backport | Merged source PR on `main` | Post `/backport to release/<branch>` only after main ancestry is verified | | SR stabilization | `release/<major>.0.1xx-sr<N>` | Keep its `PatchVersion`; switch to `servicing` and stable packages after the final backport | | Next-cycle preparation | `main` | Change only `PatchVersion` to `(N+1)*10`; keep SDK-band and CI prerelease settings unchanged | | Ship Assessment feed | `release/<major>.0.1xx-sr<N>` build | Add default channel → promote the build → link the per-build `darc-pub-dotnet-maui-<sha8>` feed in the DevDiv Assessment so CSI/customers can validate the exact candidate packages | ## What not to do - Do not recommend a backport command for a fix that exists only on `inflight/current`. - Do not combine the `main` next-cycle bump with the release branch servicing flip. - Do not change `SdkBandVersion` or copy servicing settings onto `main`. - Do not create the ship Assessment without the per-build validation feed — if the SR branch has no BAR default channel the build is never promoted and no `darc-pub-dotnet-maui-<sha8>` feed exists to link. - Do not let the report mutate release or `main` refs, or create channels / promote builds / edit the Assessment; the skill remains report-only (it only derives and surfaces the feed URL). ## Validation - The added and affected release-readiness assertions pass, including the exact SR9 → SR10 title/XML guidance, promoted (`READY`) / unpromoted (`WATCH`) feed cases, common-ancestry main-revert detection, the shipped-SR + next-candidate state with no in-flight SR, and GraphQL→REST PR-discovery fallback pagination. - The complete release-readiness harness reports **1069 passing assertions and 0 failures**. - A live preview-readiness smoke-run completed successfully through REST fallback while GitHub's GraphQL endpoint was returning HTTP 502. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: kubaflo <kubaflo@users.noreply.github.com> Copilot-Session: cf5a6299-1e58-4157-b7fd-b85efaa14755 Copilot-Session: 04bf990b-a216-41df-aa75-08f62a1ecaf0 Copilot-Session: 136770fc-91e0-451c-8a4d-ea6a176f30e8 Copilot-Session: d00747b7-96f3-4e7a-8dfb-e3a48db04b2d Copilot-Session: 4c228cec-8795-4bd5-a86c-c3fede46d534
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Description of Change Automates visual snapshot evidence in `/review tests`. When public AzDO results contain failed screenshot comparisons, the command now emits exactly one test-failure analysis comment containing bounded, expandable baseline/actual/diff panels. Visual evidence remains supplementary: it does not change `gate.verdictCeiling`, deterministic attribution, or the merge-readiness verdict. #### One-comment flow 1. Trusted pre-activation code discovers failed visual results through the public AzDO `resultsbybuild` API, including retry-suffixed attachments such as `Snapshot[1].png` and `Snapshot-diff[1].png`. 2. It resolves baselines from the exact source version tested by AzDO and maps runtime evidence to the correct snapshot directory (`ios-26`, `android-notch-36`, `mac`, or `windows`). 3. It streams and validates bounded PNG assets, then stores them on `review-tests-assets` using immutable commit-pinned `raw.githubusercontent.com` URLs. 4. The Copilot agent emits the normal single `add_comment` analysis payload with a trusted insertion marker. 5. A sealed post-step validates the published asset manifest and injects as many expandable comparison panels as fit into that same comment. Each collapsed panel shows a conservative relationship label: - `Likely PR-caused` for an exact test/platform base regression or directly changed snapshot/test; - `Likely unrelated` for an exact base/known-issue match without direct visual scope; - `Needs human investigation` for unmatched or mixed evidence. 6. Excess comparisons are summarized as omitted instead of creating a companion comment. The local `.github/scripts/Review-Tests.ps1 -PostComment` path uses the same merger. It also recognizes complete reports returned in Copilot's final response, preserving nested evidence code fences without wrapping a second title or badge section. ### Security and Failure Safety - PR text, logs, test names, attachment metadata, changed files, and visual labels remain untrusted input. - The merger script and visual context are copied to a root-owned location before the workflow checks out the untrusted PR branch. - The post-step runs without `COPILOT_GITHUB_TOKEN`, `GH_TOKEN`, or `GITHUB_TOKEN`. - AzDO attachment URLs must match the expected public project and attachment route. - Published assets are size-bounded, signature-checked PNGs with validated dimensions and repository paths. - Raw image URLs must match the exact repository, asset commit, PR directory, and safe filename. - Labels are HTML-escaped and `@` is neutralized before insertion. - Relationship labels use fixed trusted text. Untrusted attribution values are never rendered, and same-named snapshots changed on another platform do not count as PR scope. - The final body is checked panel-by-panel against conservative limits of 45 URLs, 10 mentions, and 60,000 UTF-16 characters, below gh-aw's throwing limits. - The analysis JSON update is atomic (written to a temp file, then renamed over the original). Invalid context, malformed output, missing analysis payloads, limit failures, and dry-run/noop output leave the original analysis unchanged. - The publisher never creates or patches PR comments; only the existing gh-aw `add_comment` payload is mutated. ### What NOT to Do - Do not use the ordinary anonymous AzDO test-runs listing for discovery; it redirects to sign-in. Use the public failed-results endpoint. - Do not resolve baselines from the current PR head; use the source version actually tested by the selected AzDO build. - Do not let the agent construct or trust visual asset URLs. - Do not publish a second companion comment; merge bounded panels into the single analysis payload. ### Validation - 98 focused Pester tests pass. - Changed PowerShell scripts parse successfully. - `gh aw compile copilot-review-tests --approve` completes without errors or warnings. - A real `agent_output.json` from gh-aw run [29674953402](https://github.com/dotnet/maui/actions/runs/29674953402) was replayed through the post-step: - one `add_comment` item remained one item; - five visual panels were inserted; - the final body contained 26 URLs, one mention, and 9,585 characters. ### Live Single-Comment Examples The exact local `/review tests` path from this branch posted or repaired these merged comments after the PRs' `/azp run` pipelines completed: | PR | Single merged result | Included evidence | Relationship labels | Final limits | | --- | --- | --- | --- | --- | | #36413 | [Test-failure analysis with visual panels](#36413 (comment)) | 5 panels / 15 images | 1 PR-caused, 4 investigate | 23 URLs, 13,156 chars | | #36631 | [Test-failure analysis with visual panels](#36631 (comment)) | 6 panels / 18 images | 2 PR-caused, 4 investigate | 31 URLs, 21,367 chars | | #36395 | [Test-failure analysis with visual panels](#36395 (comment)) | 11 panels / 33 images; 19 omitted | 11 investigate | 43 URLs, 19,858 chars | | #36404 | [Test-failure analysis with visual panels](#36404 (comment)) | 14 panels / 40 images; 81 omitted | 14 investigate | 45 URLs, 23,779 chars | | #35846 | [Test-failure analysis with visual panels](#35846 (comment)) | 10 panels / 30 images; 9 omitted | 10 investigate | 43 URLs, 22,496 chars | | #36277 | [Test-failure analysis with visual panels](#36277 (comment)) | 7 panels / 19 images | 3 PR-caused, 4 investigate | 31 URLs, 18,355 chars | | #36170 | [Test-failure analysis with visual panels](#36170 (comment)) | 11 panels / 33 images; 8 omitted | 11 investigate | 44 URLs, 23,180 chars | | #35578 | [Test-failure analysis with visual panels](#35578 (comment)) | 12 panels / 36 images; 50 omitted | 12 investigate | 44 URLs, 25,443 chars | | #36672 | [Test-failure analysis with visual panels](#36672 (comment)) | 14 panels / 40 images; 9 omitted | 14 investigate | 45 URLs, 25,915 chars | | #31755 | [Test-failure analysis with visual panels](#31755 (comment)) | 12 panels / 36 images; 3 omitted | 12 investigate | 44 URLs, 22,728 chars | | #34637 | [Test-failure analysis with visual panels](#34637 (comment)) | 9 panels / 27 images; 81 omitted | 9 investigate | 43 URLs, 22,325 chars | | #35156 | [Test-failure analysis with visual panels](#35156 (comment)) | 2 panels / 6 images | 1 PR-caused, 1 investigate | 19 URLs, 11,911 chars | | #35885 | [Test-failure analysis with no visual failures](#35885 (comment)) | 0 panels / 0 images | No visual failures detected | 8 URLs, 4,239 chars | | #36577 | [Test-failure analysis with visual panels](#36577 (comment)) | 1 panel / 3 images | 1 investigate | 44 URLs, 21,768 chars | | #36212 | [Test-failure analysis with no visual failures](#36212 (comment)) | 0 panels / 0 images | No visual failures detected | 5 URLs, 5,982 chars | Each result contains one `Tests Failure Analysis` title and one merged review marker. Across 114 rendered panels, all 336 embedded image URLs returned HTTP 200. Seven panels were safely classified as likely PR-caused; no panel in this sample had enough exact evidence to be safely classified as likely unrelated, so the remaining 107 stayed at `Needs human investigation`. Another 260 comparisons were omitted safely by the comment limits. The latest eight-example batch was regenerated concurrently, and #36672, #31755, #34637, #35156, #35885, #36577, and #36212 were added afterward. The current [`review-tests-assets` head](f937993) retains the full asset history. The protected `copilot-pat-pool` environment rejects feature-branch `workflow_dispatch` runs before job execution. The live local-runner examples validate comment generation and asset publication, while the real gh-aw output replay validates the workflow post-step mutation without weakening that branch protection. ### Issues Fixed N/A - reviewer workflow enhancement. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: kubaflo <kubaflo@users.noreply.github.com> Copilot-Session: a280b482-e102-4ca0-9ff9-1cfe1946e21f Copilot-Session: d00747b7-96f3-4e7a-8dfb-e3a48db04b2d Copilot-Session: 478d195b-20f3-4bc6-aeed-f6aa88b55fda
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Description of Change Set `tools.github.integrity-proxy: false` for the regression-corpus scanner's deterministic pre-agent `gh` calls while retaining `min-integrity: approved` for every agent MCP read. The scanner continues to emit only validated structural IDs, labels, and merge SHAs; fetched prose never enters the agent prompt. The generated lock file is updated in the same commit. ### Root Cause The deterministic pre-activation pass inherited gh-aw's integrity proxy because the agent uses `min-integrity: approved`. The proxy redacted maintainer-authored attribution fields before `Find-RegressionFixPRs.ps1` could apply its own OWNER/MEMBER/COLLABORATOR checks, so [production run 29947778128](https://github.com/dotnet/maui/actions/runs/29947778128) completed successfully but emitted `usableCount: 0` and opened no draft PR. The two trust boundaries remain separate: the pre-pass applies its deterministic maintainer-association validation to live REST data, while the agent's GitHub MCP gateway still enforces approved integrity. ### Validation - 77 Pester tests passed - Production-shaped scan resolved fix PR #35768 to introducing PR #31931 at `af540589fc5a3b053cd8c08334d0ca5a0125451b`, source `pr-body`, with `usableCount: 1` - `gh aw compile regression-corpus-scanner --strict`: 0 errors, 0 warnings; recompilation parity confirmed - Generated `pre_activation` contains no integrity/CLI proxy injection; agent MCP remains `min-integrity: approved` - Vally 0.10 strict lint passed for the code-review eval corpus - Three independent adversarial reviewers found no significant issues (3/3 consensus) ### Issues Fixed N/A - fixes the regression-corpus scanner behavior observed in the linked production run. Co-authored-by: PureWeen <223556219+Copilot@users.noreply.github.com> Copilot-Session: e0da256b-eef3-41b1-b532-0d8557106c0c
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! Context: #24744 Context: #24952 ### Description of Change `Java.Interop.ExportAttribute` is annotated with `[RequiresUnreferencedCode]`, so every use of `[Export]` produces an IL2026 trim warning and depends on `Java.Interop.Export.dll` reflection at runtime. #24744 established the alternative: declare an abstract class in `src/Core/AndroidNative` and `override` it, which lets the Java Callable Wrapper generator emit the method — and its `@android.webkit.JavascriptInterface` annotation — statically. This adds `T:Java.Interop.ExportAttribute` to `eng/BannedSymbols.txt` so the pattern is enforced by RS0030 going forward, instead of relying on reviewers to catch it. The message points at `HybridJavaScriptInterface.java` as the working example: ``` T:Java.Interop.ExportAttribute;[Export] pulls in Java.Interop.Export dynamic features that are not trimming or AOT friendly. Declare an abstract class in src/Core/AndroidNative and override it instead, see src/Core/AndroidNative/maui/src/main/java/com/microsoft/maui/HybridJavaScriptInterface.java ``` Adding the ban flagged the one remaining offender, `RefreshViewWebViewScrollCapture.ScrollCaptureState.SetCanScrollUp()`: ``` src/Core/src/Platform/Android/RefreshViewWebViewScrollCapture.cs(209,4): error RS0030: The symbol 'Java.Interop.ExportAttribute' is banned in this project: [Export] pulls in Java.Interop.Export dynamic features that are not trimming or AOT friendly. ... ``` So it is fixed the same way #24744 did: a new `RefreshViewJavaScriptInterface` abstract class in the `maui.aar` Java sources, with `ScrollCaptureState` deriving from it. The `[RequiresUnreferencedCode("Java.Interop.Export uses dynamic features.")]` suppression on `SetCanScrollUp()` is no longer needed and is removed. Note the base type is deliberately an **abstract class** and not an interface. #24952 reverted `HybridJavaScriptInterface` from an interface back to a class because Java does not inherit method annotations from interfaces — the generated JCW silently lost `@android.webkit.JavascriptInterface` and the JavaScript bridge stopped working. The same applies here. The remaining `[Export]` usages in the repo are all `Foundation.ExportAttribute` (Apple), which is a different type and is unaffected by this ban. ### Issues Fixed None; this is a proactive lint rule plus the one cleanup it surfaced. ### Testing Verified locally by building `src/Core/src/Core.csproj` for `net10.0-android36.0`: - **Before the fix** — build fails with `error RS0030` at `RefreshViewWebViewScrollCapture.cs(209,4)`, confirming the new banned-symbol entry is actually enforced. - **After the fix** — `Microsoft.Maui.dll` builds clean, including the Gradle step that compiles the new Java file into `maui.aar`. No behavior change is expected at runtime: the exported Java method name is still `setCanScrollUp`, and `[JavascriptInterface]` remains on the C# override, matching the shipping `HybridWebViewHandler` pattern. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 7fb11a38-1848-4bb2-8b5c-7853dcad56bb
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## Summary - Restrict CI-fixer human-PR dedup searches to PR titles and bodies, and require an explicit ownership reference before stopping triage. - Add a shared CI-fix triage policy and hermetic Vally capability scenarios for ownership, stale failures, safe de-flaking, and attempt limits. - Regenerate both CI-fixer workflow locks with gh-aw v0.82.14. ## Testing - `gh aw compile .github/workflows/ci-status-fix.md` - `gh aw compile .github/workflows/ci-status-fix-net11.md` - `vally lint .github/skills/ci-fix --eval-spec .github/skills/ci-fix/tests/eval.vally.yaml --strict` - Focused actionlint validation of the generated locks (baseline gh-aw expression diagnostics excluded). --------- Co-authored-by: PureWeen <223556219+Copilot@users.noreply.github.com> Copilot-Session: d41db557-d1b5-45e0-ba14-f5a71cf61f0a Copilot-Session: 8eac356d-a7ec-4451-a4bc-ad6d2cd88023
… preview8) (#36803) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Description of Change The `release-readiness` skill's `Get-MilestoneHygieneChecks` derived the roll-forward milestone for a preview cycle by naively incrementing the preview number: ```powershell $expectedTitlesNext = @(".NET $major.0-preview$($cycleNum + 1)") ``` So surveying `preview7` told the release captain to create a **`.NET <major>.0-preview8`** milestone. **.NET does not ship a preview8.** The pre-release train is: ``` preview1 → preview2 → … → preview7 → rc1 → rc2 → GA ``` This surfaced during an **ad-hoc SR-lane run against the net11 `preview7` branch** — `Get-ReleaseReadiness.ps1 -SrBranch release/11.0.1xx-preview7` — where the report recommended creating `.NET 11.0-preview8`. The **automated preview lane** (`Get-PreviewReadiness.ps1` → `Test-PreviewMilestoneExists`) never had this bug: it validates only the *current* preview's own milestone and never derives a next-cycle title. This fix therefore hardens the SR lane's defensive preview-handling — see the reachability note in `SKILL.md` — rather than changing automated preview-lane behavior. #### Evidence (from this repo) | Major | Last preview | Then | |-------|--------------|------| | .NET 9 | `9.0.0-preview.7.24407.4` | `9.0.0-rc.1.24453.9` → `9.0.0-rc.2.24503.2` | | .NET 10 | `10.0.0-preview.7.25406.3` | `10.0.0-rc.1.25424.2` → `10.0.0-rc.2.25504.7` | Matching milestones: `.NET 10.0-preview7` (due 2025-08-01) → **`.NET 10.0-rc1`** (due 2025-08-21) → `.NET 10.0-rc2`. No `preview8` milestone exists in any major since .NET 6. There was also a **second, worse instance of the same bug**: in `candidate` mode the ordinal is incremented before deriving the *current* title too, so a candidate off `preview7` reported its own current cycle as `preview8` — a milestone that can never exist, which would render as a permanent spurious `BLOCKED` row. ### Changes `.github/skills/release-readiness/scripts/Get-ReleaseReadiness.ps1` - Add `Get-PreviewTrainMilestoneTitle` — a pure ordinal → milestone-title mapper (`1..7` → previews, `8` → `rc1`, `9` → `rc2`, `10+` → `$null`). `$script:FinalPreviewNumber` is the single constant to change if the cadence ever moves (.NET 5 shipped 8 previews; 7 has held since .NET 6). - Use it for **both** the current- and next-cycle titles. - Skip the next-cycle check entirely after `rc2` instead of inventing an `rc3`. - Widen the stale-milestone filter to `(preview|rc)\d+` — preview and rc are one continuous pre-release train, so a stale `rc1` is the same housekeeping debt as a stale `preview6`. **(Review refinement:** the filter now also excludes `$expectedTitlesNext`, so a slipped-but-upcoming `rc1` — the survey's own next-cycle target — isn't mislabeled "already-shipped debt", which had contradicted the "create it" advice from the next-cycle check.**)** - **(Review refinement)** `Get-MilestoneHygieneChecks` now emits `UNKNOWN` — rather than a silent `return @()` — for a nonsensical sub-1 preview ordinal (e.g. a `release/<major>.0.1xx-preview0` branch), preserving the lane's documented "never silently skips" contract. The legitimate past-`rc2` case stays a silent skip (GA has no milestone in this naming convention). `.github/skills/release-readiness/SKILL.md` - New **Pre-release train cadence (no `preview8`)** section with the tag/milestone evidence above. - Updated the `Milestone for next cycle` / `Stale open milestones` ship-check rows. - Documented that **`preview7` is the effective feature/API-lock gate**: because no eighth preview exists, work that misses the preview7 cut does not roll into "the next preview" — RC is normally API-locked, so in practice it slips to the next major. Reports on a preview7 branch should treat still-open public-API PRs as a *decide-now* item. - **(Review refinement)** Added a **reachability note** clarifying that the `preview→rc` mapping fires only in the SR lane when driven with a preview-shaped branch; an in-flight survey of a cut `release/*-rc1` branch produces no milestone checks at all (rc branch shapes are skipped by the parser). `.github/skills/release-readiness/scripts/Find-ReleaseReadinessTrackers.ps1` **(Review refinement — this file was originally reported as needing no change; that was wrong.)** Lane 4 does read `PreReleaseVersionIteration` from the survey ref rather than incrementing, and it does no-op once the label flips from `preview` to `rc`. But **the no-op is the bug, not the safeguard.** The same preview→rc discontinuity this PR fixes for milestone naming applies here: the pre-release train continues into `rc1`/`rc2`, so once the survey ref is bumped past the final preview the `PreLabel -eq 'preview'` guard stops matching for the entire rc window and **no rc tracker is ever proposed**. Verified against this repo rather than assumed: `release/10.0.1xx-rc1`'s `Versions.props` carries `rc`/`1`, and rc branches and tags use naming exactly parallel to previews (`release/<major>.0.1xx-rc<N>`, `<major>.0.0-rc.<N>.<build>`). - Lane 4 now recognises the rc phase explicitly and **warns** with an actionable message. - It deliberately does **not** emit an rc tracker, because the rest of the preview lane is still preview-only and an rc tracker would break downstream rather than help: `Get-PreviewReadiness.ps1`'s branch parser hard-`throw`s on any ref that isn't `release/<major>.0.1xx-preview<N>`, and rc branches/tags don't match the strict preview regexes — so Lane 3's in-flight detection and the already-cut / already-shipped dedup would never fire and the same rc candidate would be re-proposed forever. The inline comment records exactly what full rc support requires, so the follow-up is scoped rather than rediscovered. - The fix therefore targets the genuinely dangerous half: **the silence.** This case previously fell into the same `No active preview cycle` line a major legitimately in SR phase prints, so a release captain could not distinguish "nothing to do" from "rc1 needs a tracker and you won't get one". ### Tests Added 25 assertions (**M17–M23**, plus **M20b / M20c / M20d / M22c** from review) to `Test-ReleaseReadiness.ps1`: - `preview7` → next cycle is `rc1`, and explicitly **not** `preview8` - `preview7` + `rc1` both present → no check emitted - `preview6` → still `preview7` (cadence below 7 unchanged) - candidate mode off `preview7` → current `rc1`, next `rc2` - **(M20b)** candidate off `preview7` with `rc1` *missing* → current-cycle `BLOCKED` naming `rc1` (not `preview8`) — the negative-case guard for the newly-reachable rc current-cycle check; mutation-verified to catch a mutant that neuters `BLOCKED` for every `-rc\d+$` title - **(M20c / M20d)** `preview0` ordinal → `UNKNOWN`; past-`rc2` ordinal → silent skip (0 checks) - `rc2` → no roll-forward check (GA follows) - **(M22b / M22c)** a stale `rc2` (neither current nor next) is flagged; a slipped next-cycle `rc1` is **not** flagged as stale debt - pure-function mapping for ordinals 0, 1, 7, 8, 9, 10 and major-number substitution Subsequent adversarial-review rounds added further coverage and fixes: - **(M22 / M22b)** negative coverage for Check 3b — it must stay silent when the past-due milestone is not the roll-forward target. - **`Get-PastDueOpenMilestones`** — extracted so Check 3 and Check 3b cannot drift apart on what "past due" means. - **`Sort-Object -Stable`** — PowerShell's default `Sort-Object` is *not* stable (ties are only preserved with `-Top`/`-Bottom`/`-Stable`); since sorting now happens before each caller's discriminator, stability is what makes the new ordering equivalent to the old. Divergence only begins around 17 elements, because .NET falls back to a stable insertion sort below ~16 — so the guarding fixture is padded past that threshold. - **(M22e / M22f)** ordering is now pinned in two separate scenarios because neither catches the other's mutant: M22e uses all-tied `due_on` (kills the missing-`-Stable` mutant but cannot see direction), M22f uses distinct dates (kills `-Descending`). - **Dual-tracker E2E gate** — this assertion ran against the live repo and had two independent preconditions (branch cut *and* survey ref bumped) but only checked the first, so it failed for the whole legitimate interval between them. It also derived its expected tracker as `shipped+2`, i.e. it was asserting the very `preview8` naming this PR removes. It now reads the survey ref's actual iteration and derives the expectation from it. - **(rc window)** synthetic scenario for the Lane 4 fix above, **plus a negative control** so a naive "always warn" cannot satisfy it. ``` Passed: 1124 Failed: 0 ``` Every fix is **mutation-verified** — reverting each one fails its own assertion and no others. Two mutants were checked in both directions for the rc-window change (reverting to silence fails the warning assertions; forcing the condition to `$true` fails the negative control). One surviving mutant is left deliberately: `-lt` → `-le` on the grace cutoff, which requires exact datetime equality to distinguish and is pre-existing. The 5 pre-existing milestone scenarios that could have regressed (M11, M12, M13, M15) all still pass — notably M15, which asserts an `rc` *branch shape* is still skipped (that's a separate, intentional behaviour and out of scope here). ### Issues Fixed None filed — found during an ad-hoc SR-lane run against the net11 `preview7` branch (`Get-ReleaseReadiness.ps1 -SrBranch release/11.0.1xx-preview7`). --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: kubaflo <kubaflo@users.noreply.github.com> Copilot-Session: 63594848-5aab-4ffa-8cb0-a64823163037 Copilot-Session: d00747b7-96f3-4e7a-8dfb-e3a48db04b2d Copilot-Session: 7f87d6b9-cc21-4952-81c7-787a8585ce11
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! Updates `github-merge-flow-release-11.jsonc` to point the `net11.0` merge flow at `release/11.0.1xx-preview7` now that preview6 has been cut. ## Changes - **`github-merge-flow-release-11.jsonc`**: `MergeToBranch` updated from `release/11.0.1xx-preview6` → `release/11.0.1xx-preview7` --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: PureWeen <5375137+PureWeen@users.noreply.github.com>
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 36883Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 36883" |
|
Azure Pipelines: Successfully started running 1 pipeline(s). There may be pipelines that require an authorized user to comment /azp run to run. |
There was a problem hiding this comment.
Pull request overview
This pull request reverts the behavior changes from #35632 on the .NET 10 servicing line, restoring the prior cross-platform behavior of auto-tinting SwipeItem.IconImageSource for contrast/legibility (and removing the associated test artifacts and baselines that were added to validate the newer behavior).
Changes:
- Restores prior icon tinting behavior on Android and iOS by applying contrast-based tinting to swipe item icons again.
- Reverts Windows swipe item icon mapping back to
ToIconSource()(and removes the async icon loading helper introduced in #35632). - Removes the Issue23074 HostApp page, shared UI test, and the added SVG test asset used to validate the now-reverted behavior.
Reviewed changes
Copilot reviewed 6 out of 23 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/Core/src/Handlers/SwipeItemMenuItem/SwipeItemMenuItemHandler.Android.cs | Reverts to applying a color filter based on GetTextColor() for swipe item icon drawables. |
| src/Core/src/Handlers/SwipeItemMenuItem/SwipeItemMenuItemHandler.iOS.cs | Reverts to template rendering + tinting for swipe item icons rather than preserving original raster colors. |
| src/Core/src/Handlers/SwipeItemMenuItem/SwipeItemMenuItemHandler.cs | Reverts Windows source mapping to use ToIconSource() directly instead of async image-service loading. |
| src/Core/src/Handlers/SwipeItemMenuItem/SwipeItemMenuItemHandler.Windows.cs | Removes the previously-added async LoadFileIconAsync helper and related usings. |
| src/Controls/tests/TestCases.HostApp/Issues/Issue23074.cs | Removes the HostApp repro/validation page added for the reverted behavior. |
| src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue23074.cs | Removes the screenshot-based UI test added for the reverted behavior. |
| src/Controls/tests/TestCases.HostApp/Resources/Images/cancel_red.svg | Removes the test SVG asset added for the reverted behavior. |
| if (item.Source is IFontImageSource fontImageSource && fontImageSource.Color != null) | ||
| button.TintColor = fontImageSource.Color.ToPlatform(); | ||
| else | ||
| { | ||
| button.TintColor = null; | ||
| var tintColor = item.GetTextColor(); | ||
| if (tintColor != null) | ||
| button.TintColor = tintColor.ToPlatform(); | ||
| } |
There was a problem hiding this comment.
Thanks — this PR is a deliberate revert of #35632, so it intentionally restores the prior SwipeItem icon-tint code. You're right that the restored else branch only assigns button.TintColor when GetTextColor() is non-null, so a stale tint can persist — but that's the pre-#35632 behavior being restored, not a defect introduced by this revert. #35632 had actually addressed exactly this (it used AlwaysOriginal rendering for raster images and set TintColor = null on the non-font path); since that change is what's being reverted, the unconditional/explicit-reset handling should ride along with a forward re-fix of #35632 rather than be layered onto the revert, so this PR cleanly restores the known-prior state.
|
Closing in favor of #36887. This branch was cut from #36887 applies the same revert directly on top of |
…ross platforms (#35632)" (#36887) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! > Supersedes #36883, which was branched off `main` while targeting `inflight/candidate`. That mismatch dragged in 42 unrelated `main`-only commits and produced four spurious conflicts in files that have nothing to do with `SwipeItem`. This branch is built directly on `inflight/candidate`, so it is a clean single-commit diff. ### Issue Details This reverts #35632 ("Fix SwipeItem IconImageSource color handling and rendering across platforms") from the .NET 10 servicing line. #35632 stopped auto-tinting `SwipeItem.IconImageSource` for PNG/SVG sources, so those icons now render in their own colors instead of a contrast color derived from the item background. It shipped in 10.0.90 (SR9) and is causing #36766 — an SVG icon whose fill is `#212121` now renders black on a black swipe item in dark mode, i.e. effectively invisible. The change is a reasonable direction, but it is too breaking for a servicing release: - **It removes a legibility guarantee with no replacement.** `GetTextColor()` picks white or black from background luminosity. #35632 removed that for PNG/SVG but left it in place for the item's label text, so the text is still contrast-corrected while the icon is not. - **There is no opt-in.** #23074 was labelled `proposal/open` and asked for *more configuration*; what shipped was a behavior change with none. An affected app's only options today are pinning to 10.0.80 or re-authoring every SVG per theme. - **It compounds with #36271** (also SR9), which makes `BackgroundColor` correctly follow `AppThemeBinding`. Before SR9 the stale light background accidentally preserved contrast; together the two changes produce black-on-black. - **The prior behavior was the Xamarin.Forms behavior**, not an inconsistency — Xamarin tinted every icon unconditionally on both Android ([`SwipeViewRenderer.cs#L858`](https://github.com/xamarin/Xamarin.Forms/blob/main/Xamarin.Forms.Platform.Android/Renderers/SwipeViewRenderer.cs#L858)) and iOS ([`SwipeViewRenderer.cs#L713`](https://github.com/xamarin/Xamarin.Forms/blob/main/Xamarin.Forms.Platform.iOS/Renderers/SwipeViewRenderer.cs#L713)). ### Description of Change `git revert` of c78acfe, restoring the previous behavior on all platforms: - **Android** — `SetColorFilter(GetTextColor(), SrcAtop)` applied to every drawable again - **iOS/Mac** — `AlwaysTemplate` rendering mode on every image again, with `TintColor = fontImageSource.Color ?? GetTextColor()` - **Windows** — `MapSourceAsync` back to `ToIconSource()` (`BitmapIconSource`, whose `ShowAsMonochrome` defaults to `true`); the `LoadFileIconAsync` helper is removed The `Issue23074` host-app page, shared test, `cancel_red.svg` and the `SwipeItemFontAndSvgIconsRenderCorrectly` snapshots are removed with it, and the SwipeView snapshots are restored to their pre-#35632 baselines. The revert is scoped strictly to #35632. `MapVisibility` on the Windows handler — added on `inflight/candidate` after #35632 — is untouched. **Conflict resolution note:** `TestCases.iOS.Tests/snapshots/ios/VerifyCollectionViewContentWithIconImageSwipeItem.png` conflicted because #36202 re-saved it for iOS 18 after #35632 landed. That test's swipe item has `BackgroundColor = #6A5ACD` (luminosity ≈ 0.40 → white), so with this revert `groceries.png` is tinted solid white again and the pre-#35632 baseline is the correct content. If iOS 18 CI shows drift unrelated to the tint, this one snapshot may need a re-save from the CI artifact. ### Follow-up The behavior change itself is good and should ship — just in .NET 11 rather than servicing, paired with an explicit opt-in API so users get a real migration path instead of a silent rendering change in a patch release. That is #36884, which keeps the #35632 behavior and adds `SwipeItem.IconColor`. ### Issues Fixed Fixes #36766 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: cb2a11ab-30ba-4020-836a-3acccb5f58cc
Note
Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!
Issue Details
This reverts #35632 ("Fix SwipeItem IconImageSource color handling and rendering across platforms") from the .NET 10 servicing line.
#35632 stopped auto-tinting
SwipeItem.IconImageSourcefor PNG/SVG sources, so those icons now render in their own colors instead of a contrast color derived from the item background. It shipped in 10.0.90 (SR9) and is causing #36766 — an SVG icon whose fill is#212121now renders black on a black swipe item in dark mode, i.e. effectively invisible.The change is a reasonable direction, but it is too breaking for a servicing release:
GetTextColor()picks white or black from background luminosity. Fix SwipeItem IconImageSource color handling and rendering across platforms #35632 removed that for PNG/SVG but left it in place for the item's label text, so the text is still contrast-corrected while the icon is not.proposal/openand asked for more configuration; what shipped was a behavior change with none. An affected app's only options today are pinning to 10.0.80 or re-authoring every SVG per theme.BackgroundColorcorrectly followAppThemeBinding. Before SR9 the stale light background accidentally preserved contrast; together the two changes produce black-on-black.SwipeViewRenderer.cs#L858) and iOS (SwipeViewRenderer.cs#L713).Description of Change
Straight
git revertof c78acfe, restoring the previous behavior on all platforms:SetColorFilter(GetTextColor(), SrcAtop)applied to every drawable againAlwaysTemplaterendering mode on every image again, withTintColor = fontImageSource.Color ?? GetTextColor()MapSourceAsyncback toToIconSource()(BitmapIconSource, whoseShowAsMonochromedefaults totrue); theLoadFileIconAsynchelper is removedThe
Issue23074host-app page, shared test,cancel_red.svgand theSwipeItemFontAndSvgIconsRenderCorrectlysnapshots are removed with it, and the SwipeView snapshots are restored to their pre-#35632 baselines.Conflict resolution note:
TestCases.iOS.Tests/snapshots/ios/VerifyCollectionViewContentWithIconImageSwipeItem.pngconflicted because #36202 re-saved it for iOS 18 after #35632 landed. That test's swipe item hasBackgroundColor = #6A5ACD(luminosity ≈ 0.40 → white), so with this revertgroceries.pngis tinted solid white again and the pre-#35632 baseline is the correct content. If iOS 18 CI shows drift unrelated to the tint, this one snapshot may need a re-save from the CI artifact.Follow-up
The behavior change itself is good and should ship — just in .NET 11 rather than servicing, paired with an explicit swipe-item icon color / tint opt-out API so users get a real migration path instead of a silent rendering change in a patch release. Tracking that separately for
net11.0.Issues Fixed
Fixes #36766