| name | qa |
| description | Use when performing quality assurance on code changes.
Identifies test gaps, writes missing tests, explores edge cases, and auto-fixes with caution.
Triggers: "QA", "quality check", "test coverage", "run QA", "check quality".
|
| allowed-tools | ["Bash","Read","Write","Edit","Grep","Glob"] |
| when_to_use | Use during VERIFY stage for test coverage, edge cases, auto-fix. Complements verification (which checks acceptance criteria).
|
| produces | null |
| consumes | ["docs/superomni/executions/execution-[branch]-[session]-[date].md"] |
Preamble (Core)
Status protocol — end every session with one of: DONE (evidence provided) · DONE_WITH_CONCERNS (list each) · BLOCKED (state what blocks you) · NEEDS_CONTEXT (state what you need).
Auto-advance — pipeline: THINK → PLAN → REVIEW → BUILD → VERIFY → RELEASE. Only human gate is spec approval at THINK. On DONE at other stages, print [STAGE] DONE -> advancing to [NEXT-STAGE] and invoke the next skill. On any non-DONE status at any stage, STOP.
Output directory — all artifacts go in docs/superomni/<kind>/<kind>-[branch]-[session]-[date].md. See CLAUDE.md for the full directory map.
TACIT-DENSE — before high-tacit decisions, classify D1 (domain expertise) · D2 (user-facing UX) · D3 (team culture) · D4 (novel pattern). On hit, output TACIT-DENSE [D#]: [question] — My default: [recommendation]. See reference for actions.
Anti-sycophancy — take a position on every significant question. Name flaws directly. No filler ("that's interesting", "you might consider", "that could work").
Telemetry (local only) — at session end, log bin/analytics-log. Nothing leaves the machine.
See preamble-ref.md for detailed protocols.
Quality Assurance
Goal: Ensure code changes are correct, well-tested, and free of regressions through systematic test analysis, gap filling, and edge case exploration.
Iron Law
NEVER MARK A TEST GREEN BY WEAKENING THE ASSERTION.
If a test fails, the fix is to fix the code or update the test to match a correct new behavior — never to loosen the assertion just to make it pass. A test that asserts nothing is worse than no test.
Phase 1: Identify Test Scope
Determine what changed and what could break.
git diff main...HEAD --stat 2>/dev/null || git diff HEAD~1 --stat
git diff main...HEAD 2>/dev/null | grep "^@@" | head -30
git diff main...HEAD --name-only 2>/dev/null | while read f; do
grep -rl "$(basename "$f" | sed 's/\..*//')" . \
--include="*.js" --include="*.ts" --include="*.py" --include="*.go" \
2>/dev/null
done | sort -u | head -20
git diff main...HEAD --name-only 2>/dev/null | while read f; do
base=$(basename "$f" | sed 's/\..*//')
find . -name "*${base}*test*" -o -name "*${base}*spec*" -o -name "test_*${base}*" \
2>/dev/null
done | sort -u | head -20
Produce a scope map:
QA SCOPE
─────────────────────────────────
Files changed: [list]
Functions affected: [list key functions]
Existing tests: [list test files that cover these changes]
Missing tests: [files/functions with no test coverage]
Blast radius: [what else could break]
─────────────────────────────────
Phase 2: Run Existing Test Suite
Run the full test suite and capture results.
npm test 2>&1 | tee qa-results.txt || true
pytest -v 2>&1 | tee qa-results.txt || true
go test -v ./... 2>&1 | tee qa-results.txt || true
echo "---"
grep -cE "PASS|✓|ok " qa-results.txt 2>/dev/null || true
grep -cE "FAIL|✗|FAILED" qa-results.txt 2>/dev/null || true
rm -f qa-results.txt
Record results:
TEST SUITE RESULTS
─────────────────────────────────
Total: [N]
Passing: [N]
Failing: [N]
Skipped: [N]
Duration: [Ns]
─────────────────────────────────
If tests fail, classify each failure:
| Failure | Type | Action |
|---|
| Test broke due to your change | Regression | Fix the code (not the test) |
| Test was already broken | Pre-existing | Note it, don't fix during QA |
| Test is flaky (passes on re-run) | Flaky | Note it, consider stabilizing |
| Test assertion is wrong (spec changed) | Outdated | Update test to match new spec |
Phase 3: Write Missing Tests
For each uncovered code path identified in Phase 1:
Apply the test-driven-development skill with:
- The file(s) under test
- The specific behaviors to cover (from Phase 1 scope map)
- The project's existing test conventions (
find . -name "*.test.*" -o -name "*.spec.*" | head -5)
The skill returns a TEST REPORT block with all new tests written. Confirm the new tests pass (and would fail if the behavior broke) before proceeding to Phase 4. (Test authoring was consolidated from the retired test-writer agent into the test-driven-development skill.)
For each uncovered behavior, write:
Test Naming Convention
Follow the project's existing convention. If none exists, use:
test_[function]_[scenario]_[expected result]
# Examples:
test_calculateTotal_emptyCart_returnsZero
test_authenticate_expiredToken_throwsAuthError
test_parseConfig_missingRequiredField_usesDefault
What to Cover
- Happy path — does it work for normal input?
- Boundary values — 0, 1, max, empty, null
- Error conditions — invalid input, missing dependencies, timeout
- State transitions — before/after key operations
npm run test:coverage 2>/dev/null | tail -20 || true
pytest --cov 2>/dev/null | tail -20 || true
go test -cover ./... 2>/dev/null | tail -20 || true
Phase 4: Edge Case Exploration
Go beyond the obvious. For each changed function, consider:
| Category | Examples |
|---|
| Empty/null | null, undefined, "", [], {} |
| Boundary | 0, -1, MAX_INT, single character, max length |
| Type coercion | "123" vs 123, true vs 1, 0 vs false |
| Concurrency | Two simultaneous calls, race conditions |
| Encoding | Unicode, emoji, special characters, RTL text |
| Large input | Very long strings, huge arrays, deep nesting |
| Malicious input | SQL injection strings, XSS payloads, path traversal |
For each edge case found:
- Write a test that exercises the edge case
- If the code handles it correctly — great, the test documents this
- If the code fails — report the bug, write a regression test
Phase 5: Auto-Fix Failing Tests
Only fix a failing test if the root cause is understood.
Decision tree:
Test fails → Do you understand WHY it fails?
├── YES → Is the test correct (matches spec)?
│ ├── YES → Fix the CODE (the code has a bug)
│ └── NO → Fix the TEST (spec changed, test is outdated)
└── NO → STOP. Investigate root cause first.
Do NOT change the test or code without understanding.
Rules:
- Never delete a failing test without understanding why it fails
- Never weaken an assertion (e.g., changing
assertEquals to assertNotNull)
- Never add
skip / xit / @pytest.mark.skip without documenting the reason
- If fixing the code causes other tests to fail, stop and reassess — the change may be wrong
npm test 2>&1 | tail -20
Phase 6: QA Report
QA REPORT
════════════════════════════════════════
Scope: [what was tested]
Changes tested: [N files, N functions]
Test Results (before QA):
Passing: [N]
Failing: [N]
Skipped: [N]
Test Results (after QA):
Passing: [N]
Failing: [N]
Skipped: [N]
New tests: [N added]
Coverage:
Before: [N% or "not measured"]
After: [N% or "not measured"]
Edge Cases Found:
- [edge case 1] — [handled/bug filed]
- [edge case 2] — [handled/bug filed]
Bugs Found:
- [bug 1]: [description] — [fixed/reported]
- [bug 2]: [description] — [fixed/reported]
Flaky Tests:
- [test name] — [observed behavior]
Risk Assessment:
[LOW/MEDIUM/HIGH] — [1-sentence justification]
Status: DONE | DONE_WITH_CONCERNS | BLOCKED | NEEDS_CONTEXT
════════════════════════════════════════