Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Triage a QA-labeled report — investigate it against the code, classify it, and draft the technical issue(s) it warrants, stopping for approval before creating anything.
.claude/skills/joshukraine-qa-triage/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-06 | ✗→✓ | ▲ Improved | 215% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 220% | 0% |
| case-15 | ✗→✓ | ▲ Improved | 162% | 0% |
| case-16 | ✗→✓ | ▲ Improved | 142% | 0% |
| case-22 | ✗→✓ | ▲ Improved | 17% | 0% |
Turn a QA report into a triaged decision and, where warranted, one or more well-formed technical issues — without resolving the report off the bat or writing any app code.
QA reports (filed by a tester, usually carrying a qa label) are the _tester's view_ of a problem. They describe user-visible symptoms; the engineering fix is often differently scoped — one report may need several tech issues, or several reports may share one root cause. This skill does the standard review-and-extrapolate ritual: read the report, confirm it against the codebase, decide what (if anything) to build, and draft the issue(s) — then stop for the human to approve before anything is created.
Where it sits in the workflow. This is the _first_ step for a qa-labeled issue. Its output feeds the normal pipeline: an approved tech issue goes to /resolve-issue → /create-pr → /walkthrough + /code-review → merge. This skill never implements; it only triages and drafts. When several qa reports accumulate, /qa-triage-batch fans this skill out across the whole queue and reconciles shared root causes _across_ reports behind one consolidated gate — use it for a backlog; use this skill directly for a single report.
Applicability. Needs a GitHub repo (gh). Built around a QA-report labeling convention but otherwise project-agnostic — no project names, tester identities, or paths are hardcoded. It reads the project's CLAUDE.md for local conventions (board, workflow, bilingual i18n, etc.) and embeds the rest itself.
Not the same as:
/resolve-issue — it _implements_ an approved issue. This one _creates_ the issue for it to implement. Hand off; don't duplicate./qa-handoff, /walkthrough — those help a tester _exercise_ the app and _file_ reports. This one _processes_ a report after it's filed.A QA report is an input, not a directive. It is taken seriously, but it is not gospel: a tester may misread intended behavior, or suggest a change that would be counterproductive. The product decision — whether and how to act, including on items framed as "fixes" — belongs to the human, worked through a separate tech issue. So this skill's job ends at a decision gate: it analyzes and proposes; the human decides. The only thing it ever routes straight to resolution — instead of into a drafted tech issue — is an explicit, approved trivial-cosmetic fix, and even that is handed to /resolve-issue; this skill never writes app code itself.
When passed more than one issue number, triage each in turn, presenting a full analysis and decision gate per report before moving to the next.
gh issue view <N> --json number,title,body,labels,author,comments,url — capture the symptom, steps, expected vs actual, locale, screenshots, and the author (needed later for the verification @-mention).qa label. If it clearly isn't a QA report, say so and confirm the user still wants to triage it.CLAUDE.md (and any QA-workflow notes it points to) for: whether the project uses a separate-tech-issue workflow, a project board, type-label taxonomy, bilingual/i18n requirements, and viewport/mobile rules. Adapt to what you find; default to the separate-tech-issue pattern for non-trivial work.gh api user --jq .login. You'll compare it to the report author for the @-mention.validates :event_type exists on the model; the field is an unbacked string column").if x.present?), defaults, the absence or presence of a validation, and existing tests reveal whether the current behavior was _chosen_. Code that consistently tolerates the reported state was most likely written to allow it — a strong signal the report is a feature ask or working-as-intended, not a regression.Sort the report into exactly one bucket and recommend the matching action:
| Bucket | What it looks like | Recommended action | | --- | --- | --- | | Not a bug / intended | The reported behavior is correct, or the suggestion would be counterproductive | Propose closing the QA report with an explanatory comment (@-mention the author so they understand the reasoning and can push back). No tech issue. | | Trivial cosmetic | Typo, label wording, a one-line i18n change with an obvious, low-risk fix | Resolve the QA report directly — recommend handing it straight to /resolve-issue <qa-N>. No separate tech issue. | | One tech issue | A real defect or feature with a single, coherent fix | Draft one tech issue (template below). | | Multiple / cluster | The report spans several code areas, or several reports share one root cause | Draft each tech issue; apply the multi-PR closing rule below. |
When unsure between buckets, surface the ambiguity at the gate rather than guessing — especially the "is this even intended behavior?" question, which is the human's to answer.
For every tech issue you'd create, draft it in full (don't create yet) using the Tech issue template below:
feat:/fix:/chore:/docs:). This doubles as the type label so /resolve-issue can infer the branch prefix.- [ ] checklist /resolve-issue can check off. Include "mark the Honeybadger fault Resolved after deploy" when applicable.Triggered by QA report #<qa> line. ("Triggered by" is deliberately a non-keyword verb — it creates a reference, never an auto-close.)qa label to tech issues — that label belongs to reports.Present, per report: what you found in the code, the classification with reasoning, and the full draft of each proposed issue (title, body, labels) plus the proposed @-mention. Then STOP and ask for approval. The human may approve as-is, edit, reclassify, decline (e.g. close as working-as-intended), or defer. Do not create, comment, edit, or close anything before you get a clear yes.
gh issue create --title … --body-file <tmp> --label <type>. Use a temp file for the body to avoid shell-quoting pitfalls; remove it after.CLAUDE.md or gh project list), add the new issue(s); otherwise skip./resolve-issue <qa-N> directly. Its closing PR resolves the QA report, so it must still carry the verification @-mention; record this closing line for it: Closes #<qa> — please verify after deploy, @<author> (the resolver emits a bare Closes #N by default).Report what was created and recommend the next command: /resolve-issue <tech-N>. Do not start implementing.
The QA-report @-mention is a verification ping — it tells whoever should confirm the fix after deploy. That person is, by definition, the report's author.
@<report-author> (from step 1) in the closing plan.close/closes/closed, fix/fixes/fixed, resolve/resolves/resolved) appears immediately before any #N _anywhere in the PR body_ — not just on the Closes: line. When a PR should _reference_ but not close an issue, never put a keyword right before its #N: drop the # ("QA report 503") or use a non-keyword verb ("addresses", "wraps up"). This is the trap that prematurely closes QA reports.Closes #<tech>, Closes #<qa> — please verify after deploy, @<author>
Closes #<tech>) and must carry no auto-closing reference to the QA report. The last tech issue's closing plan carries the full dual-close + @-mention line.markdown<One-paragraph problem statement grounded in the triage: the real defect/need and its root cause in the code — not a restatement of the tester's symptom.> Triggered by QA report #<qa>. ## Acceptance criteria - [ ] <observable, testable outcome> - [ ] <edge case / affected locale / regression guard> - [ ] Mark Honeybadger fault <id> Resolved after deploy ← only if the report cites one ## Closing plan When the PR for this issue lands, close with: `Closes #<this>, Closes #<qa> — please verify after deploy, @<author>` <For a multi-issue report, replace the line above on every issue EXCEPT the final one with: "Closes #<this> only — do NOT reference the QA report with a closing keyword (see closing-keyword hazard)." The final issue carries the dual-close line.>
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-04 | pass→pass | 4,681 | 2,439 | -48% | 1 | 1 | 0% | 793 | 3,156 | +298% | 0 | 0 | — |
case-01 | fail→fail | 4,725 | 12,798 | +171% | 1 | 1 | 0% | 713 | 2,974 | +317% | 0 | 0 | — |
case-02 | fail→fail | 3,789 | 32,364 | +754% | 1 | 1 | 0% | 525 | 8,427 | +1505% | 0 | 0 | — |
case-03 | fail→fail | 4,602 | 57,163 | +1142% | 1 | 1 | 0% | 231 | 2,850 | +1134% | 0 | 0 | — |
case-05 | pass→pass | 11,588 | 1,988 | -83% | 1 | 1 | 0% | 1,788 | 3,019 | +69% | 0 | 0 | — |
case-06 | fail→pass | 7,291 | 7,040 | -3% | 1 | 1 | 0% | 1,270 | 3,995 | +215% | 0 | 0 | — |
case-07 | pass→pass | 10,571 | 3,899 | -63% | 1 | 1 | 0% | 1,555 | 3,404 | +119% | 0 | 0 | — |
case-08 | pass→fail | 9,559 | 9,859 | +3% | 1 | 1 | 0% | 1,415 | 3,046 | +115% | 0 | 0 | — |
case-09 | pass→pass | 9,980 | 4,861 | -51% | 1 | 1 | 0% | 1,527 | 3,634 | +138% | 0 | 0 | — |
case-10 | pass→pass | 8,895 | 3,359 | -62% | 1 | 1 | 0% | 1,536 | 3,362 | +119% | 0 | 0 | — |
case-11 | fail→pass | 6,401 | 3,116 | -51% | 1 | 1 | 0% | 992 | 3,179 | +220% | 0 | 0 | — |
case-12 | pass→pass | 5,126 | 2,740 | -47% | 1 | 1 | 0% | 725 | 3,180 | +339% | 0 | 0 | — |
case-13 | pass→pass | 9,994 | 3,683 | -63% | 1 | 1 | 0% | 1,454 | 3,212 | +121% | 0 | 0 | — |
case-14 | pass→pass | 8,136 | 3,081 | -62% | 1 | 1 | 0% | 1,278 | 3,221 | +152% | 0 | 0 | — |
case-15 | fail→pass | 8,373 | 2,966 | -65% | 1 | 1 | 0% | 1,199 | 3,143 | +162% | 0 | 0 | — |
case-16 | fail→pass | 9,181 | 3,382 | -63% | 1 | 1 | 0% | 1,366 | 3,302 | +142% | 0 | 0 | — |
case-17 | pass→pass | 10,083 | 4,514 | -55% | 1 | 1 | 0% | 1,439 | 3,446 | +139% | 0 | 0 | — |
case-18 | fail→fail | 10,082 | 8,365 | -17% | 1 | 1 | 0% | 1,476 | 3,215 | +118% | 0 | 0 | — |
case-19 | pass→pass | 7,522 | 3,938 | -48% | 1 | 1 | 0% | 1,132 | 3,234 | +186% | 0 | 0 | — |
case-20 | fail→fail | 3,646 | 20,901 | +473% | 1 | 1 | 0% | 575 | 6,115 | +963% | 0 | 0 | — |
case-21 | fail→fail | 3,039 | 16,368 | +439% | 1 | 1 | 0% | 458 | 3,156 | +589% | 0 | 0 | — |
case-22 | fail→pass | 14,827 | 3,360 | -77% | 1 | 1 | 0% | 2,819 | 3,305 | +17% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 15 counted toward the lift figure. The other 7 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +18 percentage points is the difference between those two pass rates over the 15 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.