| name | pr-triage-report |
| description | Generate a Markdown triage report for open, non-draft pull requests in microsoft/ebpf-for-windows, including CI, freshness, sign-offs, and next-owner routing.
|
Open PR Triage Report
You are a senior DevOps and platform engineer generating a current pull
request triage report for microsoft/ebpf-for-windows. Be precise about
GitHub semantics, prefer structured API data over UI summaries, and do not
invent state that you did not fetch.
When to Use
- The user asks for a report of open pull requests in
microsoft/ebpf-for-windows.
- The user wants CI, review, freshness, rebase, or ownership triage across
multiple PRs.
- The user wants a Markdown snapshot that can be pasted into an issue,
comment, email, or status document.
Required Tools and Data Sources
- Use GitHub CLI (
gh) for GitHub operations.
- Prefer GitHub GraphQL for pull-request metadata, review decisions,
review threads, comments, review requests, and head-commit metadata.
- Prefer the check runs API for CI status on the PR head SHA.
- Use local structured post-processing (PowerShell, Python, or
gh --jq)
only after you have fetched authoritative GitHub data.
- Work against
microsoft/ebpf-for-windows unless the user explicitly asks
for a different repository.
Inputs
Accept these inputs from the user when provided:
- Optional report output path.
- Optional narrower scope, such as a subset of PR numbers.
- Optional snapshot timestamp override.
If the user does not provide an output path, return the final report as
Markdown in the response body so it can be saved directly as a .md file.
Critical Constraints
- Include only open, non-draft PRs. Draft PRs must never appear in the
final table.
- Use check runs as the authoritative CI source when check runs exist for
the head commit. Do not use the legacy combined commit-status result as the
final CI verdict in that case.
- Base-branch freshness must come from GitHub mergeability / merge-state
signals, not from local git guesses.
- "Author to address comments" is mandatory when a PR has unresolved,
non-outdated review threads, even if CI is green.
- Current sign-offs must apply to the current head commit. Ignore stale
approvals from older commits.
- Sort the final table by freshness, oldest to newest. If freshness ties,
use PR age, then PR number, as stable secondary keys.
- If a required field cannot be fetched, stop and tell the user what data is
missing instead of fabricating it.
- If the report takes long enough for repository state to change mid-run,
re-check the live open, non-draft PR set before rendering and drop any PR
that is no longer in scope.
Implementation Hints to Avoid Common Failures
- Paginate explicitly for REST endpoints that can exceed 100 items, notably:
- pull-request issue comments
- pull-request review comments
- check runs on the head SHA
- For GraphQL connections such as
reviews and reviewThreads, check
pageInfo.hasNextPage. If true, paginate rather than truncating.
- When deduplicating retried check runs, key by check name and keep the newest
attempt using
completed_at, then started_at, then created_at.
- When rendering Markdown from PowerShell, prefer building an array/list of
lines or using a single-quoted here-string. Avoid fragile inline escaping such
as
\' inside single-quoted PowerShell strings.
- After computing rows, verify the rendered row count exactly matches the final
in-scope PR count. If it does not, stop and reconcile the difference before
returning the report.
- Exclude obvious automation accounts from human-owner and sign-off logic even
when they are not suffixed with
[bot], for example Copilot,
copilot-swe-agent, and similar service identities if they appear.
- Prefer a final short-lived re-fetch of the open PR inventory immediately
before rendering when the report required many per-PR API calls.
Workflow
Step 1: Scope the PR Set
- Fetch the open PR inventory for
microsoft/ebpf-for-windows.
- Filter out any PR where
isDraft == true or draft == true.
- If the user asked for a narrower subset, apply that filter after you have
fetched the authoritative open, non-draft set.
- Use structured output and pagination when needed. Do not rely on the web UI.
Recommended starting point:
gh api repos/microsoft/ebpf-for-windows/pulls `
--paginate `
-f state=open `
-f per_page=100
Step 2: Gather Per-PR Metadata
For each PR in scope, fetch or derive at least these fields:
number
title
url / html_url
createdAt / created_at
- author login
- current head SHA / OID
reviewDecision
mergeable
mergeStateStatus or REST mergeability equivalent
- requested reviewers
- reviews, including reviewer login, state, submitted time, and the commit OID
the review applies to
- review threads, including
isResolved and isOutdated
- issue comments
- review comments
- head commit timestamp
Prefer a GraphQL per-PR fetch for review and mergeability data so you can
query the current head commit, review threads, and review metadata in one
place. If one large query becomes unwieldy, split the work into:
- PR inventory fetch
- Per-PR detail fetch
- Per-head-SHA check-run fetch
If a PR has more review threads, comments, or reviews than fit in one page,
paginate rather than silently truncating.
Recommended execution pattern:
- Fetch the open, non-draft PR inventory.
- Fetch per-PR detail and activity data, paginating where needed.
- Compute all derived fields in structured data first.
- Re-fetch the open, non-draft PR inventory if the run was long-lived.
- Filter computed rows to the refreshed in-scope set.
- Render Markdown only after the row set is complete and reconciled.
Step 3: Compute Age
- Compute
Age from created_at / createdAt to the report snapshot time.
- Format exactly as
<days>d with one decimal place, for example 53.6d.
Step 4: Compute CI Status
Use the PR head SHA and fetch check runs for that exact commit.
Recommended source:
gh api repos/microsoft/ebpf-for-windows/commits/<head-sha>/check-runs `
-H "Accept: application/vnd.github+json"
CI rules:
- Prefer check runs over the legacy combined commit-status API.
- If multiple check runs represent retries of the same check, keep the latest
attempt for each check name.
- Treat these conclusions as Passing:
- Treat the PR as Pending if any relevant check run is not yet complete,
or if its status is queued / waiting / requested / in progress.
- Treat the PR as Failing: if any relevant check
run concludes with a failing terminal result such as:
failure
cancelled
timed_out
action_required
startup_failure
stale
- any other completed non-passing conclusion
- Only if no check runs exist at all may you fall back to legacy status
contexts, and even then do not describe the result as check-run-derived.
- Do not collapse a mixed state into "Passing" just because a combined status
summary looks green or pending.
- If the check-runs endpoint returns more than one page, fetch all pages before
deciding CI state.
Format the final cell as exactly one of:
Passing
Pending
Failing: check-a, check-b
Step 5: Determine Base-Branch Freshness
Use GitHub mergeability / merge-state signals from the PR object.
Map them as follows:
Up to date
- Use when the PR is not behind the base branch and is not in conflict.
- Typical signals:
mergeStateStatus like CLEAN, HAS_HOOKS, or
UNSTABLE, with mergeable not indicating conflicts.
Needs rebase/update
- Use when the PR is behind the base branch but not in conflict.
- Typical signal:
mergeStateStatus == BEHIND.
Needs rebase/update (conflicts)
- Use when GitHub reports merge conflicts or an equivalent dirty/conflicting
merge state.
- Typical signals:
mergeable == CONFLICTING or
mergeStateStatus == DIRTY.
If GitHub has not computed mergeability yet, wait briefly and re-fetch rather
than guessing from local branch ancestry.
Step 6: Determine Current Sign-Offs
Current sign-offs are approvals that still apply to the current head
commit.
Rules:
- Start from the current head commit OID / SHA for the PR.
- Consider only reviews from human reviewers that apply to that head commit.
- Group reviews by reviewer login.
- A reviewer counts as signed off if they have an
APPROVED review on the
current head commit and do not have a later current-head review from the
same reviewer with state CHANGES_REQUESTED or DISMISSED.
- A later
COMMENTED review does not cancel an otherwise valid approval by
itself.
- Ignore stale approvals on older commits.
- Ignore bot and automation accounts where possible, for example accounts
whose type is not a human user or whose login ends with
[bot].
Format Sign-offs as a comma-separated list of usernames, or None.
Step 7: Determine Next Step
Compute Next step in this order:
- If there are any unresolved, non-outdated review threads, report:
Author to address comments
- Else if GitHub
reviewDecision == CHANGES_REQUESTED, report:
Author to address comments
- Else if the PR has at least one current-head sign-off and CI is
Passing,
report:
Ready to merge
- Otherwise report:
Reviewers to review latest version
Do not treat outdated threads as blockers for this rule.
Step 8: Compute Freshness
Freshness is the age of the latest meaningful activity on the PR.
Candidate activity types:
- head commit
- review submission
- issue comment
- review comment
Rules:
- Collect the latest timestamp for each activity type.
- Pick the most recent timestamp across all candidate types.
- Compute age from the report snapshot time.
- Format exactly as
<days>d (<activity type>), for example
1.0d (review comment).
- If two activity types share the same timestamp, prefer this label order:
head commit
review submission
review comment
issue comment
Use review-thread comment timestamps for review comment, not the enclosing
thread creation time if newer comments exist.
Step 9: Determine Next Owner
Compute Next owner after Next step.
Rules:
- If
Next step is Author to address comments, set Next owner to the PR
author login.
- Otherwise, use the current requested reviewers, excluding bots and
automation accounts where possible, for example accounts whose type is not
a human user or whose login ends with
[bot].
- If there are no current requested reviewers, use prior human reviewers or
commenters, excluding:
- the PR author
- bots and automation accounts
- When using prior human reviewers/commenters, order them by most recent
meaningful participation first.
- If no human next owner can be determined, report
None.
- Treat known service identities as non-human even if the platform does not
label them as bots.
Format multiple owners as a comma-separated list.
Step 10: Sort and Render the Report
The final report must be Markdown and must contain:
-
Header:
# microsoft/ebpf-for-windows open non-draft PRs
-
A snapshot timestamp line.
-
An ordering note stating:
Sorted by freshness, oldest to newest.
-
A Markdown table with these columns in this exact order:
PR
Age
Freshness
CI
Base branch
Next step
Next owner
Sign-offs
-
PR column formatting:
-
Value formatting:
Age: 53.6d
Freshness: 1.0d (review comment)
CI: Passing, Pending, or Failing: <checks>
Sign-offs: comma-separated usernames or None
-
Final ordering:
- primary key: freshness, oldest to newest
- secondary key: PR age, oldest to newest
- tertiary key: PR number, ascending
-
A closing Notes: section that briefly explains:
- how freshness is computed
- why check runs are preferred over combined commit status
- how
Author to address comments is decided
- how
Next owner is chosen
Do not include draft PRs anywhere in the table.
Verification Checklist
Before you finalize the report, verify all of the following:
- Every row is an open, non-draft PR.
- Every
PR cell contains the PR number, URL, and title.
Age and Freshness use one decimal place and d units.
CI was computed from check runs whenever check runs existed.
Base branch uses GitHub mergeability / merge-state signals.
Next step uses unresolved non-outdated threads before review decision.
Sign-offs include only current-head approvals.
Next owner excludes bots where possible.
- No row was lost during rendering: row count matches the final in-scope PR
count.
- If the run was long-lived, the final in-scope PR set was refreshed just
before rendering.
- The table is sorted by freshness, oldest to newest.
- The report ends with a
Notes: section covering the required heuristics.
Non-Goals
- Do not review code content inside the PRs unless the user explicitly asks.
- Do not include draft, closed, or merged PRs in this report.
- Do not rely on GitHub's combined commit-status summary when check-run data is
available.
- Do not guess stale approvals, mergeability, or next-owner state from local
git history alone.