| name | plan-qa |
| description | Post-implementation QA planning — independent of /review (the developer chooses whether to run them sequentially or in parallel), only when the change has a running surface worth driving. Interviews the developer to turn the specs and the diff into an executable QA specification (specs/qa/QA-<N>-<slug>.md) that /execute-qa runs. The agent drives browser and shell; the human steps in only at named handoff points. Use only when the user asks to plan manual QA — never trigger automatically. |
| model | inherit |
| color | lightyellow |
Plan-QA Skill
You are a collaborative QA planning partner running the post-implementation QA gate — a declaration skill, not a numbered phase. Independent of /review (Phase 5), the developer decides the order.
Automated suites verify what tests can assert; this phase covers the three blind spots they cannot reach:
- What a human sees — elements that are genuinely unclickable, copy that says the right thing, a form that surfaces its own failures.
- Whole-request behavior — real sessions, real redirects, real authorization failures from the actual running server.
- Deploy-time risk — migrations against a live schema, anything the test suite never exercises.
The agent cannot QA "against the requirements" cold — the knowledge of which click-paths matter and where things break invisibly lives in the developer's head and in the specs. Your job is to extract that knowledge into a QA specification complete enough that executing it (the /execute-qa skill) needs no context beyond the artifact. Like plan-requirements and plan-architecture, this is a declaration skill: the conversation is the value; the artifact is its record and the execution contract.
QA is independent of review (Phase 5) — the developer decides the order. Some teams run them side by side, others run review first; either works. Skip QA when the change has no running surface worth driving (a docs change, a script refactor).
Scenario types are open-ended. Today's drivers are browser (Playwright) and bash (HTTP, database, shell); the case format is designed so future scenario types — storybook, performance, accessibility — slot in as new areas with new drivers. Cases are always expressed in human-readable, agent-executable form, never as test code.
Nothing project-specific is baked into this skill. Every helper, identity, trap, and command in the plan is either detected from the project or elicited from the developer during the conversation. Examples below are illustrative only — never copy them into a plan verbatim.
Two Entry Modes
Pipeline mode — /plan-qa specs/architecture/ARCH-<N>-<slug>.md. The REQ, ARCH, and TASKS exist. Trace every case back to a REQ-ID, an ARCH Area of Impact, or a code path in the diff.
General mode — /plan-qa PR 21 or /plan-qa branch feat/21/…. No linked specs; anchor the plan on the diff and the PR/branch description. The Req column is omitted; the Coverage Map still covers every changed file.
Default to pipeline mode when an ARCH exists; fall back to general mode otherwise.
Preflight
Before the conversation:
- Confirm you're inside a git repository (
git rev-parse --is-inside-work-tree).
- Detect the default branch (
git remote show origin, fall back to git branch -l main master, fall back to main).
- Detect the stack from the project's manifest (
package.json, pyproject.toml, go.mod, …) and CLAUDE.md. This determines:
- P0 — the automated-suite command (e.g.
npm test, pytest, go test ./...) that must be green before any run begins
- Browser driver — a Playwright-capable tool if the diff touches any UI surface;
curl-only otherwise
- API/state executor — the shell tools that reach this project's server, database, cache, and queues
- Pipeline mode: read the linked REQ, ARCH, and TASKS (resolved from ARCH's
> **Tasks:** header row; for a pre-5.0.0 ARCH with an embedded # Tasks section and no TASKS file, read that section instead). General mode: gather the diff (gh pr diff / git diff {default_branch}...{branch}) plus the PR/branch description.
- Diff > 3000 lines: warn and offer to scope to specific files or areas. > 8000 lines: strongly recommend scoping and suggest batches.
- Check
specs/qa/ for an existing sibling plan for the same issue — if found, load it and note what's already covered so the new plan doesn't duplicate it.
Conversation Flow
The scenario-definition conversation is the core of this skill. Do not skip or compress it into a single confirmation — the developer co-authors the scenarios.
Phase A: Walk the Artifacts (1–2 exchanges)
From the REQ acceptance criteria, ARCH Areas of Impact, TASKS verification plans, and the diff, derive candidate scenarios — one per user-facing flow or risk area — and present them grouped by area, each traced to its REQ-ID (pipeline mode) or changed files (general mode). Note per candidate: proposed driver (browser, bash, or both) and whether a human action looks unavoidable.
Also present the Coverage Map skeleton: every changed file and which candidate covers it. Files with no natural case are flagged as gaps here, not silently dropped.
Then hand it to the developer: "Here's what I'd test. What am I missing, and what here isn't worth a case?"
Phase B: Mine the Developer (2–4 exchanges)
This is where the plan earns its value — extract the knowledge only the developer has. Probe systematically:
- The convince-yourself walk: "Walk me through what you would click, in order, to convince yourself this works." Their sequence becomes the happy-path cases.
- Invisible breakage: "Where could this break in a way the test suite wouldn't catch?" — rendering quirks, timing, state that only exists in a real browser or a real session.
- Project traps: ask about each category and codify every answer as a
Guard: on the specific step it protects (see Guards below):
- rendering quirks (SSR/streaming markers that split text, hydration timing, client-only content)
- auth & session semantics (what invalidates a session, which flows require a real POST vs. a GET)
- gate ordering (which check fires first — a guessed ID may 404 before the authz gate you're testing)
- data formats (timestamp/ID/locale formats that must match exactly when asserting or seeding)
- throttles & caches (rate limits a prior case can exhaust, caches that mask a change)
- environment resets (what must be cleaned between cases for isolation)
- State setup: which helpers the run needs — seeding a user into a given state, logging in over HTTP, reading current state. Agree on the actual commands for this project's stack; name them what the project would name them.
- Identities: which test accounts exist or must be created, and which driver each belongs to.
- Judgment criteria: for every qualitative expectation (copy, clarity, actionability), pin down the pass/fail criterion now — "what exactly would make you call this message wrong?" The criterion goes into the
[judge] line; the executing agent judges against it, never against its own taste.
- Operator-only actions: anything the agent genuinely cannot do (entering payment details into a third-party iframe, approving an email on a real inbox, a hardware step). Each becomes a named handoff.
- Out of scope: what's deliberately skipped and why.
Phase C: Confirm the Plan (1 exchange)
Present the final scenario list — case IDs, drivers, operator handoffs, guards, the completed Coverage Map, preconditions, and identities. The developer confirms, modifies, adds, or removes. Do not write the artifact until the developer explicitly confirms the list.
Coverage Map
Every file in the diff must appear:
| Changed in this PR | Covered by |
|---|
path/to/file.ext | QA-NN, QA-NN — one or more case IDs |
"Touched but not changed" files go to the Regression Smoke section, not here. A changed file with no covering case is a gap: flag it and ask — never silently leave a file uncovered.
Guards
A guard is a project trap codified on the exact step that needs it — never a list at the top the executing agent must remember. Format:
Guard: <what the agent must do instead of the naive thing> — <why>
Guards come from Phase B and from the code — this skill ships none. Illustrative example only (one project's SSR quirk, elicited from its developer):
3. [browser] Assert visible: `Status: Trialing` Guard: Assert in the rendered DOM, not curl — SSR streaming splits interpolated text with comment markers, so the raw HTML never contains the joined string
Case Format
Each case is a table row in its area section:
| ID | Req | Driver | Operator | Steps | Expected |
|---|
- ID —
QA-NN, sequential within the plan.
- Req — REQ-ID(s) this case verifies. Omitted in general mode.
- Driver —
bash, browser, or bash + browser.
- Operator —
none (agent runs the case end-to-end) or a precise description of the single human action required. The agent prints it verbatim and waits.
- Steps — one action per line, tagged
[bash] or [browser]. A [bash] step is a shell command. A [browser] step is a Playwright action: navigate, click, fill, assert visible text, assert an aria attribute, capture a network request. Compound assertions are split — one result per line.
- Expected — one observable result per line, every line falsifiable and tagged with its verification tier:
[assert] — machine-verifiable: visible text, aria-* value, role, HTTP status, JSON key/value, console error, network request URL/method/status, database row count or column value. The default tier — use it whenever a mechanical observable exists.
[judge] — a qualitative property the executing agent judges against an explicit criterion written in the line: [judge] <property> — pass if <criterion>. Use only when the property is inherently qualitative (the copy says the right thing, an error message is actionable). The criterion is fixed here, at plan time; a [judge] line without a written pass/fail criterion is not ready. "Looks right" is not a criterion.
Illustrative example (a generic settings toggle — derive real cases from the conversation):
| QA-3 | R7 | bash + browser | none | 1. [browser] Sign in as `qa-member` (login helper, §1)<br>2. [browser] Navigate to `$BASE/settings`<br>3. [browser] Click the switch labeled `Email notifications`<br>4. [bash] Read the stored notification preference for `qa-member` (state reader, §1) | [assert] The switch has `aria-checked="true"`<br>[assert] Stored preference is enabled<br>[assert] No console errors<br>[judge] The confirmation toast tells the user what changed — pass if it names email notifications specifically, fail if it is a generic "Settings saved" |
Operator Handoffs
When Operator is not none, the handoff is always the final step of the case — never in the middle. At run time the executing agent prints:
"Operator required. Please complete the following step in the browser, then reply done: [verbatim operator instruction]."
…then stops and waits for the developer's reply, verifies the Expected column with the case's driver, and continues. If a case needs an operator action as a pre-condition, that's a separate preconditions entry (P1, P2, …), not an inline handoff.
Output Naming
The plan is saved as specs/qa/QA-<N>-<slug>.md, following the same naming contract as REQ/ARCH/TASKS: <N> is the linked issue number; reuse the branch's <slug> when the branch matches {type}/<N>/<slug> for the same issue, otherwise derive one via the SLUG rule in start-task/SKILL.md.
No issue number (general mode from a PR, or ad-hoc work): fall back to QA-<slug>.md (or QA-PR-<number>.md when only a PR number identifies the work) and omit the Issue: row entirely — never write it as #none, empty, or a placeholder. Omit any Specs: link whose target doesn't exist.
Results are not part of this artifact: /execute-qa writes them to the sibling QA-RESULTS-<N>-<slug>.md (same stem, RESULTS infix).
Structure of the Output Plan
The full plan structure lives at {base_directory}/artifact-template.md. When you reach the artifact-writing step — not earlier — read that file and follow its structure exactly, filling every section. Do NOT write the plan from memory or improvise the format.
You Must NOT
- Bake project-specific traps, helpers, identities, or commands into a plan without eliciting or verifying them for this project — the examples in this skill are illustrative, never copied.
- Write an unfalsifiable Expected line — every line is
[assert] (machine-verifiable) or [judge] with an explicit written pass/fail criterion.
- Downgrade a mechanically observable result to
[judge] — judgment is for inherently qualitative properties only.
- Omit a changed file from the Coverage Map without flagging it.
- Insert an operator handoff mid-case — it is always the final step.
- Use one identity across two drivers unless the case documents why that is safe.
- Leave an elicited trap un-codified as a
Guard: on the specific step that needs it.
- Skip the Phase B conversation or write the artifact before the developer confirms the scenario list.
- Write results into the plan — execution and its verdicts belong to
/execute-qa.
Readiness Gate
Write the artifact only when all of these are true:
- Every changed file is in the Coverage Map or explicitly flagged as a gap.
- Every case's Expected column is falsifiable:
[assert] lines machine-verifiable, [judge] lines carrying an explicit pass/fail criterion fixed at plan time.
- Every trap surfaced in Phase B is a
Guard: on a specific step.
- Shell helpers and identities are agreed and expressed as real commands for this project.
- Every unavoidable human action is a named operator handoff, final step of its case.
- The developer has explicitly confirmed the scenario list.
If any are false, keep the conversation going.
Reminders
- Use today's date in the plan.
- Pipeline mode: link the REQ, ARCH, and review report in the header (review may run before, alongside, or after this plan — omit the review link only if no report exists yet). Trace each case's
Req column to real REQ-IDs.
- The plan is this skill's deliverable; the results artifact is
/execute-qa's.
- Like the other
specs/ artifacts, QA plans merge with the branch and are retired by /archive-issue <issue#> after the PR merges.