Add ha-merge-queue skill for merge-ready PR detection (#180152)

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Martin Hjelmare
2026-08-25 15:01:44 -04:00
committed by GitHub
co-authored by Claude
parent 1d935e5c7c
commit f75eb8eb9e
+118
View File
@@ -0,0 +1,118 @@
---
name: ha-merge-queue
description: Finds open Home Assistant pull requests that are genuinely ready to merge, checking CI, the merge-gate statuses, code-owner approval, merge conflicts, requested changes and unresolved review threads. Use when looking for PRs to merge, doing merge-queue triage, or asking for "quick wins" from the open PR backlog.
---
# Find Ready-to-Merge Pull Requests
Produce a shortlist of open PRs a maintainer can approve and merge immediately, plus a
short list of near-misses that each need one specific nudge. Default to 10 candidates
unless the user asks for a different number.
## Gather candidates
Search open PRs, excluding those that are structurally not mergeable:
```
repo:home-assistant/core is:open is:pr draft:false status:success -review:changes_requested
-label:"awaiting-frontend" -label:"stale" -label:"cla-needed"
```
Add `label:"small-pr"` for quick wins, or `label:"code-owner-approved"` / `review:approved`
for PRs already carrying an approval. Run several searches and pool the results — no single
query surfaces everything.
The search index lags reality by hours. Treat `status:` as a rough filter, never as proof;
verify every finalist with the per-PR checks below.
## Verify each finalist
Check all five. A PR fails the shortlist if any one fails.
Paginate every list response before deciding. Check runs, reviews and review threads are all
paged, typically 30 per page, and a full-suite Home Assistant PR runs to 40-odd check runs —
so page one shows a green subset while a failure or a standing review sits on page two.
Compare the returned count against the reported total and keep fetching until they match.
1. **Merge-gate statuses** — fetch the combined commit status. This is the cheapest and
most informative call, and it is what actually blocks the merge button. Five contexts
matter: `code-owner-approval` (required for Platinum integrations),
`required-labels` (red when the author checked no "Type of change" box),
`docs-missing` (red when a user-facing change has no documentation PR), `cla-bot`, and
`blocking-label-awaiting-frontend`.
2. **Check runs** — the commit statuses do not cover GitHub Actions. Fetch the check runs
and require every one to have reached an acceptable terminal result: `status` must be
`completed`, and `conclusion` must be `success`, `skipped` or `neutral`. Everything else
disqualifies — `failure`, `cancelled`, `timed_out`, `action_required` and `stale`, and
any run still `queued` or `in_progress`. A green combined status sitting on top of a red
or still-running test job is common, so the status list alone is never enough.
3. **Merge conflicts** — read `mergeable_state`. GitHub computes it asynchronously: a
request that finds no cached answer returns `unknown` and starts the computation, and
the request after that can still return `unknown`. Poll with bounded retries — a few
attempts, pausing between them — and treat an `unknown` that never resolves as not
ready, rather than assuming it is fine.
- `clean` — every merge requirement met; merge now
- `blocked` — some branch-protection requirement is unmet. It does not specifically mean
"waiting on an approval", so do not report it that way by default: use the other four
checks to establish which requirement is missing, and only call it awaiting review once
they all come back clean.
- `behind` — the base branch has moved on. Actionable and often a one-click update, so
surface it rather than dropping the PR.
- `unstable` — a non-required check is failing. Find out which one before shortlisting.
- `dirty` — merge conflict. The author needs to merge `dev` into the branch. Do not tell
them to rebase: `AGENTS.md` forbids rewriting history on a PR branch once the PR is
open, because reviewers need to see what changed since their last review.
`homeassistant/generated/integrations.json` conflicts constantly, so PRs adding
integrations go stale fast.
- anything else (`draft`, `has_hooks`, a value not listed here) — do not guess at what it
means. Treat the PR as not ready and report the value you got.
4. **Review submissions** — fetch the reviews, not just the threads. A `CHANGES_REQUESTED`
review is returned here and nowhere else, and a reviewer can request changes with only a
top-level body and no inline comments — such a PR has zero open review threads and looks
clean to the check above. Take the latest submission per reviewer: a standing
`CHANGES_REQUESTED` that no later `APPROVED` from the same person supersedes disqualifies
the PR, regardless of whether its inline threads have since been resolved — resolving a
thread does not withdraw the review. Do not lean on the `-review:changes_requested`
search qualifier instead — the
index is stale, and `mergeable_state: blocked` does not distinguish "needs an approval"
from "changes were requested".
5. **Review threads** — fetch review threads and read `is_resolved`. Judge a thread by
whether it is resolved or substantively addressed, never by who wrote it: an unresolved
finding from `copilot-pull-request-reviewer` is a bug report and can be a real defect,
so read it on its merits before discounting it. Every thread still open counts against
the PR until you have read it and concluded it needs no change — the question was
answered, the suggestion was considered and declined, the point was fixed elsewhere in
the diff. Say for each open thread what it is and why it does or does not block. Never
discount one for the category it appears to fall into; an unaddressed defect is a
blocker whether or not anyone is arguing about it.
## Report
Rank by how little work each PR needs: `clean` first, then `blocked` with everything else
green. For each PR give the number as a full markdown link, the integration or core area,
one line on what it does, and its blocking state. Plenty of `home-assistant/core` PRs touch
helpers, the framework, the recorder or repo tooling and have no integration at all — name
what they touch instead, rather than dropping them or inventing one.
Then list the near-misses separately, each with the one action that unblocks it. The
recurring ones:
- A failing test unrelated to the diff — name the test, say re-run the job.
- `required-labels` red — name the label to add (`bugfix`, `new-feature`, …).
- Awaiting code-owner approval — name the code owner from `manifest.json`.
- A standing `CHANGES_REQUESTED` review — name the reviewer, and say what they asked for.
- `dirty` — the author must merge `dev` and regenerate any generated files.
Call out mismatches worth a maintainer's attention: a PR whose body declares a breaking
change but carries no `breaking-change` label will silently miss the release notes.
## IMPORTANT
- Only report in the CONSOLE. DO NOT ACT ON GITHUB — no comments, no reviews, no merges,
no pushes to contributor branches. Per `AI_POLICY.md`, a human decides and acts.
- Never call a PR ready on green CI alone. Read the diff of every PR you shortlist; CI
cannot tell you whether the change is correct or wanted.