Produce the QA checklist for one PR: numbered checks, each an action on the running app and the result to expect. Checks describe behaviour, so anyone can run them without reading the code; a check may still point at the file or test behind it for whoever wants to look.
Write in the language the ticket is written in (the PR description if there is no ticket).
If the repo documents its issue-tracker workflow (e.g. docs/agents/issue-tracker.md), follow it; the commands below assume GitHub via gh.
Process
1. Pin the PR
Take the PR number from the argument. Fetch:
gh pr view <n> --json number,title,body,headRefName,commentsgh pr diff <n>
Stop and tell the user if the PR does not resolve or the diff is empty.
2. Fetch the acceptance criteria
Find the ticket from issue references in the PR body or its commits (Closes #m, Part of #m), then gh issue view <m> --comments. Extract its acceptance criteria verbatim.
If the PR references no ticket, ask the user for it. If they say there is none, derive the criteria from the PR description and open the checklist with one line saying so.
3. Map the diff
Walk every hunk and label it observable (a user, a caller of a public endpoint, or a job output sees it change) or internal (refactor, type change, logging, test, config). Step 4 spends the list.
4. Write the checks
Each check is numbered QA-<k> and has one shape: where to go, what to do, what to expect. Short, one action, one result. Add a → path/to/file or → test name after the check only when it helps whoever verifies at code level.
Cover, in order:
- Every acceptance criterion from step 2: at least one check each. A criterion the diff does not implement is still a check, marked (not found in diff), so missing work is caught rather than assumed.
- Every observable hunk from step 3 not covered by a criterion: a check marked (outside the criteria), so extra behaviour is seen before it is merged.
- One negative check per error path or branch the diff adds: wrong input, empty input, external call failing.
Every internal hunk goes under Not covered by these checks, one line each stating what it changes, so the reader knows exactly where the checklist stops.
Done when: every acceptance criterion has a check, every changed file is named by a check or listed as not covered.
5. Post
Write the checklist to a file and post it as a PR comment (gh pr comment <n> --body-file). If the PR already carries a QA comment (found in step 1), edit that comment's body instead of adding a second one (gh api repos/{owner}/{repo}/issues/comments/<id> -X PATCH -F body=@<file>). Tell the user where it is.
Template (translate the headings into the checklist language; keep the QA-<k> ids as they are):
## QA — PR #<n> · ticket #<m>
**Setup**: <one line: branch to check out and how to run the app, from the repo's own run instructions>
### Checks
- [ ] **QA-1** — <where>. <what to do>. Expect: <result>. → `<file or test, optional>`
- [ ] **QA-2** — …
### Edge cases
- [ ] **QA-<k>** — <scenario>. Expect: <result>.
### Not covered by these checks
- <what it changes, one line>