qa-workflow-cc 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +461 -0
- package/VERSION +1 -0
- package/bin/install.js +116 -0
- package/commands/qa/continue.md +77 -0
- package/commands/qa/full.md +149 -0
- package/commands/qa/init.md +105 -0
- package/commands/qa/resume.md +91 -0
- package/commands/qa/status.md +66 -0
- package/package.json +28 -0
- package/skills/qa/SKILL.md +420 -0
- package/skills/qa/references/continuation-format.md +58 -0
- package/skills/qa/references/exit-criteria.md +53 -0
- package/skills/qa/references/lifecycle.md +181 -0
- package/skills/qa/references/model-profiles.md +77 -0
- package/skills/qa/templates/agent-skeleton.md +733 -0
- package/skills/qa/templates/component-test.md +1088 -0
- package/skills/qa/templates/domain-research-queries.md +101 -0
- package/skills/qa/templates/domain-security-profiles.md +182 -0
- package/skills/qa/templates/e2e-test.md +1200 -0
- package/skills/qa/templates/nielsen-heuristics.md +274 -0
- package/skills/qa/templates/performance-benchmarks-base.md +321 -0
- package/skills/qa/templates/qa-report-template.md +271 -0
- package/skills/qa/templates/security-checklist-owasp.md +451 -0
- package/skills/qa/templates/stop-points/bootstrap-complete.md +36 -0
- package/skills/qa/templates/stop-points/certified.md +25 -0
- package/skills/qa/templates/stop-points/escalated.md +32 -0
- package/skills/qa/templates/stop-points/fix-ready.md +43 -0
- package/skills/qa/templates/stop-points/phase-transition.md +4 -0
- package/skills/qa/templates/stop-points/status-dashboard.md +32 -0
- package/skills/qa/templates/test-standards.md +652 -0
- package/skills/qa/templates/unit-test.md +998 -0
- package/skills/qa/templates/visual-regression.md +418 -0
- package/skills/qa/workflows/bootstrap.md +45 -0
- package/skills/qa/workflows/decision-gate.md +66 -0
- package/skills/qa/workflows/fix-execute.md +132 -0
- package/skills/qa/workflows/fix-plan.md +52 -0
- package/skills/qa/workflows/report-phase.md +64 -0
- package/skills/qa/workflows/test-phase.md +86 -0
- package/skills/qa/workflows/verify-phase.md +65 -0
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: visual-regression
|
|
3
|
+
description: Set up and run visual regression tests for UI consistency. Use when verifying design system compliance and preventing visual regressions.
|
|
4
|
+
context: fork
|
|
5
|
+
agent: test-qa
|
|
6
|
+
allowed-tools:
|
|
7
|
+
- Read
|
|
8
|
+
- Glob
|
|
9
|
+
- Grep
|
|
10
|
+
- Write
|
|
11
|
+
- Edit
|
|
12
|
+
- Bash
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# Visual Regression Testing
|
|
16
|
+
|
|
17
|
+
This skill guides setup and execution of visual regression tests.
|
|
18
|
+
|
|
19
|
+
## Prerequisites
|
|
20
|
+
|
|
21
|
+
- Playwright installed for screenshot capture
|
|
22
|
+
- Baseline screenshots established
|
|
23
|
+
- CI/CD pipeline configured for visual tests
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Overview
|
|
28
|
+
|
|
29
|
+
Visual regression testing captures screenshots and compares them against baselines to detect unintended visual changes.
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
┌─────────────────────────────────────────────────────────┐
|
|
33
|
+
│ VISUAL REGRESSION WORKFLOW │
|
|
34
|
+
├─────────────────────────────────────────────────────────┤
|
|
35
|
+
│ │
|
|
36
|
+
│ 1. Capture baseline screenshots (first run) │
|
|
37
|
+
│ 2. Make code changes │
|
|
38
|
+
│ 3. Capture new screenshots │
|
|
39
|
+
│ 4. Compare against baselines │
|
|
40
|
+
│ 5. Review differences (if any) │
|
|
41
|
+
│ 6. Approve changes OR fix regressions │
|
|
42
|
+
│ │
|
|
43
|
+
└─────────────────────────────────────────────────────────┘
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Playwright Visual Testing Setup
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
// playwright.config.ts
|
|
52
|
+
import { defineConfig } from '@playwright/test'
|
|
53
|
+
|
|
54
|
+
export default defineConfig({
|
|
55
|
+
testDir: './visual-tests',
|
|
56
|
+
|
|
57
|
+
// Screenshot settings
|
|
58
|
+
expect: {
|
|
59
|
+
toHaveScreenshot: {
|
|
60
|
+
maxDiffPixels: 100, // Allow small differences
|
|
61
|
+
maxDiffPixelRatio: 0.01, // 1% pixel difference threshold
|
|
62
|
+
animations: 'disabled', // Disable animations for consistency
|
|
63
|
+
caret: 'hide', // Hide blinking cursor
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
// Use consistent viewport
|
|
68
|
+
use: {
|
|
69
|
+
viewport: { width: 1280, height: 720 },
|
|
70
|
+
deviceScaleFactor: 1,
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
// Only run on chromium for consistency
|
|
74
|
+
projects: [
|
|
75
|
+
{
|
|
76
|
+
name: 'visual-chromium',
|
|
77
|
+
use: { browserName: 'chromium' },
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
})
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Basic Visual Test
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
// visual-tests/pages.visual.ts
|
|
89
|
+
import { test, expect } from '@playwright/test'
|
|
90
|
+
|
|
91
|
+
test.describe('Page Visual Tests', () => {
|
|
92
|
+
test.beforeEach(async ({ page }) => {
|
|
93
|
+
// Login and navigate (customize per project)
|
|
94
|
+
await page.goto('/')
|
|
95
|
+
await page.waitForLoadState('networkidle')
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
test('homepage matches baseline', async ({ page }) => {
|
|
99
|
+
// Hide dynamic content
|
|
100
|
+
await page.evaluate(() => {
|
|
101
|
+
document.querySelectorAll('[data-testid="timestamp"]').forEach(el => {
|
|
102
|
+
el.textContent = '2024-01-15'
|
|
103
|
+
})
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
await expect(page).toHaveScreenshot('homepage-full.png', {
|
|
107
|
+
fullPage: true,
|
|
108
|
+
})
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
test('navigation matches baseline', async ({ page }) => {
|
|
112
|
+
const nav = page.locator('[data-testid="navigation"]')
|
|
113
|
+
await expect(nav).toHaveScreenshot('navigation.png')
|
|
114
|
+
})
|
|
115
|
+
})
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## Component Visual Tests
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
// visual-tests/components/buttons.visual.ts
|
|
124
|
+
import { test, expect } from '@playwright/test'
|
|
125
|
+
|
|
126
|
+
test.describe('Button Component Visual Tests', () => {
|
|
127
|
+
test('primary button states', async ({ page }) => {
|
|
128
|
+
await page.goto('/') // Navigate to a page with buttons
|
|
129
|
+
|
|
130
|
+
const primaryBtn = page.locator('[data-testid="btn-primary"]')
|
|
131
|
+
|
|
132
|
+
// Default state
|
|
133
|
+
await expect(primaryBtn).toHaveScreenshot('btn-primary-default.png')
|
|
134
|
+
|
|
135
|
+
// Hover state
|
|
136
|
+
await primaryBtn.hover()
|
|
137
|
+
await expect(primaryBtn).toHaveScreenshot('btn-primary-hover.png')
|
|
138
|
+
|
|
139
|
+
// Focus state
|
|
140
|
+
await primaryBtn.focus()
|
|
141
|
+
await expect(primaryBtn).toHaveScreenshot('btn-primary-focus.png')
|
|
142
|
+
})
|
|
143
|
+
})
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Responsive Visual Tests
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
// visual-tests/responsive.visual.ts
|
|
152
|
+
import { test, expect, devices } from '@playwright/test'
|
|
153
|
+
|
|
154
|
+
const viewports = [
|
|
155
|
+
{ name: 'mobile', ...devices['iPhone 13'] },
|
|
156
|
+
{ name: 'tablet', viewport: { width: 768, height: 1024 } },
|
|
157
|
+
{ name: 'desktop', viewport: { width: 1280, height: 720 } },
|
|
158
|
+
{ name: 'wide', viewport: { width: 1920, height: 1080 } },
|
|
159
|
+
]
|
|
160
|
+
|
|
161
|
+
for (const vp of viewports) {
|
|
162
|
+
test.describe(`${vp.name} viewport`, () => {
|
|
163
|
+
test.use(vp)
|
|
164
|
+
|
|
165
|
+
test('layout', async ({ page }) => {
|
|
166
|
+
await page.goto('/')
|
|
167
|
+
await page.waitForLoadState('networkidle')
|
|
168
|
+
|
|
169
|
+
await expect(page).toHaveScreenshot(`layout-${vp.name}.png`, {
|
|
170
|
+
fullPage: true,
|
|
171
|
+
})
|
|
172
|
+
})
|
|
173
|
+
})
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## Theme Visual Tests
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
// visual-tests/themes.visual.ts
|
|
183
|
+
import { test, expect } from '@playwright/test'
|
|
184
|
+
|
|
185
|
+
test.describe('Theme Visual Tests', () => {
|
|
186
|
+
test('light theme', async ({ page }) => {
|
|
187
|
+
await page.goto('/')
|
|
188
|
+
await page.emulateMedia({ colorScheme: 'light' })
|
|
189
|
+
await page.waitForLoadState('networkidle')
|
|
190
|
+
await expect(page).toHaveScreenshot('theme-light.png')
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
test('dark theme', async ({ page }) => {
|
|
194
|
+
await page.goto('/')
|
|
195
|
+
await page.emulateMedia({ colorScheme: 'dark' })
|
|
196
|
+
await page.waitForLoadState('networkidle')
|
|
197
|
+
await expect(page).toHaveScreenshot('theme-dark.png')
|
|
198
|
+
})
|
|
199
|
+
})
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## Handling Dynamic Content
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
// visual-tests/utils/stabilize.ts
|
|
208
|
+
import { Page } from '@playwright/test'
|
|
209
|
+
|
|
210
|
+
export async function stabilizePage(page: Page) {
|
|
211
|
+
// Disable animations
|
|
212
|
+
await page.addStyleTag({
|
|
213
|
+
content: `
|
|
214
|
+
*, *::before, *::after {
|
|
215
|
+
animation-duration: 0s !important;
|
|
216
|
+
animation-delay: 0s !important;
|
|
217
|
+
transition-duration: 0s !important;
|
|
218
|
+
transition-delay: 0s !important;
|
|
219
|
+
}
|
|
220
|
+
`,
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
// Replace dynamic timestamps
|
|
224
|
+
await page.evaluate(() => {
|
|
225
|
+
document.querySelectorAll('[data-testid*="timestamp"]').forEach(el => {
|
|
226
|
+
el.textContent = '2024-01-15 10:00:00'
|
|
227
|
+
})
|
|
228
|
+
document.querySelectorAll('[data-testid*="relative-time"]').forEach(el => {
|
|
229
|
+
el.textContent = '5 minutes ago'
|
|
230
|
+
})
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
// Replace dynamic counts with stable values
|
|
234
|
+
await page.evaluate(() => {
|
|
235
|
+
document.querySelectorAll('[data-testid*="count"]').forEach(el => {
|
|
236
|
+
el.textContent = '42'
|
|
237
|
+
})
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
// Wait for fonts to load
|
|
241
|
+
await page.evaluate(() => document.fonts.ready)
|
|
242
|
+
|
|
243
|
+
// Wait for images to load
|
|
244
|
+
await page.waitForFunction(() => {
|
|
245
|
+
const images = document.querySelectorAll('img')
|
|
246
|
+
return Array.from(images).every(img => img.complete)
|
|
247
|
+
})
|
|
248
|
+
}
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## CI/CD Integration
|
|
254
|
+
|
|
255
|
+
```yaml
|
|
256
|
+
# .github/workflows/visual-tests.yml
|
|
257
|
+
name: Visual Regression Tests
|
|
258
|
+
|
|
259
|
+
on:
|
|
260
|
+
pull_request:
|
|
261
|
+
branches: [main]
|
|
262
|
+
|
|
263
|
+
jobs:
|
|
264
|
+
visual-tests:
|
|
265
|
+
runs-on: ubuntu-latest
|
|
266
|
+
|
|
267
|
+
steps:
|
|
268
|
+
- uses: actions/checkout@v4
|
|
269
|
+
|
|
270
|
+
- name: Setup Node
|
|
271
|
+
uses: actions/setup-node@v4
|
|
272
|
+
with:
|
|
273
|
+
node-version: '20'
|
|
274
|
+
|
|
275
|
+
- name: Install dependencies
|
|
276
|
+
run: npm install # or pnpm install
|
|
277
|
+
|
|
278
|
+
- name: Install Playwright browsers
|
|
279
|
+
run: npx playwright install chromium
|
|
280
|
+
|
|
281
|
+
- name: Start app
|
|
282
|
+
run: npm run dev &
|
|
283
|
+
|
|
284
|
+
- name: Wait for app
|
|
285
|
+
run: npx wait-on http://localhost:3000
|
|
286
|
+
|
|
287
|
+
- name: Run visual tests
|
|
288
|
+
run: npm run visual-test
|
|
289
|
+
|
|
290
|
+
- name: Upload diff artifacts
|
|
291
|
+
if: failure()
|
|
292
|
+
uses: actions/upload-artifact@v4
|
|
293
|
+
with:
|
|
294
|
+
name: visual-diff
|
|
295
|
+
path: visual-tests/test-results/
|
|
296
|
+
retention-days: 7
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
## Updating Baselines
|
|
302
|
+
|
|
303
|
+
```bash
|
|
304
|
+
# Update all baselines
|
|
305
|
+
npx playwright test --update-snapshots
|
|
306
|
+
|
|
307
|
+
# Update specific test baselines
|
|
308
|
+
npx playwright test pages.visual.ts --update-snapshots
|
|
309
|
+
|
|
310
|
+
# Interactive update (approve changes one by one)
|
|
311
|
+
npx playwright test --ui
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
## Directory Structure
|
|
317
|
+
|
|
318
|
+
```
|
|
319
|
+
visual-tests/
|
|
320
|
+
├── playwright.config.ts # Visual test config
|
|
321
|
+
├── pages.visual.ts # Full page tests
|
|
322
|
+
├── components/
|
|
323
|
+
│ ├── buttons.visual.ts
|
|
324
|
+
│ ├── cards.visual.ts
|
|
325
|
+
│ └── forms.visual.ts
|
|
326
|
+
├── responsive.visual.ts # Responsive tests
|
|
327
|
+
├── themes.visual.ts # Theme tests
|
|
328
|
+
├── utils/
|
|
329
|
+
│ └── stabilize.ts # Helper functions
|
|
330
|
+
└── screenshots/ # Baseline images (git tracked)
|
|
331
|
+
├── homepage-full-chromium.png
|
|
332
|
+
└── ...
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
---
|
|
336
|
+
|
|
337
|
+
## Best Practices
|
|
338
|
+
|
|
339
|
+
| Practice | Why |
|
|
340
|
+
|----------|-----|
|
|
341
|
+
| Use consistent viewport sizes | Prevents false positives from resize |
|
|
342
|
+
| Disable animations | Animations cause flaky comparisons |
|
|
343
|
+
| Replace dynamic content | Timestamps, counts change between runs |
|
|
344
|
+
| Wait for network idle | Ensures all data loaded |
|
|
345
|
+
| Wait for fonts | Font loading affects rendering |
|
|
346
|
+
| Use data-testid for locators | More stable than CSS classes |
|
|
347
|
+
| Run only on one browser | Reduces maintenance, ensures consistency |
|
|
348
|
+
| Store baselines in git | Easy to review changes in PRs |
|
|
349
|
+
|
|
350
|
+
---
|
|
351
|
+
|
|
352
|
+
## Design System Assertions
|
|
353
|
+
|
|
354
|
+
Visual regression tests should verify design system invariants programmatically:
|
|
355
|
+
|
|
356
|
+
```typescript
|
|
357
|
+
// visual-tests/design-system.visual.ts
|
|
358
|
+
import { test, expect, Page } from '@playwright/test'
|
|
359
|
+
|
|
360
|
+
async function getComputedStyle(page: Page, selector: string, property: string): Promise<string> {
|
|
361
|
+
return page.evaluate(
|
|
362
|
+
({ sel, prop }) => {
|
|
363
|
+
const el = document.querySelector(sel)
|
|
364
|
+
if (!el) throw new Error(`Element not found: ${sel}`)
|
|
365
|
+
return window.getComputedStyle(el).getPropertyValue(prop)
|
|
366
|
+
},
|
|
367
|
+
{ sel: selector, prop: property }
|
|
368
|
+
)
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
test.describe('Design System Invariants', () => {
|
|
372
|
+
test('touch targets meet 44x44px minimum', async ({ page }) => {
|
|
373
|
+
await page.goto('/')
|
|
374
|
+
await page.waitForLoadState('networkidle')
|
|
375
|
+
|
|
376
|
+
const violations = await page.evaluate(() => {
|
|
377
|
+
const interactive = document.querySelectorAll('button, a, [role="button"], input, select, textarea')
|
|
378
|
+
const small: string[] = []
|
|
379
|
+
|
|
380
|
+
for (const el of interactive) {
|
|
381
|
+
const rect = el.getBoundingClientRect()
|
|
382
|
+
if (rect.width > 0 && rect.height > 0) {
|
|
383
|
+
if (rect.width < 44 || rect.height < 44) {
|
|
384
|
+
small.push(`${el.tagName}${el.id ? '#' + el.id : ''}: ${rect.width}x${rect.height}`)
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
return small
|
|
390
|
+
})
|
|
391
|
+
|
|
392
|
+
expect(violations).toHaveLength(0)
|
|
393
|
+
})
|
|
394
|
+
})
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
---
|
|
398
|
+
|
|
399
|
+
## Checklist
|
|
400
|
+
|
|
401
|
+
Before adding visual tests:
|
|
402
|
+
|
|
403
|
+
- [ ] Identify pages/components to test
|
|
404
|
+
- [ ] Handle dynamic content (timestamps, counts)
|
|
405
|
+
- [ ] Disable animations
|
|
406
|
+
- [ ] Define viewport sizes for responsive tests
|
|
407
|
+
- [ ] Set appropriate diff thresholds
|
|
408
|
+
- [ ] Configure CI/CD for visual test runs
|
|
409
|
+
- [ ] Document baseline update process
|
|
410
|
+
|
|
411
|
+
---
|
|
412
|
+
|
|
413
|
+
## See Also
|
|
414
|
+
|
|
415
|
+
- E2E testing skill
|
|
416
|
+
- Component testing skill
|
|
417
|
+
- Test standards
|
|
418
|
+
- QA report template
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Workflow: Bootstrap (Phase 0)
|
|
2
|
+
|
|
3
|
+
<purpose>
|
|
4
|
+
Thin interface document for bootstrap. Actual logic lives in SKILL.md (B1-B9). This file exists so commands can reference it consistently alongside other workflows.
|
|
5
|
+
</purpose>
|
|
6
|
+
|
|
7
|
+
<required_context>
|
|
8
|
+
- SKILL: ~/.claude/skills/qa/SKILL.md (contains full B1-B9 protocol)
|
|
9
|
+
</required_context>
|
|
10
|
+
|
|
11
|
+
<process>
|
|
12
|
+
|
|
13
|
+
## Input
|
|
14
|
+
|
|
15
|
+
- `--rebootstrap` flag: Force re-discovery even if qa-profile.json exists
|
|
16
|
+
|
|
17
|
+
## Execution
|
|
18
|
+
|
|
19
|
+
Invoke the `/qa` skill which contains the full Phase 0 Bootstrap Protocol:
|
|
20
|
+
|
|
21
|
+
| Step | Description |
|
|
22
|
+
|------|-------------|
|
|
23
|
+
| B1 | Root Discovery (package.json, framework detection, domain detection) |
|
|
24
|
+
| B2 | Parallel Research (app discovery, security context, PRD analysis, Anthropic docs, stack/security/UX research) |
|
|
25
|
+
| B3 | Monorepo structure detection |
|
|
26
|
+
| B4 | Profile assembly (qa-profile.json) |
|
|
27
|
+
| B5 | Directory creation + project-level CLAUDE.md registration |
|
|
28
|
+
| B6 | File generation (skill files, agent files, test matrix) |
|
|
29
|
+
| B7 | Existing file handling (skip user-modified files) |
|
|
30
|
+
| B8 | Validation (check generated files) |
|
|
31
|
+
| B9 | State checkpoint + output |
|
|
32
|
+
|
|
33
|
+
## Output
|
|
34
|
+
|
|
35
|
+
- `.claude/qa-profile.json` — project profile
|
|
36
|
+
- `.claude/agents/qa-*.md` — 6 agent files
|
|
37
|
+
- `.claude/skills/testing/*.md` — skill files
|
|
38
|
+
- `docs/qa-reports/cycle-state.json` — initial state (`phase: "bootstrap_complete"`)
|
|
39
|
+
|
|
40
|
+
## Terminal Output
|
|
41
|
+
|
|
42
|
+
Read and output `~/.claude/skills/qa/templates/stop-points/bootstrap-complete.md`
|
|
43
|
+
Substitute all `{placeholder}` values with profile data from B4.
|
|
44
|
+
|
|
45
|
+
</process>
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Workflow: Decision Gate (Phase 5)
|
|
2
|
+
|
|
3
|
+
<purpose>
|
|
4
|
+
Evaluate the consolidated report against exit criteria. Return PASS, FAIL, or ESCALATE. Pure logic — no agent spawning.
|
|
5
|
+
</purpose>
|
|
6
|
+
|
|
7
|
+
<required_context>
|
|
8
|
+
- STATE: docs/qa-reports/cycle-state.json (cycle number, previousCycles, blockedDefectIds)
|
|
9
|
+
- REPORT: docs/qa-reports/cycle-{N}-{date}.md (consolidated report)
|
|
10
|
+
- EXIT_CRITERIA: ~/.claude/skills/qa/references/exit-criteria.md
|
|
11
|
+
</required_context>
|
|
12
|
+
|
|
13
|
+
<process>
|
|
14
|
+
|
|
15
|
+
## 1. Read Exit Criteria
|
|
16
|
+
|
|
17
|
+
Read `~/.claude/skills/qa/references/exit-criteria.md` on-demand.
|
|
18
|
+
|
|
19
|
+
## 2. Read Consolidated Report
|
|
20
|
+
|
|
21
|
+
Read the cycle report and extract:
|
|
22
|
+
- Total tests, passing, failing
|
|
23
|
+
- Defect counts by severity (critical, major, minor, cosmetic)
|
|
24
|
+
- UX score, Lighthouse scores (if applicable)
|
|
25
|
+
- Tenant isolation results (if applicable)
|
|
26
|
+
- Auth boundary results (if applicable)
|
|
27
|
+
|
|
28
|
+
## 3. Evaluate Against Thresholds
|
|
29
|
+
|
|
30
|
+
For each gate in exit criteria, compare report values:
|
|
31
|
+
|
|
32
|
+
| Gate | Threshold | Actual | Pass? |
|
|
33
|
+
|------|-----------|--------|-------|
|
|
34
|
+
{evaluate each gate}
|
|
35
|
+
|
|
36
|
+
## 4. Determine Decision
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
IF all exit criteria pass:
|
|
40
|
+
→ decision = "PASS"
|
|
41
|
+
|
|
42
|
+
ELIF cycle >= 3 AND same defects persist across 2+ cycles:
|
|
43
|
+
→ decision = "ESCALATE"
|
|
44
|
+
|
|
45
|
+
ELIF cycle >= 3 AND blockedDefectIds.length > 0 across 2+ cycles:
|
|
46
|
+
→ decision = "ESCALATE"
|
|
47
|
+
|
|
48
|
+
ELSE:
|
|
49
|
+
→ decision = "FAIL"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## 5. Write Decision to State
|
|
53
|
+
|
|
54
|
+
Update cycle-state.json with decision BEFORE routing:
|
|
55
|
+
```json
|
|
56
|
+
{ "decision": "PASS|FAIL|ESCALATE", "verdict": "PASS|FAIL" }
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## 6. Return Decision
|
|
60
|
+
|
|
61
|
+
Return the decision to the calling command for phase routing:
|
|
62
|
+
- **PASS** → Phase 8 (certification)
|
|
63
|
+
- **FAIL** → Phase 6 (plan fixes)
|
|
64
|
+
- **ESCALATE** → Phase 9 (escalation)
|
|
65
|
+
|
|
66
|
+
</process>
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Workflow: Fix Execution (Phase 7)
|
|
2
|
+
|
|
3
|
+
<purpose>
|
|
4
|
+
Execute approved fix plan by dispatching implementer agents per priority batch (P0 → P1 → P2), with post-implementation validation and correction loops.
|
|
5
|
+
</purpose>
|
|
6
|
+
|
|
7
|
+
<required_context>
|
|
8
|
+
- PROFILE: .claude/qa-profile.json (commands.typeCheck, commands.build, agentRouting.fixRoutes)
|
|
9
|
+
- STATE: docs/qa-reports/cycle-state.json (fixPlanPath, batchProgress)
|
|
10
|
+
- MODEL_MAP: resolved models for fix-implementer and qa-verifier
|
|
11
|
+
- FIX_PLAN: docs/qa-reports/fix-plan-cycle-{N}.md
|
|
12
|
+
</required_context>
|
|
13
|
+
|
|
14
|
+
<process>
|
|
15
|
+
|
|
16
|
+
## 1. Write State Checkpoint
|
|
17
|
+
|
|
18
|
+
```json
|
|
19
|
+
{
|
|
20
|
+
"phase": "fixing",
|
|
21
|
+
"batchProgress": {
|
|
22
|
+
"completedBatches": [],
|
|
23
|
+
"currentBatch": null
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## 2. Load Fix Plan
|
|
29
|
+
|
|
30
|
+
Read fix plan from `STATE.fixPlanPath`.
|
|
31
|
+
Read agent routing from `PROFILE.agentRouting.fixRoutes`.
|
|
32
|
+
|
|
33
|
+
## 3. For Each Priority Batch (P0 → P1 → P2)
|
|
34
|
+
|
|
35
|
+
### 3a. Parse Batch
|
|
36
|
+
|
|
37
|
+
Extract defect IDs, target files, fix approach, and target agent for each fix in the batch.
|
|
38
|
+
|
|
39
|
+
### 3b. Pre-Applied Fix Detection
|
|
40
|
+
|
|
41
|
+
For each fix, read target files and check if the fix appears already applied (e.g., from manual user changes). Skip to verification if already applied.
|
|
42
|
+
|
|
43
|
+
### 3c. Analyze Independence
|
|
44
|
+
|
|
45
|
+
- Fixes touching **different files** → dispatch in parallel
|
|
46
|
+
- Fixes touching **same files** → dispatch sequentially
|
|
47
|
+
|
|
48
|
+
### 3d. Dispatch Implementers
|
|
49
|
+
|
|
50
|
+
For each fix needing implementation:
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
Task(
|
|
54
|
+
subagent_type="general-purpose",
|
|
55
|
+
prompt="[FIX] Defect {defect-id} ({severity})
|
|
56
|
+
|
|
57
|
+
Root cause: {root-cause}
|
|
58
|
+
Fix approach: {approach}
|
|
59
|
+
Files to modify: {file-list}
|
|
60
|
+
|
|
61
|
+
PROJECT CONTEXT (inlined):
|
|
62
|
+
- TypeCheck command: {PROFILE.commands.typeCheck}
|
|
63
|
+
- Build command: {PROFILE.commands.build}
|
|
64
|
+
|
|
65
|
+
SCOPE CONSTRAINT: Targeted fix only, not a refactor.
|
|
66
|
+
Do NOT review your own code after writing it.",
|
|
67
|
+
model="{MODEL_MAP['fix-implementer']}",
|
|
68
|
+
description="Fix {defect-id}"
|
|
69
|
+
)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### 3e. Post-Implementation Validation
|
|
73
|
+
|
|
74
|
+
Orchestrator runs directly (not via agent):
|
|
75
|
+
1. Type-check: `{PROFILE.commands.typeCheck}` → FAIL: re-dispatch (max 3 retries)
|
|
76
|
+
2. Build: `{PROFILE.commands.build}` → FAIL: re-dispatch (max 3 retries)
|
|
77
|
+
|
|
78
|
+
### 3f. Batch Verification
|
|
79
|
+
|
|
80
|
+
Spawn qa-verifier for the batch:
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
Task(
|
|
84
|
+
subagent_type="general-purpose",
|
|
85
|
+
prompt="[QA-VERIFIER] Read .claude/agents/qa-verifier.md.
|
|
86
|
+
IMPORTANT: Read the Resources section FIRST.
|
|
87
|
+
|
|
88
|
+
Re-run ONLY these previously failed tests: {batch-test-ids}
|
|
89
|
+
|
|
90
|
+
PROJECT CONTEXT (inlined):
|
|
91
|
+
- Test command: {PROFILE.commands.test}
|
|
92
|
+
- Apps: {relevant apps from PROFILE.apps}
|
|
93
|
+
|
|
94
|
+
Return PASS or STILL_FAILING for each test.",
|
|
95
|
+
model="{MODEL_MAP['qa-verifier']}",
|
|
96
|
+
description="Verify batch P{X}"
|
|
97
|
+
)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### 3g. Correction Loop
|
|
101
|
+
|
|
102
|
+
For STILL_FAILING results: re-dispatch implementer with verifier evidence (max 3 iterations per fix). After 3 failures, mark as BLOCKED and add to `blockedDefectIds`.
|
|
103
|
+
|
|
104
|
+
### 3h. Batch Checkpoint
|
|
105
|
+
|
|
106
|
+
Update state after each batch completes:
|
|
107
|
+
```json
|
|
108
|
+
{
|
|
109
|
+
"batchProgress": {
|
|
110
|
+
"completedBatches": ["P0"],
|
|
111
|
+
"currentBatch": "P1"
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## 4. Phase Gate
|
|
117
|
+
|
|
118
|
+
Each batch must complete before the next starts. P0 → P1 → P2 strictly ordered.
|
|
119
|
+
|
|
120
|
+
## 5. Final State Checkpoint
|
|
121
|
+
|
|
122
|
+
After all batches complete:
|
|
123
|
+
```json
|
|
124
|
+
{ "phase": "verifying" }
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## 6. Output Phase Transition
|
|
128
|
+
|
|
129
|
+
Read and output `~/.claude/skills/qa/templates/stop-points/phase-transition.md`
|
|
130
|
+
Substitute: {X} = 7, {Y} = 7b
|
|
131
|
+
|
|
132
|
+
</process>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Workflow: Fix Plan (Phase 6)
|
|
2
|
+
|
|
3
|
+
<purpose>
|
|
4
|
+
Spawn fix planner agent to analyze defects and produce a prioritized fix plan. Does NOT include stop-point output — the calling command handles that.
|
|
5
|
+
</purpose>
|
|
6
|
+
|
|
7
|
+
<required_context>
|
|
8
|
+
- PROFILE: .claude/qa-profile.json (agentRouting.fixRoutes, apps)
|
|
9
|
+
- STATE: docs/qa-reports/cycle-state.json (cycle number, blockedDefectIds)
|
|
10
|
+
- MODEL_MAP: resolved model for qa-fix-planner
|
|
11
|
+
- REPORT: docs/qa-reports/cycle-{N}-{date}.md (consolidated report with defects)
|
|
12
|
+
</required_context>
|
|
13
|
+
|
|
14
|
+
<process>
|
|
15
|
+
|
|
16
|
+
## 1. Spawn Fix Planner
|
|
17
|
+
|
|
18
|
+
Inline defect data and agent routing into the prompt:
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
Task(
|
|
22
|
+
subagent_type="general-purpose",
|
|
23
|
+
prompt="[QA-FIX-PLANNER] Read .claude/agents/qa-fix-planner.md.
|
|
24
|
+
IMPORTANT: Read the Resources section FIRST.
|
|
25
|
+
|
|
26
|
+
PROJECT CONTEXT (inlined from profile):
|
|
27
|
+
- Agent routing: {JSON of PROFILE.agentRouting.fixRoutes}
|
|
28
|
+
- Apps: {JSON summary of PROFILE.apps}
|
|
29
|
+
|
|
30
|
+
DEFECT SOURCE:
|
|
31
|
+
Analyze defects from: docs/qa-reports/cycle-{N}-{date}.md
|
|
32
|
+
|
|
33
|
+
EXCLUSIONS:
|
|
34
|
+
Exclude blocked defect IDs: {STATE.blockedDefectIds}
|
|
35
|
+
|
|
36
|
+
Write fix plan to: docs/qa-reports/fix-plan-cycle-{N}.md",
|
|
37
|
+
model="{MODEL_MAP['qa-fix-planner']}",
|
|
38
|
+
description="QA fix plan cycle {N}"
|
|
39
|
+
)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## 2. Write State Checkpoint
|
|
43
|
+
|
|
44
|
+
```json
|
|
45
|
+
{ "phase": "awaiting_fix_approval", "fixPlanPath": "docs/qa-reports/fix-plan-cycle-{N}.md" }
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## 3. Verify Files Exist
|
|
49
|
+
|
|
50
|
+
Read back fix plan and cycle-state.json to confirm writes succeeded.
|
|
51
|
+
|
|
52
|
+
</process>
|