| name | mergequeue-pr-triage |
| description | Diagnose why a pull request submitted to the Trunk Merge Queue has not merged yet. Use when the user asks "why isn't my PR merged", "why is my PR not merging", "what's blocking PR #1234", "is my PR stuck", "check my merge queue status", "where is my PR in the queue", or "why did my PR fail in the merge queue". Read-only: it diagnoses and explains, it never enqueues, cancels, reprioritizes, or otherwise changes the queue. |
| license | MIT |
Merge Queue PR Triage
Diagnose why a PR hasn't merged in the Trunk Merge Queue and explain it in plain English:
the single most likely reason, the supporting evidence, and concrete next steps.
This skill is strictly read-only. Never enqueue, cancel, re-prioritize, restart tests, or
otherwise mutate the queue — only report and recommend.
Prerequisites
TRUNK_API_TOKEN must be set (a Trunk repo/API token). The script sends it as the
x-api-token header and never logs it. If it is missing, tell the user to set it and stop.
python3 (no third-party packages). gh (GitHub CLI) is optional — used only to auto-detect
the PR number and target branch from the current branch.
The script lives at scripts/trunk_mq.py relative to this file.
Step 1 — Gather the data
Run the bundled triage command. It resolves the repo, PR number, and target branch automatically
(explicit values → TRUNK_REPO env → local git / gh), then returns one JSON bundle with the
PR's queue state, testing details (when relevant), and the surrounding queue:
python3 scripts/trunk_mq.py triage
Pass values explicitly when you have them or auto-resolution can't (e.g. a deployed agent with no
git checkout):
python3 scripts/trunk_mq.py triage --repo github.com/<owner>/<repo> --pr 1234 --target main
The bundle looks like:
{
"repo": { "host": "...", "owner": "...", "name": "..." },
"prNumber": 1234,
"targetBranch": "main",
"pullRequest": { "state": "...", "readiness": { ... }, "testedCommits": [ ... ], ... },
"testingDetails": { "statusChecks": [ ... ], "checkSuites": [ ... ], "dependentPrs": [ ... ], ... },
"queue": { "pullRequests": [ ... ] },
"notes": [ ]
}
If you need finer control, the individual subcommands return raw endpoint responses:
get-pr, testing-details --test-run-id <id>, list-prs [--state <s>] [--take <n>].
All accept --print-request to preview the exact request (token redacted) without sending it.
If the command errors, relay its message — it is written to be user-actionable (missing token,
PR not in queue, network failure, etc.). Do not retry mutating anything.
Step 2 — Diagnose
Map pullRequest.state (plus readiness) to the single most likely reason. Evaluate in this
order:
merged → It already merged. Report the merge; nothing is wrong.
not_ready → Inspect readiness:
doesBaseBranchMatch == false → the PR's base branch is out of date or targets the wrong
branch.
requiresImpactedTargets == true && hasImpactedTargets == false → impacted build/test targets
haven't been reported yet.
gitHubMergeability == "not_mergeable" → a GitHub-side block: merge conflict, failing
required check, missing review, or branch protection.
gitHubMergeability == "in_progress" → GitHub is still computing mergeability; likely just
needs a moment.
- (
gitHubMergeability is an enum: unspecified | in_progress | mergeable | not_mergeable.)
pending → In the queue, waiting its turn. Use queue.pullRequests to report how many PRs
are ahead and whether any have higher priorityValue or skipTheLine == true.
testing → The speculative test branch is running. Read testingDetails; report which
statusChecks / checkSuites.checkRuns are still in progress.
tests_passed → Tests passed; waiting to merge (behind others, or a brief merge window).
failed / pending_failure → A test run failed. From testingDetails, name the specific
failing check: statusChecks[].context where state is ERROR/FAILURE, and
checkSuites[].checkRuns[].name where conclusion is FAILURE/TIMED_OUT/ACTION_REQUIRED.
Check dependentPrs / testedPullRequests: if a predecessor PR in the same speculative
run is the one that failed, say so explicitly — the user's PR may be innocent and just needs the
predecessor resolved or a re-test.
cancelled → Removed from the queue. Report it and suggest the user re-enqueue (do not
do it yourself).
Always cross-reference testedCommits: an entry with conclusion: "failed" corroborates a
real test failure; all succeeded while the PR still hasn't merged points to queue position
rather than a failure. If testedCommits is absent/empty or notes says the drill-down was
skipped, do not invent a failing check — diagnose from state + readiness and say the
check-level detail wasn't available.
Do not invent fields or endpoints beyond those above. If a deeper signal would be needed, note it
as a follow-up rather than fabricating it.
Step 3 — Answer
Lead with the verdict. Keep it scannable:
- Verdict — one sentence: the single most likely reason it isn't merged.
- Evidence — the deciding fields:
state, the specific readiness flag, the named failing
check, or the queue position.
- Next steps — concrete and specific, e.g. "rebase on
main", "fix failing check
<name>", "nothing to do — 3 PRs ahead, all tests green", "re-enqueue; it was cancelled".
Example
Verdict: PR #1234 isn't merging because a required check is failing in the merge queue.
Evidence: State is failed. The test run's statusChecks shows ci/unit-tests →
FAILURE. The latest testedCommits entry is conclusion: failed, and dependentPrs is
empty — this is your PR's own failure, not a predecessor's.
Next steps: Fix ci/unit-tests (it failed on your changes), push, and the queue will
re-test automatically. No queue action needed from me.