[automated] Merge branch 'main' => 'net11.0' - #36139
Merged
Merged
Conversation
) > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Description of Change Several request-interception device tests were running an `[InlineData("https://echo.free.beeceptor.com/...")]` row on Windows and Android Helix queues even though that external service is known to be flaky (tracked in #33927). The sibling tests in the same files already skip that scenario; these four were missed: - `BlazorWebViewTests.RequestsCanBeInterceptedAndCustomDataReturnedForDifferentHosts` - `BlazorWebViewTests.RequestsCanBeInterceptedAndCancelledForDifferentHosts` - `BlazorWebViewTests.RequestsCanBeInterceptedAndCaseInsensitiveHeadersRead` - `HybridWebViewTests_Interception.RequestsCanBeInterceptedAndCancelledForDifferentHosts` Reflection on the built `Microsoft.Maui.Controls.DeviceTests.dll` (net10.0-windows10.0.19041.0) confirmed each of these methods had a `Microsoft.Maui.TheoryAttribute` with **no** `Skip` and the `https://echo.free.beeceptor.com/` `InlineData` attached — they would attempt a real outbound TLS request from the Helix worker whenever interception did not fire. ### Fix Split the single `[Theory]` into two: one inside the `#if !ANDROID && !WINDOWS` block (paired with the `app://echoservice/` row) and one inside the `#if !IOS && !MACCATALYST` block carrying `Skip = "Flaky due to external service dependency (echo.free.beeceptor.com). See https://github.com/dotnet/maui/issues/33927"` (paired with the `https://` row). This matches the convention already used by the three other sibling methods (`CustomDataReturned`, `HeadersAdded`, `CaseInsensitiveHeadersRead` in `HybridWebViewTests_Interception.cs`). Importantly, **iOS / MacCatalyst coverage is preserved** — only the `https://` rows are skipped. The `app://echoservice/` rows are fully self-contained (the OS cannot resolve the `app://` scheme, so the request never touches the network — it is satisfied entirely by the `WebResourceRequested` handler inside the test). ### Per-TFM safety check The custom `Microsoft.Maui.TheoryAttribute` has `AllowMultiple = false`, and the `#if` guards make the two `[Theory]` attributes mutually exclusive across every TFM in `MauiDeviceTestsPlatforms`: | TFM | `[Theory]` (app://) | `[Theory(Skip)]` (https://) | |---|---|---| | net10.0-android | excluded | included | | net10.0-windows10.x | excluded | included | | net10.0-ios | included | excluded | | net10.0-maccatalyst | included | excluded | ### Issues Fixed Related to #33927. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Description of Change Restricts `/review rerun` eligibility so PRs are only queued for rerun when there is new PR-author activity after the latest AI Summary or previous rerun checkpoint: - new non-command comments from the PR author - new commits / head changes Reviewer or maintainer reminder comments no longer satisfy the rerun evidence check. ### Issues Fixed Prevents `/review rerun` from applying `s/agent-ready-for-rerun` when only a reviewer/maintainer comment was added after the latest AI Summary. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Description of Change Updates the `Skill Validation Results` PR comment to match the visual style used by AI Summary and Test Failure Review comments: - stable marker plus `## Skill Validation Results` title - PR author/commit context - status badges for overall, static checks, LLM evaluation, skills, and agents - a single expandable session with commit metadata - existing static-check and LLM-evaluation details preserved inside the session ### Issues Fixed No issue filed. ### Validation - Extracted and syntax-checked the `actions/github-script` post-comment JavaScript with `node --check` - `git diff --check` --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## Summary Adds a deterministic, evidence-backed release-readiness skill that produces a single "Is `release/X.Y.Zxx-srN` (or preview) ready to ship?" report for .NET MAUI release branches — both **Servicing Releases (SR)** and **Previews**, in both **in-flight** and **candidate** (pre-cut) modes. Supersedes #35754. ## What it does `Get-ReleaseReadiness.ps1` walks the SR branch, classifies open `regressed-in-*` issues against branch contents, computes the source-PR list (handling cherry-pick number swaps + non-main forward-flow), and rolls up an "is this ready to ship?" verdict with a **Blocking** summary hoisted to the top of the report. Posts/refreshes a single `[Release Readiness]` GitHub tracking issue per release lane (idempotent via a semantic hash marker — only reposts when something meaningfully changed). See **[issue #35876 (SR8)](#35876 for a live example. ## Ship-readiness checks A release captain sees these surface as 🟢 READY / 🟡 WATCH / 🔴 BLOCKED / ⚪ UNKNOWN rows. All BLOCKED rows roll up into the **Blocking** summary at the top. | Check | Catches | |-------|---------| | **Versions.props bump** | SR cycle hasn't been bumped on the SR branch | | **Versions.props servicing flip** | `PreReleaseVersionLabel=servicing` + `StabilizePackageVersion=true` not applied — branch silently builds prerelease packages | | **Bug template lists SR version** | Users can't file bugs against the new version | | **Main bumped to next SR cycle** | Post-SR-cut PRs on main would falsely claim to ship in the SR being shipped | | **BAR default-channel mapping** | SR branch not wired to `.NET <band> SDK` in BAR — caught the real SR8 outage | | **BAR build for SR HEAD** | No published build at the SR HEAD commit | | **Milestone for current cycle** | Fixed issues have nowhere to land | | **Milestone for next cycle** | Open issues can't roll forward when current ships | | **Stale open milestones** | Already-shipped releases accumulating untriaged issues (scoped to same major + same cycle type, 7-day grace) | | **CI Failure Scanner signals** | Fresh ci-scan issues filed in the last 24h | | **Known Build Errors** | Open KBE issues that may explain background CI noise | Each check that needs external tooling (darc, gh, milestone API) degrades to **UNKNOWN** with the exact verification command embedded — the report never silently skips. ## Expected ship date Header line surfaces the deadline. Cadence is patch-aware: - `PatchVersion` ends in 0 (`80`, `90`, `100`…) or `0` (previews) → 2nd Tuesday of the month - Anything else (`81`, `82`, `91`…) → **ASAP** hotfix, no cadence ## Custom agent `.github/agents/release-readiness-agent.agent.md` wraps the skill — handles regression-label confirmation, runs the script, then uses **WorkIQ** + **maestro MCP** to: - Patch UNKNOWN BAR rows live (e.g. when darc isn't on CI's PATH) - Add narrative context for `rejected-from-sr` PRs (chat history, review feedback) - Present the final READY / Conditionally Ready / Not Ready verdict with citations ## Testing ```bash pwsh .github/skills/release-readiness/tests/Test-ReleaseReadiness.ps1 # 447 pass / 0 fail ``` Dogfooded live against SR7 + SR8 + the .NET 11 preview lane. Caught real-world bugs: - **SR8** missing from BAR default-channel mappings (verified via `maestro_default_channels` MCP) - `.NET 10 SR6` + `.NET 10 SR7` milestones open with 76 + 63 open issues, past due - `.github/ISSUE_TEMPLATE/bug-report.yml` missing `10.0.80` entry ## Methodology gotchas (documented in `references/methodology.md`) 1. **Cherry-pick number swap** — SR backports get NEW PR numbers; can't naively grep source PR numbers 2. **Timeline cross-references** — `closedByPullRequestsReferences` returns empty for most MAUI issues; must walk `gh api .../issues/N/timeline` cross-referenced events 3. **Forward-flow / non-main merges** — a fix can merge into `inflight/current` only, not `main` (real example: PR #35609) ## Files - `.github/skills/release-readiness/SKILL.md` — skill entry point + reference docs - `.github/skills/release-readiness/scripts/Get-ReleaseReadiness.ps1` — main orchestrator (deterministic, no MCP) - `.github/skills/release-readiness/tests/Test-ReleaseReadiness.ps1` — 447-assertion test suite - `.github/skills/release-readiness/references/methodology.md` — gotchas and patterns - `.github/agents/release-readiness-agent.agent.md` — MCP-enriched agent wrapping the skill --------- Co-authored-by: bot <bot@test> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: VSC Agent <vsc-agent@example.com>
…35942) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## Summary Migrates the `skill-validation.yml` workflow from the legacy `dotnet/skills` binary (`skill-validator check` + `skill-validator run`) to **[@microsoft/vally-cli@0.6.0](https://github.com/nicknow-ms/vally)**. All 5 skill-eval suites are ported and validated green in CI. ## What Changed ### Workflow (`skill-validation.yml`) - Replaced `skill-validator` install/check/run steps with `vally lint --strict` and `vally run --eval-spec` - Added **hermeticity negative-control gate** that verifies the sandbox doesn't have unauthorized network access (rate-limit auth detection) - Added `workflow_dispatch` manual trigger with `skills` and `runs` inputs for on-demand evaluation - Changed fixture fetch depth from `--depth=1` to `--depth=2` so `git diff HEAD^ HEAD` works in worktree environments - Removed all `skill-validator` references and legacy `eval.yaml` files ### Eval Specs Ported (all in `.github/skills/<skill>/tests/`) | Skill | File | Stimuli | Status | |-------|------|---------|--------| | code-review | `eval.capability.vally.yaml` | 9 capability scenarios | ✅ 9/9 | | code-review | `eval.vally.yaml` | 2 regression scenarios | ✅ 2/2 | | code-review | `hermeticity.vally.yaml` | 1 negative control | ✅ | | agentic-labeler | `eval.vally.yaml` | 3 labeling scenarios | ✅ | | try-fix | `eval.vally.yaml` | 2 fix scenarios | ✅ | | verify-tests-fail-without-fix | `eval.vally.yaml` | 2 verification scenarios | ✅ | | evaluate-pr-tests | `eval.vally.yaml` | 2 evaluation scenarios | ✅ | ### Key Design Decisions - **Structural graders** (output-matches, output-not-contains) verify hard behavioral requirements (e.g., never approve via API, verdict markers present) - **LLM prompt graders** (scale_1_5) assess quality and depth with calibrated thresholds - Regression stimuli use **frozen git worktrees** pinned to known-regressing commits — no network calls, fully reproducible - Capability stimuli target **real merged PRs** to test against actual code review scenarios ## Validation Final CI run [#27635665319](https://github.com/dotnet/maui/actions/runs/27635665319): **11/11 stimuli pass, 0 failures**. Iteratively validated across 9 CI runs, fixing: - Fixture fetch depth (parent commit needed for `git diff`) - Structural floor regex (added 🔴 marker, broadened to accept `Verdict`/`Finding`) - Merged-PR prompt engineering (agents short-circuit reviews on merged PRs) - Environment constraints (Vally sandbox lacks GH_TOKEN — adjusted rubrics accordingly) - LLM judge threshold calibration (structural graders verify correctness; LLM judges assess quality) ## Removed - All `eval.yaml` files (legacy skill-validator format) - `skill-validator` binary installation steps - `--allow-repo-traversal` flag usage (Vally worktrees provide full repo access natively) --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…compile all to v0.79.8 (#35951) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## Summary Adds top-level `environment: gh-aw-agents` gating to the 4 gh-aw workflows that have write capabilities or uncapped inference spend, following the [gh-aw best practice](https://github.github.com/gh-aw/reference/cost-management/): *"Gate any write-capable or spendy agentic workflow behind such an environment."* Uses a **single shared environment** (`gh-aw-agents`) since the AzDO federation secrets are also used by `review-trigger.yml`, so per-workflow secret isolation isn't achievable. Also brings **all 7** gh-aw workflow lock files to the current compiler (v0.79.8 / AWF 0.27.2). **Validated:** triggered `ci-status-main` on this branch — activation ✅, agent job running ✅ (confirms `COPILOT_GITHUB_TOKEN` from environment is accessible). ## Changes ### Commit 1: Environment gating + deprecated field migration | Workflow | Write surface | |----------|---------------| | `rerun-review-scanner` | Labels, reactions, AzDO pipeline triggers, federation secrets | | `ci-status-main` | Creates up to 5 tracking issues/run | | `ci-status-net11` | Creates up to 5 tracking issues/run | | `daily-repo-status` | Creates issues + closes older ones | All 4 now use `environment: gh-aw-agents`. Also migrates the deprecated `max-effective-tokens: -1` → `max-ai-credits: -1` in both CI scanner workflows. ### Commit 2: Lock freshness Recompiles `agentic-labeler.lock.yml` and `copilot-review-tests.lock.yml` to current gh-aw v0.79.8 / AWF 0.27.2. No source `.md` changes — lock-only refresh. ### Commit 3: Fix copilot-evaluate-tests + recompile Fixes `workflow_dispatch.inputs.pr_number.required: true` → `false` — v0.79.8 correctly rejects `required: true` when `slash_command:` is also configured (auto-dispatch can't fill required inputs). The workflow already falls back to `github.event.issue.number` from slash command context. ## Intentionally NOT gated | Workflow | Reason | |----------|--------| | `agentic-labeler` | Uses `roles: all` for community auto-labeling; gating would require approval per issue/PR | | `copilot-evaluate-tests` | Comment-only (max 1), already role-gated to `[admin, maintain, write]` | | `copilot-review-tests` | Same as above | ## Environment setup (already done ✅) The `gh-aw-agents` environment has been created with: - ✅ `COPILOT_GITHUB_TOKEN` — Copilot inference auth - ✅ `AZDO_TRIGGER_TENANT_ID` — AzDO Workload Identity Federation - ✅ `AZDO_TRIGGER_CLIENT_ID` — AzDO Workload Identity Federation - No required reviewers (scheduled automation would stall) - No branch restrictions yet (can be added post-merge for `main` + `net11.0`) --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## Problem The milestone-drift automation (`Fix-MilestoneDrift.ps1`) maps a commit found on an SR release branch to a milestone using **only the branch name** — `release/10.0.1xx-sr7` → `.NET 10 SR7`. But a single SR release branch ships **many servicing drops** over its lifetime (`10.0.70` = SR7, `10.0.71` = SR7.1, `10.0.72` = SR7.2, …), so the base SR is too coarse. A revert/hotfix that lands **after** the base SR shipped actually goes out in a later sub-patch. Milestoning it as the base SR is wrong — and can even **downgrade** an already-correct SR7.1 issue back to SR7. ### Concrete case that motivated this - PR #35694 is a backport to `release/10.0.1xx-sr7`; its commit is contained only in tag `10.0.71` → it ships in **SR7.1**. - It directly links the issue via `Fixes #35584`. - Before this change the script resolved #35694 → **SR7** (branch name), which would *downgrade* issue #35584 from SR7.1 → SR7. ## Root cause `Find-ReleaseBranchForCommit` resolved the milestone via `ConvertBranchToMilestone` (branch-name only), which has no notion of sub-patches. ## Fix (general — no special-casing) Add `Get-RefinedReleaseMilestone`: for a commit found on an **SR** branch, resolve the milestone from the **earliest SR-family tag** (`X.0.{sr}{sub}`) that actually contains the commit (git ancestry). Rules: - **Earliest release wins** — return the earliest family tag that contains the commit. - If no family tag contains it yet (the drop isn't tagged), use the **next sub-patch** after the latest shipped family tag — **clamped to the SR family** so it never crosses into the next SR (an exhausted SR7 at `.79` falls back to base SR7, never predicts SR8). - **Non-SR** milestones (preview/rc/GA) are returned unchanged. It's wired into both match paths of `Find-ReleaseBranchForCommit`. The PR-number grep fallback now captures the **oldest** on-branch SHA (`--reverse`, so a later revert that re-mentions `(#NNN)` can't hijack the result) and is hardened against stderr noise (`2>$null` + strict 40-hex SHA filter). Result: #35694 → **SR7.1**, so its existing `Fixes #35584` link marks the issue **SR7.1**. The existing earliest-release-wins guard reconciles the issue regardless of merge order. Note: PR #35625 (the same revert on `inflight/current`) intentionally stays **SR9** — a PR's milestone tracks the physical branch it merged into; the *issue* converges to the earliest customer-facing release (SR7.1). ## Verification - ✅ Dry-run #35694 → `.NET 10 SR7.1` (was SR7); issue #35584 already-correct (no downgrade). - ✅ Regression dry-runs unchanged: #34620 → SR6, #35016 → SR6, #30132 → preview3. - ✅ Pester suite: **162 passed, 0 failed** (9 new unit tests for the helper, incl. the family-boundary clamp). ## Review Reviewed with three independent models (GPT-5.5, Gemini 3.1 Pro, Claude Opus 4.8). Consensus on correctness and contained blast radius (refinement only ever moves *within* one SR family). Their concrete findings — boundary clamp, stderr hardening, oldest-match grep, and a dead parameter — were all addressed in this PR. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## Summary Follow-up to #35951 — extends `environment: gh-aw-agents` gating to the **remaining 4 workflows** that were not included in the initial PR: | Workflow | Type | Change | |----------|------|--------| | `agentic-labeler.md` | gh-aw | Added `environment: gh-aw-agents` | | `copilot-evaluate-tests.md` | gh-aw | Added `environment: gh-aw-agents` | | `copilot-review-tests.md` | gh-aw | Added `environment: gh-aw-agents` | | `review-trigger.yml` | Regular GHA | Added `environment: gh-aw-agents` to `trigger-review` job | ## Why After #35951 merged, repo-level secrets (`COPILOT_GITHUB_TOKEN`, `AZDO_TRIGGER_TENANT_ID`, `AZDO_TRIGGER_CLIENT_ID`) were deleted in favor of environment-scoped secrets on the `gh-aw-agents` environment. These 4 workflows need the `environment:` reference to access those secrets. ## Details - All 3 gh-aw workflow locks recompiled with `gh aw v0.79.8` - `environment: gh-aw-agents` verified on agent + safe-outputs + threat-detection jobs in all lock files - `review-trigger.yml` is a regular GHA workflow — environment added at job level, no compile needed - Pre-existing compile warnings (agentic-labeler `pull_request_target`, copilot-evaluate-tests `slash_command` + `bots:`) are unchanged and intentional Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… as resolved (#35895) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Summary When a maintainer comments `/review`, `/review rerun`, or `/review tests` on a PR, the command comment lingers and clutters the conversation. This change **hides the command comment as resolved** (collapses it) **once the command is recognized and the commenter is authorized** (i.e. once we accept and act on it). Unauthorized or invalid attempts are left fully visible. ### Why hide instead of delete? The rerun scanner reconstructs review/rerun state by replaying the PR's comment history through the **REST list endpoint** (`Resolve-RerunEligibility.ps1`, `Query-RerunReadyPRs.ps1`, `Get-LatestRerunCommentBefore`). **Deleting** the command comments would erase that durable checkpoint — re-qualifying unchanged commits and dropping `--branch`/`--platform` options on later reruns. Minimizing (GraphQL `minimizeComment(classifier: RESOLVED)`) collapses the comment in the web UI but **keeps it in the REST comment history**, so the scanner keeps working. This addresses the data-loss findings from review without losing the decluttering benefit. ### Changes | Command | Workflow | Where it's hidden | |---|---|---| | `/review` | `review-trigger.yml` (`trigger-review`) | after the AzDO pipeline is triggered (`trigger_azdo == success`) | | `/review rerun` | `review-trigger.yml` (`mark-rerun-ready`) | after eligibility resolution, only when `eligible == 'true'` | | `/review tests` | `copilot-review-tests.md` (gh-aw) | pre-activation step | All three call `minimizeComment(input: { subjectId: <comment node_id>, classifier: RESOLVED })`. **`review-trigger.yml`** - `trigger-review`: hides the `/review` comment as the last step, gated on `steps.trigger_azdo.outcome == 'success'` so a lock-skip or failed trigger leaves the command (and its `--branch`/`--platform` options) visible for retry. The job already has `issues: write`. - `mark-rerun-ready`: hides the `/review rerun` comment **after** `Resolve-RerunEligibility.ps1` runs and only when a rerun was actually triggered (`eligible == 'true'`). Ineligible reruns keep the comment fully visible. **`copilot-review-tests.md` (gh-aw)** - Keeps `on.permissions: issues: write` so the deterministic pre-activation job token can minimize the comment (the AI agent job stays read-only). - The `github-script` pre-activation step minimizes the `/review tests` comment only when the command is exactly `/review tests` (`should_run`), the event is `created` (not `edited`), **and** the commenter is an authorized collaborator (`write`/`maintain`/`admin`). - Recompiled `copilot-review-tests.lock.yml` in the same commit (gh-aw v0.77.5). `frontmatter_hash` updated; `body_hash`, the concurrency block, and the read-only agent-job permissions are unchanged. ### Token / permissions No special token is required. Minimizing uses the same `issues: write` scope deletion did, via the default `github.token`. (Minimizing is the same moderation tier as the previous deletion — if the token could delete the comment, it can minimize it.) ### Safety - **No double-hide** — each command activates exactly one minimize path (`/review tests` is gated on the exact-match that `review-trigger.yml` explicitly skips). - Minimizing only runs on `issue_comment` `created` events (never `workflow_dispatch`, never `edited`). - A failed minimize emits a `::warning::` and never fails the review/rerun/tests trigger. - History is preserved: the REST comment list still returns minimized comments, so the rerun scanner and option/checkpoint recovery are unaffected. ### Validation - `gh aw compile` → 0 errors / 0 warnings; lock diff verified (only the step body + `frontmatter_hash` change; concurrency intact; agent job still `issues: read`). - `review-trigger.yml` and the regenerated lock parse as valid YAML. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…anches from the tracker matrix (#35971) > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! Follow-up to #35807. Two independent release-readiness fixes. --- ## Fix 1 — Surface p/0-labelled PRs as Preview release blockers ### Summary The Preview readiness engine (`Get-PreviewReadiness.ps1`) only treated **p/0 issues** as release blockers. **p/0-labelled PRs** targeting a preview/candidate branch were silently bucketed into the generic "Release branch PRs" WATCH count and rendered as "Needs review or triage" rows — never hoisted, never blocking. The root cause is structural: the p/0 blocker path used `gh issue list --label p/0`, which **by design never returns PRs**. So p/0 PRs were invisible to the blocker logic. This was observed live on the **net11.0 preview6** tracker (#35866), where #34758, #35626, and #34600 (all `p/0`, base `net11.0`) appeared only as generic WATCH rows instead of blockers. ### What changed Carves p/0-labelled PRs out of the generic human-PR bucket — the label data is **already fetched** by `Get-OpenPullRequests`, so no extra API call — and: - adds a **BLOCKED `P/0 release-branch PRs`** check (parallel to the p/0-issues check) so the overall verdict turns red when one is open; - itemizes each p/0 PR as a **`🔥 P/0 PR`** row in the hoisted **🔴 High-priority items** section (with base ref + age + per-PR next action); - **excludes** the new check from the **🔴 Blocking** summary (its PRs are already enumerated in the hoist) — exactly matching the p/0-issues treatment; - updates the WATCH note + hoist header/intro text from 3 → 4 high-priority categories. A PR whose base **is** the survey ref is release-relevant by definition, so — unlike issues — no title/milestone relevance filter is applied. ### Testability Adds a small **StrictMode-safe `Test-IsP0Pr`** helper plus a **dot-source guard** on the engine (mirroring `Find-ReleaseReadinessTrackers.ps1`) so the predicate can be unit-tested without invoking the full git/gh-backed report flow. --- ## Fix 2 — Drop stale below-watermark SR branches from the tracker matrix ### Summary The Lane 1 in-flight detector (`Find-ReleaseReadinessTrackers.ps1`) treated **tag-absence** as the sole in-flight signal. Abandoned hotfix leftovers like **SR2** (patch 21) and **SR3** (patch 33) — which never published their stable tags and sit far below the shipped watermark (**SR7** patch 71) — were still emitted as trackers. The workflow then spun up a **no-op matrix job** per branch: the per-job activity gate skipped issue creation, but the job still ran. ### What changed Adds a secondary **`Test-IsStaleSrBranch`** disambiguator applied **only after** `Test-IsBranchInFlight` returns true. A branch is stale when **both**: - its patch is **strictly below** the highest shipped patch, **and** - it has had **no commits** within the activity window (idle). Tag-existence stays the **primary** signal; the idle requirement preserves the out-of-order / security-hotfix case — a real reset branch below the watermark has recent commits and is therefore **not** dropped. Freshly-cut live SRs sit at/above the watermark and are never affected. Dropping these at the detector removes them from the workflow matrix **entirely**. Verified safe: SR2/SR3 have no open tracker issues, so nothing is stranded (only SR8/SR9/preview6 have open trackers). --- ### Tests `Test-ReleaseReadiness.ps1`: - **12** new unit assertions for `Test-IsP0Pr` (predicate: p/0 present/absent, missing/null/empty labels, hashtable-shaped labels, null PR; carve-out semantics: p/0 subset selected, generic bucket excludes them). - **7** new unit assertions for `Test-IsStaleSrBranch` (below-watermark idle → stale; above/equal watermark → not stale; below-watermark but active → not stale; no shipped tags → never fires). - Live-repo E2E expectations updated: net10 now surfaces **2** SR trackers (SR8 + SR9) instead of 4. ``` Passed: 517 Failed: 0 ``` --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## Summary Removes `environment: gh-aw-agents` from the `trigger-review` job in `review-trigger.yml`. ## Why PR #35974 added `environment: gh-aw-agents` to `review-trigger.yml`, which changed the GitHub OIDC token subject from `repo:dotnet/maui:ref:refs/heads/main` to `repo:dotnet/maui:environment:gh-aw-agents`. The managed identity (`Testing-MI-gh2zdo`) behind `AZDO_TRIGGER_CLIENT_ID` has no federated credential for that environment subject, so every `/review` command fails with: ``` AADSTS700213: No matching federated identity record found for presented assertion subject 'repo:dotnet/maui:environment:gh-aw-agents' ``` The `AZDO_TRIGGER_*` secrets have been re-added at the repo level. Once the federated credential is updated (requires Azure access to the managed identity), the environment gating can be re-added. ## What changed - Removed `environment: gh-aw-agents` from the `trigger-review` job (1 line) - All gh-aw workflows remain gated — only `review-trigger.yml` (regular GHA) is affected Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ive assertions, add deterministic fixture coverage (#36004) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Summary Follow-up to #35971. De-flakes a pre-existing time-bomb in the release-readiness skill's **own** test suite (`.github/skills/release-readiness/tests/Test-ReleaseReadiness.ps1`). Skills-only change — no framework code touched. ### The time-bomb The suite had four **live, wall-clock-dependent** assertions that hardcoded `hasRecentActivity = $true` against real release branches (SR8, SR9, the active-SR `foreach` loop, and preview6). The detector (`Find-ReleaseReadinessTrackers.ps1`) computes `hasRecentActivity` from `Get-RecentCommitCount`, which runs `git log <branch> --since=7.days` and returns `(count > 0)`. So those assertions are only true *while the real branch has had a commit in the last 7 days*. The moment a servicing branch goes quiet for 7 days — a **normal** end-of-cycle state — the assertion flips red. On **2026-06-18** this actually happened: SR8's last commit (the SR7→SR8 merge #35810) landed 2026-06-11, so `--since=7.days` returned 0 and the two SR8 assertions went red. They self-heal on the next commit, but nondeterministic red in a suite whose entire selling point is determinism is a credibility bug. ### What changed - **Removed the wall-clock-dependent live assertions.** The end-to-end detector run now asserts only that `hasRecentActivity` is a real `[bool]` the detector emitted — never a date-dependent value. - **Added genuinely deterministic coverage of the recency-window math** via a synthetic fixture: a throwaway temp git repo with commits at controlled dates (`GIT_AUTHOR_DATE`/`GIT_COMMITTER_DATE` at now−6d / now−8d / now−30d), then calls the **real** `Get-RecentCommitCount` (dot-sourced) against it and asserts exact counts for the 7/10/60/1-day windows plus the `origin/`-prefixed ref form. Zero network, zero dependence on "today"; the temp repo is cleaned up in a `finally`. - **Corrected the misleading comments** that equated "active SR" with `hasRecentActivity = true`. An active SR can legitimately idle for >7 days; `hasRecentActivity` is a 7-day-window signal, not a synonym for "active". ### Verification Full suite is green: `pwsh -NoProfile -File .github/skills/release-readiness/tests/Test-ReleaseReadiness.ps1` → **Passed: 552, Failed: 0** (was 545/2 before, with the two SR8 reds). The new fixture assertions also pass under `-SkipE2E` (offline), confirming they're network-independent. > Note: the `maui-pr` framework pipeline intentionally skips for skills-only PRs — that's expected, not a failure. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…den comment posting (#36003) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### The bug The **Skill Validation** workflow's `Post results comment` job was failing on its `Post comment` step with: ``` ReferenceError: agentCount is not defined at eval (... actions/github-script/v7 ...) ##[error]Unhandled error: ReferenceError: agentCount is not defined ``` The `github-script` step builds a badge array that references `agentCount`: ```js badge('Skills', String(skillCount), '8250df'), badge('Agents', String(agentCount), '0969da'), // ❌ agentCount never defined/produced ``` …but `agentCount` was **never defined** in the script and **never produced** as an artifact, whereas `skillCount` is defined (reads `static-results/skill-count.txt`). The script threw while constructing the comment body — *before* any API call — so the results comment was **never posted**. This was introduced on 2026-06-16 in commit `1c0c0eb200` (#35713, "Style skill validation results comment") and has silently broken the results comment on **every** Skill Validation run since. It is a real, deterministic workflow bug — not a permissions issue (the job already has `pull-requests: write` + `issues: write`) and not a merge/close race (the failure is a JS `ReferenceError`, not a 403). ### The fix Self-contained to `.github/workflows/skill-validation.yml`: 1. **Producer** — In the existing `Save results artifact` step (the one that writes `skill-count.txt`/`spec-count.txt`), add an agent count written to `agent-count.txt` in the same `sv-results/` dir, flowing through the same `static-check-results` upload/download wiring: ```bash agent_count=$(find .github/agents -mindepth 1 -maxdepth 1 -name '*.md' -type f 2>/dev/null | wc -l | tr -d ' ') echo "$agent_count" > sv-results/agent-count.txt ``` 2. **Definition** — In the `Post comment` github-script step, define `agentCount` mirroring `skillCount`/`specCount` exactly (read `static-results/agent-count.txt` inside a try/catch that falls back to `'?'`), placed alongside the existing definitions so it's in scope before the badge array. 3. **Hardening** — Wrap the badge + body construction in a `try/catch`. On any failure it logs via `console.error` and `core.warning` (no silent swallowing) and posts a minimal **plain-text fallback** body (keeping the `<!-- skill-validation-results -->` marker so the upsert still finds/updates the comment). The results comment now **always** posts even if the badge formatting breaks. ### Validation - YAML parses (`yaml.safe_load`). - `agentCount` is defined (script line ~898) before its only use in the badge array (line ~1178). - The embedded github-script JS passes `node --check` (balanced braces / valid scope) when wrapped in an async function (it uses top-level `await`, which github-script permits). The embedded JS can't be executed locally (depends on the `github`/`context`/`core` runtime), so dynamic behavior wasn't run; logic was reviewed by hand. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…R lane parity with Preview) (#36006) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### The gap The release-readiness skill has two report generators. The **Preview lane** (`Get-PreviewReadiness.ps1`) already surfaces open PRs carrying the `p/0` label as release **blockers**. The **SR lane** (`Get-ReleaseReadiness.ps1`) did **not**: it derived blocking only from ship-checks (`BLOCKED`) and Tier-1 `regressed-in-*` **issue** classifications. Open PRs were listed purely informationally. Consequence: a `p/0`-labelled PR targeting an SR branch was never flagged as blocking on the SR tracker issue. Concretely, PR #35970 (`Revert PR #33584…`, base `release/10.0.1xx-sr8`, label `p/0`) did **not** show as blocking on the SR8 tracker issue #35876. ### What changed - **Ported `Test-IsP0Pr`** from the Preview lane into `Get-ReleaseReadiness.ps1`. It is StrictMode-safe and accepts both the production `gh --json` PSCustomObject shape and the IDictionary/hashtable shape used by test mocks. - **Added `Get-P0PrChecks`**, which emits a single `P/0 release-branch PRs` ship-check — `BLOCKED` (naming each offending PR, e.g. `#35970`) when any open `p/0` PR targets the SR branch, `READY` otherwise. - **Merged the check into `shipChecks`** in the main flow, reusing the already-fetched open-PR list so there is **no extra `gh` call**. Because it's a standard `BLOCKED` ship-check, it is automatically hoisted into the top-of-issue `🔴 Blocking` summary and escalates the verdict to **Not Ready** — no verdict or renderer changes were needed. - **Added deterministic synthetic-fixture unit tests** for both functions (no network, no wall-clock dependence). ### Notes - This is a PowerShell-only `.github/skills/**` change; the framework `maui-pr` pipeline intentionally skips for skills-only PRs. - Discovered while working on the separate deflake PR #36004. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Update rebase action --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ments once authorized (#36021) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Summary Follow-up to #35895, which switched the `/review`, `/review rerun`, and `/review tests` command-comment cleanup from delete to GraphQL `minimizeComment(classifier: RESOLVED)`. In practice the command comments were **still left visible** in several cases. This PR makes all three reliably collapse **once the command is recognized and the commenter is authorized — regardless of the command's result.** ### Root causes (observed on #30311) 1. **`/review tests` — permission bug.** The gh-aw `copilot-review-tests` pre-activation job that minimizes the comment only had `issues: write`. The comment lives on a **pull request**, so `minimizeComment` needs `pull-requests: write`; with only `issues: write` it failed with `Resource not accessible by integration` (run `27824496263`) and the comment stayed visible. #35895's assumption that "minimizing requires the same `issues:write` scope that deletion did" is incorrect for PR conversation comments. 2. **`/review rerun` — eligibility gate.** The `mark-rerun-ready` hide step was gated on `eligible == 'true'`, so an **ineligible** rerun (e.g. `no-new-comments-or-commits`) left the comment fully visible. 3. **`/review` — trigger-outcome gate.** The `trigger-review` hide step was gated on `trigger_azdo.outcome == 'success'`, so a **lock-skip** or a **failed AzDO trigger** left the comment visible. ### Changes **`copilot-review-tests.md` (gh-aw)** - Add `pull-requests: write` to the pre-activation job (`on.permissions`) so it can minimize a PR comment. The AI agent job stays read-only. - Recompiled `copilot-review-tests.lock.yml` with gh-aw `v0.79.8`; only `frontmatter_hash` and the pre-activation permission change — `body_hash` is unchanged. **`review-trigger.yml`** - `/review rerun` and `/review` now minimize the command comment whenever the actor is authorized and the command was recognized, no matter the downstream outcome. - Each job's "Check actor permission" step gets an `id: auth`; the hide step is gated on `!cancelled() && github.event_name == 'issue_comment' && steps.auth.outcome == 'success'`. `!cancelled()` lets the hide run even after an upstream step failed (failed trigger / ineligible rerun / errored eligibility), while the `steps.auth` gate keeps **unauthorized** commenters' comments fully visible. ### Safety / scope - **Unauthorized comments are never hidden** (the `steps.auth.outcome == 'success'` gate, and the internal collaborator check in the `/review tests` script). - **Transparent to the rerun scanner.** `Resolve-RerunEligibility.ps1` / `Query-RerunReadyPRs.ps1` / `Get-LatestRerunCommentBefore` key on comment `id`, body and `created_at` — never on `isMinimized` — and minimized comments are still returned by the REST list endpoint. Verified there are no `isMinimized` references in those scripts. - A failed minimize emits a `::warning::` and never fails the review/rerun/tests trigger. - The only outcome not covered is a **cancelled/timed-out run** (`!cancelled()` skips on interruption); every completed outcome is covered. ### Validation - `gh aw compile` → 0 errors / 0 warnings; recompiling produced no stray diff. - `review-trigger.yml` parses as valid YAML. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ferences and drop invalid authorAssociation gh field (#36029) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Problem The `[Release Readiness]` tracker issues were rendering `gh` warnings embedded in their bodies, two distinct root causes: **1. Cross-repo timeline cross-references (e.g. SR8 tracker #35876).** `Get-IssueTimelinePrs` walked a regression issue's `cross-referenced` timeline events and collected the source PR number **without checking which repository the PR lives in**. Real examples found live: - regression #35584 ← PR **#102** in `zhollis21/AniSprinkles` (an unrelated personal app) - regression #35771 ← PR **#24** in `praveenkumarkarunanithi/maui` (a fork) Looked up against `dotnet/maui` these 404 (`gh pr view 24 ... Could not resolve to a PullRequest`), and the warning gets written into the tracker issue. Worse, a foreign PR whose number *happens* to exist in dotnet/maui (e.g. #877 from `DIPSAS/DIPS.Mobile.UI`) silently mis-matches an unrelated dotnet/maui PR as a "fix candidate" with no warning at all. **2. Invalid `gh pr list` field (e.g. SR9 tracker #35867).** `Get-CandidatePrChecks` requested `gh pr list --json number,title,author,authorAssociation,updatedAt,url`, but `authorAssociation` is **not a valid `gh pr list` projection field** (it's REST-only). The whole query failed (`Unknown JSON field: "authorAssociation"`), surfacing a warning and silently degrading the maintainer spoof-gate. ### Fix - `Get-IssueTimelinePrs`: drop any cross-reference whose `repository.full_name` ≠ the target repo. The timeline API populates `repository.full_name` for same-repo references too, so legitimate dotnet/maui fix PRs are preserved. This fixes both the noisy 404 warnings and the silent wrong-repo mis-matches. - `Get-CandidatePrChecks`: remove `authorAssociation` from the `gh pr list` projection and fetch `author_association` per title-matched candidate via `gh api repos/{repo}/pulls/{n}` (cheap — candidate matches are almost always 0–1). Fail closed: an unreadable association excludes the PR so a `Candidate`-titled spoof can't slip through. ### Tests Adds 8 deterministic, offline (gh-stubbed) regression assertions: cross-repo timeline filtering (keeps same-repo, drops foreign #24/#102 and non-PR events; foreign-only → 0 candidates) and the REST author-association spoof-gate (MEMBER accepted, CONTRIBUTOR excluded, spoof-only reports exclusion). Offline suite: **492 passed / 0 failed**. Scope check: the sibling Preview engine (`Get-PreviewReadiness.ps1`) has neither code path, so no change is needed there. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…d newlines + unescaped pipes) (#36031) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Problem The `[Release Readiness]` tracker issues render markdown tables built from upstream-controlled content — issue/PR **titles** dropped into pipe-delimited rows (`| #link | <title> | <…> |`). Several kinds of malformed (or hostile) title corrupt those rows: 1. **Embedded newlines.** Some `ci-scan` issues have a title containing a **literal newline** — observed live on issue #35957, whose real GitHub title spans two physical lines and ends with `(maui-pr-uitest\n[Content truncated due to length]`. An embedded `\r\n` splits the row across two physical lines, so the title tail + trailing cells land on a line that no longer contains the issue link. This was visible on the live trackers: **net10-sr9 #35867** (2 broken rows) and **net11-preview6 #35866** (3 broken rows). 2. **Unescaped pipes.** A literal `|` in a title (common — e.g. `Fix A | B`) injects an extra column. The preview engine already escaped pipes everywhere via its shared `Format-MarkdownCell`, but on the **SR** side cells were escaped ad-hoc — several embedded titles with **no newline collapse at all**. 3. **Escape-the-escaper pipe breakout.** A title may legally contain a literal `\|` (backslash immediately followed by a pipe). Escaping only the pipe turns that into `\\|`, which GitHub-flavored Markdown renders as a literal `\` followed by an **active** column delimiter — so the row still breaks out. Both engines had this latent bug. 4. **Raw `<`/`>` (HTML injection / display loss) on the SR side.** SR dropped titles in raw, so a title like `Crash <!--` could inject an HTML-comment opener, and a legitimate `List<T>` (or engine-authored placeholder text like `Bump <PatchVersion> …`) was silently swallowed by GitHub as an unknown HTML tag and never displayed. The ultimate root cause of (1) is upstream (the CI Failure Scanner producing a multi-line title), but a readiness engine should defensively sanitize any external content it embeds into its own tables. ### Fix - **`Get-ReleaseReadiness.ps1`** — introduce a single null-safe **`Format-MarkdownTableCell`** helper and route **every** SR site that embeds upstream-controlled text through it. This covers the ci-scan rows, the **Open PRs Targeting `<srBranch>`**, **regression classification**, **🔴 Blocking summary**, **🧹 Cleanup**, **📥 Open Fix PRs Inbound**, and **Ship-readiness checks** tables, **plus the candidate-PR bulleted list**. The helper: - collapses `[\r\n]+` → space (hazard 1), - escapes each `|` → `\|` and **doubles only the backslash run immediately preceding that pipe** (via a single `(\\*)\|` regex pass), so a pre-existing `\|` becomes `\\\|` (renders a literal `\|`, no breakout — hazards 2 & 3). The doubling is **scoped to pipe-adjacent runs** rather than every backslash, so a title's other backslash escapes (`\[link\](url)`, `\*not emphasis\*`) are preserved verbatim and not de-escaped into active Markdown. No-pipe-adjacent-backslash titles are unchanged (`a | b` → `a \| b`). - escapes `<`/`>` → `<`/`>` (hazard 4), **matching the preview engine** for SR↔Preview parity. - **`Get-PreviewReadiness.ps1` (`Format-MarkdownCell`)** — the newline collapse plus the same **pipe-adjacent** backslash handling so the preview engine is immune to the `\|` breakout too. **On `<`/`>` escaping (now consistent across both engines):** escaping angle brackets to entities has **zero visual cost** — `<T>` renders as `<T>` — so `List<T>` fidelity is preserved while raw HTML injection is neutralized (`<!--` → `<!--`). It also fixes a latent display bug: engine-authored `NextAction` text such as `Bump <PatchVersion> in eng/Versions.props` was previously rendered raw and **swallowed by GitHub as an unknown HTML tag**, so the Release Captain saw `Bump in eng/Versions.props`; it now displays correctly. SR is additionally hash-freeze-immune (it emits its own hash at the **top** of the body, extracted with `head -n1`) and its human-notes markers are matched **full-line-anchored**, so escaping `<>` is defense-in-depth layered on top of those backend invariants rather than the sole protection. (`.Trim()` only touches leading/trailing whitespace.) ### Tests Deterministic, offline assertions: - **`Format-MarkdownTableCell` / `Format-MarkdownCell` unit tests** — pipe escaping, LF/CRLF-run collapse, newline+pipe together, null/empty → empty string, whitespace trim; **angle brackets escaped to `<`/`>` (both engines, parity)**; **literal `\|` does NOT break out** (→ `A \\\| B`); **non-pipe backslash preserved** (`C:\dir` unchanged) and **author-escaped non-pipe Markdown not de-escaped** (`\[link\](url)` unchanged) for both engines; **`<!--` opener neutralized** to `<!--`. - **SR ci-scan row** — an embedded-newline title renders as a **single** physical row with its tail + age intact. - **SR tables (end-to-end `Format-MarkdownReport`)** — a piped+newline title in the **Open PRs Targeting**, **regression classification**, **🔴 Blocking summary**, **📥 Open Fix PRs Inbound**, and **Ship-readiness checks** tables each stays on one physical row, pipe escaped, trailing column intact; the BLOCKED ship-check next-action with `<PatchVersion>` renders entity-escaped (so GitHub actually displays it). - **Human-notes marker-forgery regressions (security)** — a title embedding `…\n<!-- …:human-notes:begin -->\n…` in a **table cell** and in the **candidate-PR list** must leave **exactly one** anchored begin-marker in the rendered body (the legitimate one), proving a hostile title cannot forge a second notes region. - **Preview engine** — `Format-MarkdownCell` collapses LF/CRLF runs and preserves the existing pipe / angle-bracket escaping contract. The discriminating assertions were verified **red on the pre-fix scripts** and **green after** (and the surgical-scoping assertions were verified red against the earlier global-doubling commit). Offline suite: **566 passed / 0 failed**; full E2E: **632 / 0**. ### Scope / follow-ups (intentionally out of this PR) - Backtick (inline-code) is intentionally **not** escaped: doing so would degrade the very common legitimate case of code-quoted titles like `` `CollectionView` ``, and an unescaped backtick is a cosmetic-only, non-structural concern (it cannot create a new column, inject HTML, or forge a human-notes marker, all of which require `|`/`<`, which **are** escaped). - Null-safety of `.title.Length` under `Set-StrictMode -Version Latest` is **pre-existing** (titles are non-null by GitHub API contract) and intentionally deferred to a focused follow-up rather than mixed into this rendering PR. - The SR "Reverts" table's "Reverts commit" column shows `?` for every row (the `This reverts commit <sha>` body-regex never resolves). Pre-existing and unrelated; noted for a future pass. - Filing an upstream issue against the CI Failure Scanner for the malformed (multi-line) titles is worth doing separately so the trackers receive clean input at the source. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…und guard) (#35955) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Problem The `/review rerun` scanner never dispatched a single AzDO run in production. Investigation across recent scheduled runs showed the agent correctly deciding `decision=trigger` for open PRs, yet **every** dispatch was aborted. Two independent bugs were responsible: 1. **Only one decision per run was ever processed.** gh-aw custom safe-output jobs run exactly once per scan. The agent was instructed to call the `trigger_rerun_review` tool once *per candidate*, so every call after the first was silently dropped by gh-aw's "max 1 item" enforcement. Even when several PRs were eligible, at most one reached the dispatch script. 2. **A false "PR not found" guard cancelled dispatches for open PRs.** `Test-GhApiPrNotFound` classified any gh error text containing "Not Found"/"Gone" (e.g. transient proxy/auth bodies) as a deleted PR, so the script logged `PR #N no longer exists; skipping stale decision` and bailed — for PRs that are demonstrably open. ### Fix 1. **Batch all decisions into one tool call.** The agent now calls `trigger_rerun_review` **exactly once per run**, passing a single `decisions` JSON array with one object per candidate PR. `Get-AgentItems` expands the array (`Expand-RerunDecisionItems`) into individual decisions, with back-compat for the legacy scalar shape. This processes *all* eligible PRs in a scan instead of just one. > Note: gh-aw v0.77.5 does **not** support `max: N` on a custom `safe-outputs.jobs.<name>`, so batching into one array-typed input is the only way to lift the one-per-run cap. 2. **Harden the not-found guard.** `Test-GhApiPrNotFound` now requires an explicit `HTTP 404`/`410` status. The fetch block logs the raw gh error and performs a second confirmation probe before skipping — it fails loud (throws) rather than silently cancelling a dispatch when the cause is ambiguous. ### Tests - 32 Pester tests pass (`Invoke-RerunReviewTrigger.Tests.ps1`), including: - 5 new tests for batched `decisions` parsing (JSON string array, object array, multi-item aggregation, legacy scalar pass-through, empty/null payloads). - A regression test ensuring bare "Not Found"/"Gone" text without an HTTP 404/410 status is **not** misclassified. - `gh aw compile rerun-review-scanner` succeeds (0 errors/warnings); the regenerated `.lock.yml` is committed and embeds the new `decisions` tool schema. ### Files - `.github/scripts/Invoke-RerunReviewTrigger.ps1` — batched decision expansion + hardened guard + raw-error logging/re-probe. - `.github/scripts/Invoke-RerunReviewTrigger.Tests.ps1` — new coverage. - `.github/workflows/rerun-review-scanner.md` — single batched `decisions` tool schema + updated agent prompt. - `.github/workflows/rerun-review-scanner.lock.yml` — recompiled. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ts (#36061) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Summary The SR release-readiness tracker overcounts the regressions header when **exactly one** regression candidate exists. The live `.NET 10 SR9` tracker ([#35867](#35867)) renders: ``` ## Regression Candidates — 13 issues scanned ``` …even though only **one** issue ([#35615](#35615)) was actually scanned. The summary table, tiers, and verdict all correctly show 1 — only the header is wrong. ### Root cause The header is built from `$regs.Count`: ```powershell $regs = $Data['regressions'] ... "## Regression Candidates — $($regs.Count) issues scanned" ``` Regression results are **hashtables**. `Get-RegressionCandidates` returns its `$results` accumulator, and when exactly one candidate matches, PowerShell **unwraps the single-element array on return**, so `$Data['regressions']` arrives as a lone hashtable rather than a 1-element array. `.Count` on a hashtable returns its **key count** (13 — `createdAt, confidence, milestone, state, closedAt, evidence, candidateFixPrs, labels, stateReason, classification, recommendedAction, issue, title`), not 1. - **N = 0** → `@()` → `.Count` = 0 ✅ (already correct) - **N = 1** → scalar hashtable → `.Count` = 13 ❌ (this bug) - **N ≥ 2** → real array → `.Count` = element count ✅ (already correct) ### Fix Force array context so `.Count` always reflects the candidate count: ```powershell $regs = @($Data['regressions']) ``` One line. The sibling SR headers (`$blockingItems`, `$cleanupItems`, `$openFixRows` are all `List[hashtable]`) and the preview engine (`Get-PreviewReadiness.ps1`, which uses `List`/`@()`-wrapped collections) are **not** affected — this is the only header fed the raw `regressions` value. ### Tests Added a **discriminating** regression test in `Test-ReleaseReadiness.ps1` that reproduces the production unwrap by assigning the regression result as a **scalar hashtable** (not `@(...)`, which would mask the bug) and asserts the header reports `1 issues scanned`, plus an N=2 guard for the already-correct path. A precondition assertion locks in that the value is a scalar hashtable so a future edit can't silently neuter the test. - ✅ Verified the new test **fails pre-fix** (renders the key count) and **passes post-fix**. - ✅ Offline suite: **569 passed / 0 failed**. - ℹ️ Full E2E: 627 passed / 3 failed — the 3 failures are **pre-existing** (live-`gh` E2E tests: `sr-source-prs.txt`, candidate JSON, `-InheritFromPriorSr` validation), reproduced identically on pristine `main` (624/3) and unrelated to this change. They pass in CI's `release-readiness.yml` Validate job, which has a proper `gh` token. ### Scope Separate, focused follow-up off `main` — unrelated to the table-escaping fix in #36031 (already merged). No behavior change beyond the header count. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Updated [Magick.NET-Q8-AnyCPU](https://github.com/dlemstra/Magick.NET) from 14.12.0 to 14.13.1. <details> <summary>Release notes</summary> _Sourced from [Magick.NET-Q8-AnyCPU's releases](https://github.com/dlemstra/Magick.NET/releases)._ ## 14.13.1 ### What's Changed - Fixed loading of animated AVIF image as MagickImageCollection (#2000) - Fixed determining the number of frames when reading animated AVIF images (#2005) - Fixed loaded of indexed color PSD file (#2007) - Another fix when reading JPEG compressed TIFF files. (#2016) ### Related changes in ImageMagick since the last release of Magick.NET: - Stack overflow in fx operation (GHSA-rcr6-g7jc-f57g) - Heap Buffer Over-Write of a single byte in the JP2 encoder (GHSA-533m-3wf6-c33v) - Use-After-Free in MSL decoder (GHSA-5r4x-w6p5-222q) - Infinite Loop in the MIFF decoder can lead to CPU exhaustion (GHSA-7gg8-qqx7-92g5) - Heap Buffer Over-Write in IPL decoder when reading multiple images of different dimensions (GHSA-36wm-hprc-mcf5) - Heap Buffer Over-Write in MIFF encoder when using LZMA compression (GHSA-jcqp-6r6f-3mfx) ### Library updates: - ImageMagick 7.1.2-23 (2026-05-17) - aom 3.14.0 (2026-05-12) - openexr 3.4.11 (2026-04-30) - libhwy 1.4.0 (2026-04-23) - lcms 2.19.1 (2026-05-06) - openjph 0.27.3 (2026-05-14) **Full Changelog**: dlemstra/Magick.NET@14.13.0...14.13.1 ## 14.13.0 ### What's Changed - Added `PixelDifferenceCount` to `ErrorMetric`. ### Related changes in ImageMagick since the last release of Magick.NET: - Corrected the patch that was made earlier to fix reading JPEG compressed TIFF images (#1993) - Call CloseBlob on the correct image to prevent the blob from remaining open (#1997) ### Library updates: - ImageMagick 7.1.2-21 (2026-04-21) - harfbuzz 14.2.0 (2026-04-20) - libpng 1.6.58 (2026-04-15) - libraqm 0.10.5 (2026-04-11) - libraw 0.22.1 (2026-04-06) - libxml2 2.15.3 (2026-04-15) - openexr 3.4.9 (2026-04-17) - openjph 0.27.0 (2026-04-14) **Full Changelog**: dlemstra/Magick.NET@14.12.0...14.13.0 Commits viewable in [compare view](dlemstra/Magick.NET@14.12.0...14.13.1). </details> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/dotnet/maui/network/alerts). </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…#35927) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## What this PR adds Two new agentic workflows that walk open CI-failure tracking issues filed by the existing scanners and open draft `[ci-fix]` PRs against the matching branch: - `.github/workflows/ci-status-fix.md` — processes `[ci-scan]` issues, opens PRs against **`main`**. - `.github/workflows/ci-status-fix-net11.md` — processes `[ci-scan-net11]` issues, opens PRs against **`net11.0`**. They are the natural counterpart to the existing `ci-status-main.md` / `ci-status-net11.md` detection workflows: one pair identifies, the other proposes a fix. **No KBE / Build Analysis integration** — just identify → auto-fix PR, as requested. Also includes two small, surgical prompt edits to both scanner files so the fixers can trust what they emit. ## Why two workflows instead of one The fixer logic is identical for both branches; the split is forced by a gh-aw transport constraint, not by behavior. gh-aw always generates a "transport patch" for its `create-pull-request` safe-output **relative to a single static `base-branch`**, and `max-patch-size` is hard-capped at **10 MB** by the gh-aw schema (raising it past 10 MB is a compile error). The `main` ↔ `net11.0` divergence is ~22 MB / ~1,000 files, so a one-file `net11.0` fix built against a `main` base produces a ~22 MB transport patch and is unconditionally rejected (file-count guard, then size). Because `base-branch` is one static value per workflow, each base needs its own workflow. With `base-branch: net11.0`, gh-aw builds the transport patch relative to `net11.0`, so the patch is just the fix's own delta. This was validated live (see below): the net11.0 fixer opened a clean **1-file** draft PR against `net11.0`. ## Design highlights **Each workflow is hard-pinned to exactly one base branch, enforced at three layers.** 1. **gh-aw declarative gate**: `safe-outputs.create-pull-request.base-branch` pins the base (`main` / `net11.0`), and `allowed-base-branches` (`[main]` / `[net11.0]`) makes gh-aw reject any other base. 2. **Prompt rule**: the agent only processes the matching label (`ci-scan` / `ci-scan-net11`) and checks out `origin/<branch>` (Step 5.2) before authoring, so the transport patch and the downstream push are both exactly the one-file fix delta. 3. **Self-check before emission**: the agent greps its own PR body for `Target branch: <branch>` and confirms `base` matches; mismatch aborts. **Iterative, capped at 5 attempts per tracking issue.** Attempt count comes from a live GitHub PR search for `"Refs: dotnet/maui#<N>"` in closed-unmerged `[ci-fix]` PRs (GitHub is the durable store — no per-run state needed). After the 5th closed-unmerged attempt the workflow stops and defers to humans (the open tracking issue is the hand-off surface). A dedicated `[ci-fix][needs-human]` hand-off PR is planned but **currently deferred** (Step 6 records a skip and emits no PR). Each attempt reads prior closed PRs' approaches and close comments and must propose a substantively different approach. **"Is it actually fixed?" check.** Before any fix attempt, the agent fetches the latest completed build of the failing pipeline on the target branch and `grep -F`s the issue's failure signature against the leaf-log output. Zero hits → silently skips ("appears fixed in latest build"). Tracking issue closure stays a human decision. **De-flake capability for intermittent test failures.** A flakiness probe classifies a reproducing failure as (a) infra → skip, (b) test-quality → de-flake PR, or (c) product-masking → product fix / hand-off. A de-flake replaces sleeps/races with condition waits and tightened assertions; it **never** adds `[Ignore]` / `[Retry]`, weakens assertions, or bumps timeouts. **Visual-regression filter is the first gate.** Silently skips any issue whose title, body, error message, or failed task names match `screenshot` / `snapshot` / `visual diff` / `baseline image` / `VerifyScreenshot` / etc. gh-aw can't judge visual diffs and must never modify baseline images. **Never mutes a test.** Stages with `[ActiveIssue]`, `Skip = "..."`, `[SkipOnPlatform]`, csproj `<*Incompatible>` / `<ExcludeFromTestRun>`, or edits to baseline images under `TestAssets` / `Snapshots` / `Baselines` are detected and rejected. If the only candidate fix is a mute, the run records a skip and stops. **MAUI area bounds.** Compile / XAML breaks are in bounds (≤ 20 lines, single file when possible). Device-test and UI-test failures (past the visual-regression gate) become `help`-only PRs or de-flakes. Handler lifecycle, threading, safe-area, perf hot-paths, Gradle/Maven feed, and infra failures are skipped — too risky for an autonomous fix. **Outputs only via `safe-outputs`.** Tracking issues are locked so no comments are possible. `draft: true`, `max: 3` PRs per run, `environment: gh-aw-agents` gating on the write-capable job, `allowed-files` restricts to `src/Core/**`, `src/Controls/**`, `src/Essentials/**`, `src/BlazorWebView/**`, `src/TestUtils/**`, `src/Templates/**`, `**/PublicAPI.Unshipped.txt` (which already excludes `.github/**`). ## Validated live The net11.0 workflow was run end-to-end against a real `[ci-scan-net11]` issue (#35981, a flaky `DropEventCoordinates` iOS 18.5 drag-and-drop test). It opened draft PR **#36027** targeting `net11.0` with a clean **1-file** de-flake (reset-between-retries + a tightened positive-coordinate assertion; no banned mute/retry patterns) and correct body markers (`Refs`, `Target branch: net11.0`, `Attempt 1/5`, `Flake class: test-quality`). #36027 is left open as a genuine candidate fix for maintainers to review — it proves the `base-branch: net11.0` split produces a small, in-cap transport patch. ## Two small scanner edits (so the fixers can rely on what they emit) Both `ci-status-main.md` and `ci-status-net11.md`: 1. **Mandatory `Build ID: <integer>` line** in the issue body template. The fixer requires it as a field gate (skipping any issue missing it) and cites it as the *original failing build* in its PR audit trail; the existing `Build: <URL>` line is opaque to grep. (The reproduce-check itself re-fetches the *latest* build of the pipeline.) 2. **Match-count gate** requiring the scanner to verify its own primary error substring actually appears in the fetched failure log before filing, and embed the result as a second hidden marker: ``` <!-- ci-scan-match-count: N hits in failure.log --> ``` Issues with 0 matches are not filed. This blocks hallucinated signatures from ever entering the fixers' work lists. The substring is treated as untrusted data — it is written to a pattern file via a fresh per-run random-delimiter single-quoted heredoc and matched with `grep -F -f` (never interpolated into a shell command), mirroring the injection-proof pattern the fixers use. ## Lifecycle and stop conditions | State | Action | |---|---| | Open `[ci-fix]` PR already exists for the issue | Skip — human owns the PR | | Merged `[ci-fix]` PR exists | Skip — fix already landed | | Open human PR (non-`agentic-workflows` label) references the issue | Skip — human is on it | | `attempt_count < 5` and signature still reproduces | Open attempt N+1 | | `attempt_count >= 5` | Stop and defer to humans; never retry (dedicated `[ci-fix][needs-human]` PR deferred — see Step 6) | | `attempt_count` search inconclusive (API error / `incomplete_results`) | Skip — cannot safely confirm the cap | | Latest build no longer reproduces the signature | Skip — "appears fixed" | | Issue body missing required fields (`Build ID`, fingerprint, error block) | Skip — scanner needs prompt update | | Only candidate fix is a mute | Skip | | Only candidate fix modifies visual baselines | Skip | | No novel approach producible vs prior attempts | Skip — defer to next tick | ## Files - **NEW**: `.github/workflows/ci-status-fix.md` — main-branch fixer (`base-branch: main`) - **NEW**: `.github/workflows/ci-status-fix.lock.yml` — generated by `gh aw compile` - **NEW**: `.github/workflows/ci-status-fix-net11.md` — net11.0-branch fixer (`base-branch: net11.0`) - **NEW**: `.github/workflows/ci-status-fix-net11.lock.yml` — generated by `gh aw compile` - **EDIT**: `.github/workflows/ci-status-main.md` — `Build ID` line + match-count gate - **EDIT**: `.github/workflows/ci-status-net11.md` — `Build ID` line + match-count gate `gh aw compile` passes cleanly on both new workflows (0 errors, 0 warnings). ## Things this PR explicitly does NOT do - Does **not** integrate Build Analysis / KBE in any form. - Does **not** add a feedback / KPI workflow (could be a follow-up if maintainers want one — the marker blocks in PR bodies are designed to make it easy). - Does **not** read PR review comments as instructions — the integrity gate filters them and the agent never treats them as authoring input. - Does **not** close tracking issues — closure stays a human decision. - Does **not** modify any production source code in this PR; workflow-only change. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…s trackers (#36066) > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Summary Each `[Release Readiness]` tracker now opens with a **nightly dogfood feed freshness banner** for that release's lane, so a release captain can tell at a glance whether dogfooders are validating *current* bits or testing stale builds. A fresh nightly is expected daily; when one stops appearing, the tracker should say so loudly. This is internal release-readiness tooling (`.github/skills/release-readiness/`) — no product/runtime code changes. ### What it looks like - ✅ fresh (`< 3` days): `**Nightly dogfood feed:** ✅ \`dotnet11\` (net11 preview) — latest \`11.0.0-preview.6.26322.3\` built today.` -⚠️ aging (`3–6` days): blockquote with age + publish date. - ❌ stale (`≥ 7` days): blockquote alarm — e.g. (live, SR8 band today): `❌ Nightly dogfood feed is STALE — 11 days … Latest build \`10.0.80-ci.main.26310.5\` published 2026-06-11 … builds appear to have stopped`. - Muted one-liners for *unknown* (feed query failed) and *no matching build* (band naming changed) — never a false alarm. ### How it works - **New shared helper `scripts/NightlyFeed.ps1`** (single source, dot-sourced by both engines + the test harness): - `Get-NightlyFeedFreshness` — queries the lane's Azure Artifacts feed (`dotnet10`, `dotnet11`, …) and returns the newest build whose version matches a **band prefix**, selected by `catalogEntry.published`. The feed orders versions by *version number, not date*, and mixes build families on one feed, so freshness **must** come from publish timestamps scoped by a version band. The network call is **fail-open** (any error → `$null`) and takes an injectable `-Fetcher` so it's fully unit-tested offline. - `Format-NightlyFeedBanner` — **pure, deterministic** renderer (caller passes `-Now`); tiers fresh/aging/stale + muted unknown/no-match. Thresholds are parameters (default 3/7 days). - **SR engine** (`Get-ReleaseReadiness.ps1`): on full (`all`) runs, maps the SR lane to `dotnet<Major>` + the `<Major>.0.<Patch>` band — in-flight SR → the SR branch's band; candidate → main's band — queries freshness, and renders the banner under the **Generated** line. Band-**number** matching is deliberate: it's resilient to family-keyword churn (an SR8 `.80` build is tagged `ci.main`, *not* `ci.inflight`, so a keyword match would miss it). - **Preview engine** (`Get-PreviewReadiness.ps1`): maps the preview to `dotnet<Major>` + the `<Major>.0.0-preview.<N>` band (iteration read from `Versions.props` at the survey ref), renders the banner under **Overall status**. - **Defensive load**: both engines dot-source the helper guarded by `Test-Path` + `Get-Command`; a missing/unloadable helper degrades to *no banner* rather than crashing the unattended nightly tracker job. The freshness query is wrapped in try/catch and gated to non-test code paths, so existing E2E tests stay network-free. ### Testing - **26 new offline assertions** for the helper: banner tiers, `unknown` / `matched=$false`, future-publish clamp, custom thresholds, deterministic publish date; and `Get-NightlyFeedFreshness` with a mocked `-Fetcher` covering newest-by-date (not version) selection, band-prefix filtering, fail-open on throw, and paged-registration `@id` follow-up. Plus SR render-path wiring assertions (banner appears after **Generated**; absent when the key isn't set). - **Offline suite: 592/0.** - **Live validation** against the real feeds (2026-06-22): `dotnet10 ^10.0.90-` → fresh today; `dotnet10 ^10.0.80-` → STALE 11d; `dotnet11 ^11.0.0-preview.` → fresh today. - Full suite is 602 passed / **2 pre-existing env-specific failures** in the *unmodified* `Find-ReleaseReadinessTrackers.ps1` E2E (its git-root guard fail-closes when run from a `/tmp` worktree without `-Repo`); identical on baseline, unrelated to this change. ### Follow-ups (out of scope) - The companion `Nightly-Builds` wiki page is stale (mislabels which branch feeds `dotnet9`/`dotnet10`, missing `dotnet11`); a corrected draft is being reviewed separately. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Description Updates `eng/scripts/get-maui-pr.sh` and `eng/scripts/get-maui-pr.ps1` so users can still apply PR package artifacts when the aggregate `maui-pr` build is red because of unrelated CI legs, as long as the package-producing artifacts exist for the current PR commit. ### Changes - Treat a red aggregate `maui-pr` build as a warning instead of an immediate abort. - Keep `PackageArtifacts` as the hard gate before downloading/applying packages. - Filter AzDO fallback builds to the current PR head/merge context using `triggerInfo.pr.sourceSha`, `sourceVersion`, and the PR merge SHA. - Warn when `Pack macOS` or `Pack Windows` timeline records do not report success. - Update troubleshooting text to refer to completed `maui-pr` builds with `PackageArtifacts` rather than green checks. ### Validation - `bash -n eng/scripts/get-maui-pr.sh` - PowerShell parser validation for `eng/scripts/get-maui-pr.ps1` - `git diff --check` - Local throwaway MAUI projects under `/Volumes/NieuwVolume/maui-pr-artifact-verification-20260616101523`: - PR `#35805`: red aggregate build `1461390`, `PackageArtifacts` present, pack jobs succeeded; Bash and PowerShell scripts applied package `10.0.80-ci.pr35805.26312.37`; `dotnet restore` succeeded. - PR `#35923`: green aggregate build path applied package `10.0.80-ci.pr35923.26315.57`; `dotnet restore` succeeded. - PR `#35626`: missing `PackageArtifacts` failed before mutating the project. - PR `#999999`: nonexistent PR failed cleanly during PR lookup. - Wrong-SHA harness for PR `#35805`: refused to use older completed builds when none matched the requested head/merge commit. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… VS Live Property Explorer (#36063) ### Issue details: After PR #33584 (BindableObject property access micro-optimizations), Visual Studio's Live Property Explorer stops showing any property values for MAUI controls. The feature becomes completely blank. ### Description of changes: PR #33584 removed GetLocalValueEnumerator(), LocalValueEnumerator, and LocalValueEntry from BindableObject as "unused dead code" — a grep of the MAUI codebase confirmed zero internal callers. However, Visual Studio's Live Property Explorer calls GetLocalValueEnumerator() via reflection at runtime to enumerate locally-set bindable property values on live objects. With these types removed, the reflection call fails silently and the panel shows nothing. This changes restores all three types, adapted to the new Dictionary<int, BindablePropertyContext> storage introduced by #33584 — the enumerator now iterates .Values (the BindablePropertyContext objects directly) and reads context.Property to expose the BindableProperty, since the dictionary key is now an int rather than the property itself. **Tested the behavior in the following platforms.** - [ ] Android - [x] Windows - [ ] iOS - [ ] Mac | Before | After | |---------|--------| | **Windows**<br> <video src="https://github.com/user-attachments/assets/df3a3448-c79c-4457-8901-f2a075087df4" width="300" height="600"> | **Windows**<br> <video src="https://github.com/user-attachments/assets/2dcbdb35-2336-44bd-9c8b-baf1f9b64b4a" width="300" height="600"> | --------- Co-authored-by: Gerald Versluis <gerald.versluis@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
<!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ### Description of Change Adds a guide for Microsoft maintainers and community contributors explaining the automated PR review workflow: - `/review` - `/review <platform>` - `/review rerun` - `/review tests` The guide also explains the `maui-copilot` pipeline flow, AI Summary and Test Failure Review comments, local `/review tests` usage, troubleshooting, and related implementation files. ### Companion review-output changes Beyond the documentation, this PR also refines the review-comment output to keep it consistent with the guide and with the project's review-symbol conventions: - **`Find-RegressionRisks.ps1`** — distinct colorless severity glyphs in the regression markdown (`✗` REVERT / `⚠` OVERLAP / `●` CLEAN). - **`post-ai-summary-comment.ps1`** — `Test-PhaseContentIsNoOp` recognizes the `●` (and legacy `🟢`) regression no-op markers so empty sections stay suppressed; **Next Steps** renders below **Review Sessions**. - **`post-inline-review.ps1`** — inline-comment marker uses a generic `(multi-model)` label instead of a hardcoded model roster. - **`pr-preflight.md`** — review-symbol set aligned (`✗`/`⚠`/`ℹ`). Producer/consumer pairs (e.g. the regression no-op markers) are kept in lock-step and covered by `Post-AISummaryComment.Tests.ps1`. ### Issues Fixed No issue filed. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: kubaflo <kubaflo@users.noreply.github.com>
…plementing AzDO (#36080) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## Problem The `/review rerun` scanner (`rerun-review-scanner`) dispatched **zero** AzDO reviews after #35955, and the few it should dispatch would target the wrong branch. Two independent bugs: ### Bug 1 — every dispatch aborted with a spurious 404 In the **gh-aw safe-output job**, the `gh` CLI returns `HTTP 404` for `repos/dotnet/maui/pulls/N` — even with `pull-requests: write` on a public repo. #35955 misread these as transient and "hardened" the not-found guard, so it now faithfully *confirms* the bogus 404 and skips every PR. Evidence it is not a permission/token problem: the `pre_activation` job (only `Metadata: read`) reads the same PRs fine, and the built-in `safe_outputs` job (octokit) succeeds in the same run. ### Bug 2 — custom review branches silently downgraded to `main` The candidate builder decided whose `/review -b <branch> -p <platform>` to trust using the comment's `author_association`. Under the Actions `GITHUB_TOKEN`, a maintainer whose org membership is private reads as `CONTRIBUTOR` (not `MEMBER`), so their command was dropped and the rerun fell back to the `main` pipeline. A live scan confirmed it dispatched four net11 (`feature/enhanced-reviewer`) PRs on `main`. ## Fix — do exactly what a maintainer `/review` does **Bug 1:** instead of re-implementing PR validation + OIDC + the AzDO trigger inside the safe job, the scanner now **dispatches the same `review-trigger.yml` workflow `/review` runs**, via `workflow_dispatch`. That workflow owns PR validation, the `s/agent-review-in-progress` lock, platform inference, OIDC, and the AzDO trigger. (`workflow_dispatch` via `GITHUB_TOKEN` always creates a run — it is exempt from Actions recursion-prevention.) - `Invoke-RerunReviewTrigger.ps1` is now pure: validate batched `decisions` against `candidates.json`, emit `actions.json`. No `gh`/AzDO/OIDC/lock/rate-limit I/O. - A `github-script` (octokit) step performs all GitHub writes — octokit works in the safe-job context where the `gh` CLI does not. `trigger` → `createWorkflowDispatch(review-trigger.yml,{pr_number,platform,pipeline_ref})` + 👍; `skip` → 👎 + remove the queue label. - Permissions: `+actions:write`, `−id-token:write`; dropped the `AZDO_TRIGGER_*` secrets from the job. **Bug 2:** authorize `/review` options by a **live collaborator-permission lookup** (`collaborators/<user>/permission` → write/maintain/admin) — the exact call `review-trigger.yml`'s auth step makes. It only needs `metadata: read` (every token has it) and reflects current access. **No new secret or permission.** - `Resolve-RerunEligibility.ps1`: add `Test-ReviewOptionLoginTrusted` (cached per login); `Get-LatestReviewCommandOptions` computes trust through it. Removed the `author_association` gate. - `Query-RerunReadyPRs.ps1`: drop the `author_association` helpers; pass `-Owner/-Repo`. ## Validation - **69 Pester tests pass** (36 dispatch + 33 resolver), incl. a regression test that an `author_association=NONE` command is still honored when the login has write access. - **Live, real (non-dry) scan**: the safe job validated all decisions with **no 404s** and octokit performed real `createWorkflowDispatch`, producing two `review-trigger.yml` runs that triggered real AzDO `maui-copilot` builds (HTTP 200, Run IDs 14459427 & 14459428). - **Real-data check for Bug 2**: PR #34564's history now resolves to `pipelineRef=feature/enhanced-reviewer` (author `kubaflo`, `author_association=CONTRIBUTOR`) instead of `main`, using the live permission lookup. ## Files - `.github/scripts/Invoke-RerunReviewTrigger.ps1`, `.github/scripts/Invoke-RerunReviewTrigger.Tests.ps1` - `.github/scripts/Resolve-RerunEligibility.ps1`, `.github/scripts/Resolve-RerunEligibility.Tests.ps1` - `.github/scripts/Query-RerunReadyPRs.ps1` - `.github/workflows/rerun-review-scanner.md` + recompiled `.lock.yml` - `.github/docs/agent-labels.md` --- 🔍 _This PR was created by an AI agent (GitHub Copilot CLI) on behalf of @kubaflo._ --------- Co-authored-by: kubaflo <kubaflo@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ts doc (#36067) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! ## Summary This is a **tooling/agent-infrastructure change only** (everything is under `.github/` plus the local `/review tests` runner) — no product source or public API changes. It converges the automated `/review tests` workflow (the `review-test-failures` skill) with the interactive `azdo-build-investigator` skill so that **both deliver the same end result** — a CI **merge-readiness verdict** plus a **base-branch baseline failure review** — while removing the duplicated MAUI CI knowledge that was copy-pasted across several files and at real risk of drifting. The two skills can't share *tooling* (the `ci-analysis` plugin that powers `azdo-build-investigator` is a stdio MCP server, which the gh-aw runtime can't run), so "minimal duplication" is achieved by sharing **docs**, not tools. ## Architecture: "shared knowledge, two roles" One canonical facts doc; every consumer references it instead of re-stating the facts. - **New `.github/docs/maui-ci-facts.md`** — single source of truth for pipeline names/IDs (`maui-pr` 302, `maui-pr-devicetests` 314, `maui-pr-uitests` 313), AzDO data sources, the XHarness exit-0 blind spot, test-count deduplication, the **baseline-comparison rule**, visual-baseline/platform-mismatch guidance, Gradle/CFSClean signatures, the common-failure-pattern table, and the **merge-readiness criteria**. Its header lists every consumer, kept bidirectionally accurate. ## What changed | Area | Change | | --- | --- | | `review-test-failures/SKILL.md` | References the facts doc; adds an **overall merge-readiness verdict** and **baseline reasoning** + an `On base?` column. | | `azdo-build-investigator/SKILL.md` | Slimmed (~106→68 lines) to reference the facts doc; keeps its unique value (ci-analysis-first, the outdated-`maui-public` correction, escalation to `helix-investigation`). | | `Gather-TestFailureContext.ps1` | Extends the deterministic gatherer with **per-test base-branch baseline extraction + comparison** (`failures.baseline`, `baselineMatchCount`, `baselineSummary`, `alsoFailsOnBaseline`). | | `copilot-review-tests.md` (+ lock) | Output template gains a **Baseline** badge, an `On base?` column, and merge-readiness verdict/colors. | | `Review-Tests.ps1` | Local runner: merge-readiness verdict→color map + a Baseline badge from `failures.baselineMatchCount`. | | `ci-status-main.md` / `ci-status-net11.md` (+ locks) | Removed duplicated pipeline-ID table, "key points" bullets, failure-pattern table, and dedup prose — now reference the facts doc; added a facts-doc existence check to the connectivity probe. | ## Validation - Both PowerShell scripts AST-parse cleanly. - `gh aw compile` of all three workflows: **0 errors**, and a second recompile is **idempotent** (no further lock diff) — the compiled `.lock.yml` files are in sync with their `.md` bodies. (gh-aw `{{#runtime-import}}`s the body and pins a `body_hash`, so body edits surface as a hash-only lock diff.) - Grep sweep confirms **no inline copies** of the canonical pipeline/failure-pattern tables remain outside the facts doc, and the facts-doc consumer list exactly matches the set of files that reference it (bidirectional). ## Intentionally out of scope (follow-up) A parallel "repo-health" analysis flagged a couple of broader items left untouched here: the pipeline name→ID table is still duplicated in `copilot-instructions.md` and `trigger-azdo-pipeline-setup`, and there are some dead `pr` agent references in `copilot-instructions.md`. Those are the next concentric ring of cleanup and aren't required for this convergence. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Reset patterns: - global.json - NuGet.config - eng/Version.Details.xml - eng/Versions.props - eng/common/*
Resolve modify/delete conflict on legacy eval.yaml by taking main's deletion (#35942 migrated skill-eval suite from skill-validator to Vally; eval.vally.yaml replaces it). All eng/versioning and auto-generated files retain net11.0 values. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
Author
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 36139Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 36139" |
Contributor
Author
Skill Validation Results
✅ Skill Validation Results —
|
Member
|
/azp run maui-pr-uitests |
|
No pipelines are associated with this pull request. |
This was referenced Jun 26, 2026
Member
|
/azp run maui-pr-uitests, maui-pr-devicetests |
|
Azure Pipelines successfully started running 2 pipeline(s). |
PureWeen
approved these changes
Jun 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
I detected changes in the main branch which have not been merged yet to net11.0. I'm a robot and am configured to help you automatically keep net11.0 up to date, so I've opened this PR.
This PR merges commits made on main by the following committers:
Instructions for merging from UI
This PR will not be auto-merged. When pull request checks pass, complete this PR by creating a merge commit, not a squash or rebase commit.
If this repo does not allow creating merge commits from the GitHub UI, use command line instructions.
Instructions for merging via command line
Run these commands to merge this pull request from the command line.
or if you are using SSH
After PR checks are complete push the branch
Instructions for resolving conflicts
Instructions for updating this pull request
Contributors to this repo have permission update this pull request by pushing to the branch 'merge/main-to-net11.0'. This can be done to resolve conflicts or make other changes to this pull request before it is merged.
The provided examples assume that the remote is named 'origin'. If you have a different remote name, please replace 'origin' with the name of your remote.
or if you are using SSH
Contact .NET Core Engineering (dotnet/dnceng) if you have questions or issues.
Also, if this PR was generated incorrectly, help us fix it. See https://github.com/dotnet/arcade/blob/main/.github/workflows/scripts/inter-branch-merge.ps1.