QA Planning Skill
Generate the QA Contract - exhaustive Gherkin BDD scenarios (G#N) for all data sources and acceptance criteria (AC#N) for frontend. This contract is consumed by Plan Mode and verified by qa-commit skill.
When to Use
-
During Ask mode Phase 2 (CONVERGE) for any feature work
-
Before implementation to define testable acceptance criteria
-
When documenting expected behavior for QA team
Output: QA Contract
The QA Contract is the primary artifact, consisting of:
-
G#1, G#2, ... - Numbered Gherkin scenarios (backend/data)
-
AC#1, AC#2, ... - Numbered acceptance criteria (frontend)
These IDs are referenced in Plan Mode's Commit Plan (Satisfies field) and verified by qa-commit skill.
Instructions
Phase 0: Identify ALL Data Sources (CRITICAL)
STOP. Before writing any Gherkin, exhaustively map ALL data sources for the feature.
Categorize each data source:
Category Description Gherkin Type
Runtime API Fetched at request time from server API scenarios (G#N)
Build-time Static Generated during build, served as static files Build script scenarios (G#N)
Database Direct DB queries (Hasura, Postgres) Query scenarios (G#N)
External API Third-party services Integration scenarios (G#N)
Middleware Request routing, auth, transforms Routing scenarios (G#N)
Data Source Inventory Template:
Data Source Inventory
Runtime APIs
| Endpoint | Method | Auth | Resource | Status |
|---|---|---|---|---|
/v1/resource | GET | Yes | Resource | Existing |
/public/resource | GET | No | Resource | New |
Build-time Static
| Output Path | Source | Generator | Content |
|---|---|---|---|
/components.json | Codebase | Build script | Component metadata |
/charts/[slug].json | Codebase | Build script | Chart config + examples |
Database Queries
| Query | Source | Auth | Purpose |
|---|---|---|---|
connectors | Hasura | Yes | List connectors |
Middleware
| Route | Behavior | Auth |
|---|---|---|
developers.* | Rewrite to public routes | Skip |
External APIs
| Service | Endpoint | Purpose |
|---|---|---|
| (none for this feature) |
Validation: Count total data sources. If < 3 for a non-trivial feature, you likely missed something. Re-examine the feature scope.
Phase 2: Define Pre-conditions Matrix (Given)
For each service, treat it as a black box. Based on the contract interface or data model, list all pre-condition parameters:
[Method] [Path] Pre-conditions
| Parameter | Type | Source | Possible Values |
|---|---|---|---|
Authorization | header | request | valid_token, invalid_token, expired_token, missing |
id | path | URL | existing_uuid, non_existing_uuid, malformed, deleted |
status | query | URL | enum values from data model |
[field] | body | JSON | valid, null, empty, wrong_type, too_long |
Sources:
-
header: Authorization, Content-Type, custom headers
-
path: URL parameters (:id , :slug )
-
query: Query string filters, pagination
-
body: Request payload fields
Phase 3: Map When (Method + Path)
Each scenario has exactly ONE action:
When [METHOD] [/path/to/resource]
Examples:
-
When GET /v1/connectors
-
When POST /v1/connectors
-
When GET /v1/connectors/{id}
-
When DELETE /v1/connectors/{id}
Phase 4: Define Then (Response Contract)
Specify expected response object. Response varies based on pre-conditions:
Then status [code] And response.[field] is [type] And response.[field] equals [value] And response.[field] in [array of valid values] And response does NOT include [sensitive_field]
Response Schema Template:
// Success response { data: { type: string, id: UUID, attributes: { ... } }, meta?: { count: number } }
// Error response { error: { code: "NOT_FOUND" | "UNAUTHORIZED" | "VALIDATION_ERROR", message: string } }
Phase 5: Write Gherkin Scenarios (G#N)
For each method+path, write scenarios covering all pre-condition combinations:
Feature: [Resource] API
@G#1 Scenario: G#1.1 - [Method] [path] - happy path Given Authorization header is "Bearer valid_token" And [pre-condition 1] And [pre-condition 2] When [METHOD] [/path] Then status 200 And response.data.id is UUID And response.data.attributes.[field] is [type]
@G#2 Scenario: G#1.2 - [Method] [path] - missing auth Given no Authorization header When [METHOD] [/path] Then status 401 And response.error.code equals "UNAUTHORIZED"
@G#3 Scenario: G#1.3 - [Method] [path] - not found Given Authorization header is "Bearer valid_token" And id is "non_existing_uuid" When [METHOD] [/path/{id}] Then status 404 And response.error.code equals "NOT_FOUND"
Numbering Convention:
-
G#N = Feature-level ID (G#1, G#2...)
-
G#N.M = Scenario within feature (G#1.1, G#1.2...)
-
Use @G#N tag for traceability
Coverage Matrix per Endpoint:
Method Required Scenarios
GET (list) Valid, filtered, paginated, empty, unauthorized
GET (detail) Found, not found, deleted, unauthorized, malformed ID
POST Valid, each validation error, conflict, unauthorized
PUT/PATCH Valid, partial, not found, conflict, unauthorized
DELETE Success, not found, unauthorized, cascade
Phase 6: Build-time Static Scenarios (G#N)
For build-time generated data, write scenarios verifying the build script:
Pre-conditions for Build Scripts:
Parameter Type Possible Values
Source file exists boolean true, false
Source file valid boolean valid structure, malformed
Metadata complete boolean all fields, partial, missing
Export type enum default, named, none
Template:
Feature: [Resource] Build Extraction
@G#N Scenario: G#N.1 - Extract [resource] with complete metadata Given [source file] exists at [path] And [source file] has valid [structure] And [metadata fields] are documented When build script runs Then [output.json] includes [resource] entry And entry has [required fields]
@G#N Scenario: G#N.2 - Skip internal/private [resources] Given [source file] has underscore prefix When build script runs Then [output.json] does NOT include entry
@G#N Scenario: G#N.3 - Handle missing optional fields Given [source file] exists And [optional field] is not documented When build script runs Then entry has [optional field] as null
Coverage Matrix for Build Scripts:
Source Type Required Scenarios
Component Extract props, extract examples, skip internal, handle missing docs
Chart Extract config schema, extract data schema, extract examples
Docs Parse MDX, extract frontmatter, build navigation
Search Index Index all sources, handle empty content, validate structure
Phase 7: Middleware/Routing Scenarios (G#N)
For middleware and routing logic:
Pre-conditions:
Parameter Type Possible Values
Host header string subdomain variants, main domain, unknown
Path string valid routes, invalid routes
Auth state enum authenticated, unauthenticated
Template:
Feature: Hostname Routing
@G#N Scenario: G#N.1 - Route [subdomain] to [target] Given Host header is "[subdomain].domain.com" And path is "[path]" When request arrives at middleware Then rewrite to [target route group] And [skip/require] authentication
@G#N Scenario: G#N.2 - Unknown subdomain redirect Given Host header is "unknown.domain.com" When request arrives at middleware Then redirect to [default domain]
Phase 8: Frontend QA (Acceptance Criteria - AC#N)
For each UI component/screen, define numbered testable criteria using AC#N format:
ID Screen Criteria Test Method Priority
AC#1 [Component] Renders without error Storybook P0
AC#2 [Component] Displays loading state Storybook P0
AC#3 [Component] Displays error state with retry Storybook P0
AC#4 [Component] Displays empty state with CTA Storybook P1
AC#5 [Component] Keyboard navigation works Browser MCP P1
AC#6 [Component] Screen reader accessible Manual P1
AC#7 [Component] Mobile responsive Browser MCP P2
Numbering Rules:
-
Use sequential IDs: AC#1, AC#2, AC#3...
-
IDs are feature-scoped (reset for each feature)
-
Include ID in first column for traceability
Data Source Mapping for AC: Each AC must indicate which data source it consumes:
ID Screen Criteria Data Source Priority
AC#1 ConnectorsList Renders list API: /public/connectors P0
AC#2 ComponentsList Renders list Static: /components.json P0
State Coverage:
State Required Tests
Initial Default render, correct layout
Loading Skeleton/spinner visible, no interaction
Success Data displayed correctly, actions enabled
Error Error message visible, retry available
Empty Empty message visible, CTA available
Phase 9: Integration Points
Identify cross-cutting concerns:
Concern Test Approach
Auth token handling Gherkin: expired token, refresh flow
Optimistic updates Frontend: show immediate, rollback on error
Cache invalidation Frontend: data refreshes after mutation
Error boundaries Frontend: component failure doesn't crash app
Phase 10: Coverage Summary
Coverage Summary
Data Sources
| Category | Count | Items |
|---|---|---|
| Runtime APIs | [N] | [list endpoints] |
| Build-time Static | [N] | [list outputs] |
| Middleware | [N] | [list routes] |
| Database | [N] | [list queries] |
| External APIs | [N] | [list services] |
| Total | [N] |
Gherkin Scenarios
| Category | Count | IDs |
|---|---|---|
| API scenarios | [N] | G#1 - G#[N] |
| Build scenarios | [N] | G#[N] - G#[M] |
| Middleware scenarios | [N] | G#[M] - G#[P] |
| Total | [N] |
Frontend Acceptance
| Category | Count | IDs |
|---|---|---|
| Acceptance criteria | [N] | AC#1 - AC#[N] |
Validation Checklist
- Every data source has at least 1 G#N scenario
- Every AC#N maps to a data source
- All error cases covered (401, 404, 400, 500)
- Build scripts have extraction + skip + missing scenarios
- Middleware has all subdomain variants
Phase 11: Artifact Validation (Poka-Yoke)
Before Gate transition, validate artifacts silently. Only show output if validation fails.
Gate 1 Validation (DIVERGE -> CONVERGE)
Check:
-
All wireframes have status (OK/KO/DIG, or no comment = OK)
-
No orphan references (#{N} mentioned but not defined)
-
At least 1 wireframe validated (OK)
Gate 2 Validation (CONVERGE -> PLAN)
Check:
-
QA Contract has at least 1 G#N (Gherkin scenario)
-
QA Contract has at least 1 AC#N (acceptance criteria)
-
Each phase has at least 1 commit planned
-
No circular dependencies in phasing order
-
All G#N and AC#N are assigned to phases
Validation Output
If all pass: (silent, no output - proceed normally)
If validation fails:
R | [Feature] | VALIDATION ERROR
Cannot proceed to [NEXT_PHASE]:
- [Missing: wireframe #4 has no status]
- [Missing: QA Contract needs at least 1 G#N]
Fix: [Specific action to resolve]
Integration
This validation runs automatically before:
-
Gate 1 presentation (ask.mdc Phase 1 - DIVERGE)
-
Gate 2 presentation (ask.mdc Phase 2 - CONVERGE)
Output Format: QA Contract
QA Contract: [Feature Name]
Data Source Inventory
Runtime APIs
| Endpoint | Method | Auth | Resource | Status |
|---|---|---|---|---|
/v1/resource | GET | Yes | Resource | Existing |
/public/resource | GET | No | Resource | New |
Build-time Static
| Output Path | Source | Generator |
|---|---|---|
/components.json | Codebase | Build script |
Middleware
| Route Pattern | Behavior |
|---|---|
developers.* | Rewrite to public, skip auth |
API Scenarios (G#1 - G#N)
G#1: [METHOD] [/path] ([Resource])
Pre-conditions:
| Parameter | Type | Possible Values |
|---|---|---|
Authorization | header | valid_token, invalid_token, missing |
id | path | existing, non_existing, malformed |
Scenarios:
| ID | Given | When | Then |
|---|---|---|---|
| G#1.1 | valid token | GET /path | 200, data array |
| G#1.2 | invalid token | GET /path | 401, UNAUTHORIZED |
Build Scenarios (G#N - G#M)
G#N: [Resource] Extraction
Pre-conditions:
| Parameter | Type | Possible Values |
|---|---|---|
| Source exists | boolean | true, false |
| Metadata complete | boolean | complete, partial |
Scenarios:
| ID | Given | When | Then |
|---|---|---|---|
| G#N.1 | source exists, complete | Build runs | output.json includes entry |
| G#N.2 | internal file (underscore) | Build runs | output.json excludes entry |
Middleware Scenarios (G#M - G#P)
G#M: Hostname Routing
| ID | Given (Host) | Given (Path) | Then |
|---|---|---|---|
| G#M.1 | developers.domain.com | /connectors | Rewrite to /(public), skip auth |
| G#M.2 | app.domain.com | /settings/* | Route to /(app), require auth |
Response Schemas
// Success
{ data: { type, id, attributes }, meta: { count } }
// Error
{ error: { code, message } }
// Static file
{ data: [{ slug, name, ... }], meta: { count } }
Frontend Acceptance Criteria
ID
Screen
Criteria
Data Source
Priority
AC#1
[Component]
Renders list
API: /public/x
P0
AC#2
[Component]
Renders from static
Static: /x.json
P0
Coverage Summary
Category
Count
IDs
Runtime APIs
[N]
G#1 - G#[N]
Build Scripts
[N]
G#[N] - G#[M]
Middleware
[N]
G#[M] - G#[P]
Acceptance Criteria
[N]
AC#1 - AC#[N]
Total Scenarios
[N]
Validation
- Every data source has ≥1 G#N
- Every AC#N maps to data source
- Error cases covered (401, 404, 400)
## Consuming the QA Contract
This QA Contract is used by:
- **Plan Mode**: Maps G#N and AC#N to commits via "Satisfies" field
- **qa-commit skill**: Verifies implementation against assigned criteria
- **test-hardening skill**: Converts passed criteria to automated tests
## Invocation
Invoke manually with "use qa-planning skill" or follow Ask mode Phase 2 (CONVERGE) which references this skill.
## Related Skills
- `state-machine` - Defines states that need testing
- `bpmn-workflow` - Uses Gherkin scenarios for process documentation
- `qa-commit` - Verifies implementation against QA Contract
- `test-hardening` - Converts passed scenarios to automated tests