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#Ntag 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
```typescript
// 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