| name | sw-team-code-qa |
| description | Full quality gate procedure for any SW-TEAM Python package: ruff format, ruff check, mypy, pytest with coverage. Loaded by the SW-TEAM-Code-QA agent at session startup. Covers the 4-stage gate, test writing conventions, contract verification checklist, and per-module/per-phase reporting formats. Domain-agnostic — contains no project-specific vocabulary. Load alongside a domain-context SKILL (e.g., {domain}-builder-context) for package name, coverage threshold, and test fixtures.
|
| user-invocable | false |
SW-TEAM Code QA — Methodology SKILL
Audience: SW-TEAM-Code-QA agent only.
Domain vocabulary: Zero — all package-specific values come from the domain-context SKILL.
Load alongside: <domain>-builder-context/SKILL.md for package name, fixture names, and cross-track rules.
FIXED — Quality Gate (4 Stages)
Run the four stages in order. A failure in any stage means overall FAIL.
Report only — do NOT auto-fix. Fixes are the Implementer's responsibility.
Stage 1: Formatting — ruff format
ruff format --check {package}/ tests/
- PASS: no formatting changes needed
- FAIL: list files that need formatting; instruct Implementer to run
ruff format {package}/ tests/ and recommit.
Stage 2: Linting — ruff check
ruff check {package}/ tests/
- PASS: zero violations
- FAIL: list violations with: file, line number, rule code, message.
Stage 3: Type checking — mypy
mypy {package}/ --strict
- PASS: zero errors
- FAIL: list errors with: file, line number, error message.
Note which errors are in new code vs pre-existing (to avoid false blockers).
Stage 4: Tests and coverage — pytest
pytest tests/ -v --tb=short --cov={package} --cov-report=term-missing
- PASS: all tests pass AND coverage ≥ {coverage_threshold}%
- FAIL: list failing tests with: test name, module under test, error message.
If coverage < threshold: list modules below threshold.
FIXED — Test Writing Conventions
When writing missing tests (before or during QA):
- File naming:
tests/test_{module_name}.py
- Test naming:
test_{function_name}_{scenario} — one test per scenario
- Framework:
pytest only — no unittest, no nose
- Assertions: plain
assert with descriptive message strings
assert result == expected, f"Expected {expected}, got {result}"
- Edge cases: at least one test per edge case listed in the design brief
- Exception tests: verify both the exception type and the message substring
with pytest.raises(ValueError, match="must be positive"):
function_under_test(-1)
- Parametrize when testing the same function across multiple input variants:
@pytest.mark.parametrize("input,expected", [...])
def test_function_name_variants(input, expected):
...
FIXED — Test Structure Template
Use this structure for new test modules:
"""Tests for {package}.{module}.{submodule}."""
from __future__ import annotations
import pytest
from {package}.{module} import {function_name}
class TestFunctionName:
"""Tests for {function_name}()."""
def test_basic_case(self, {fixture_name}):
"""Happy path with valid domain fixture data."""
result = {function_name}({fixture_name}.{relevant_column})
assert result is not None
assert len(result) == len({fixture_name})
def test_edge_case_empty(self):
"""Empty input raises ValueError."""
with pytest.raises(ValueError, match="empty"):
{function_name}([])
def test_edge_case_nulls(self, {fixture_name}_with_nulls):
"""Function handles NaN inputs correctly."""
...
def test_raises_on_wrong_type(self):
"""Wrong input type raises TypeError."""
with pytest.raises(TypeError):
{function_name}("not a list")
FIXED — Contract Verification Checklist
Before writing a test, verify the function's contract matches the design brief:
| Check | How to verify | Failure means |
|---|
| Signature match | Compare inspect.signature() to design brief Section A | Implementer deviated from the brief |
| Parameter names | Check exact spelling — callers use keyword args | Breaking change risk |
| Return type | Check isinstance(result, expected_type) | Type annotation wrong |
| Statelessness | No open(), no pd.read_*, no print(), no module-level mutation | Design rule violation |
| Defensive inputs | Empty → ValueError; wrong type → TypeError; out-of-range → ValueError | Missing guard |
| Cross-track isolation | No imports from sibling tracks (from domain-context SKILL §FIXED — Cross-track isolation rules) | P0 blocker |
If the implementation deviates from the design brief, report to the SCRUM Master
as a QA failure — the Implementer must fix against the brief, not against the code.
FIXED — Reporting Formats
Per-Module Report
Use after running the gate on a single module:
## Code QA — {package}.{module} — [PASS / FAIL]
| Stage | Result | Detail |
|-------|--------|--------|
| ruff format | PASS / FAIL | N files need formatting |
| ruff check | PASS / FAIL | N violations |
| mypy | PASS / FAIL | N errors |
| pytest | PASS / FAIL | N/M tests passing |
| coverage | PASS / FAIL | N% (threshold: {coverage_threshold}%) |
### Tests
| Test | Scenario | Result |
|------|----------|--------|
| test_{function}_{scenario} | ... | PASS / FAIL |
### Failures (if any)
- [ruff/mypy/pytest] file:line — rule/error/assertion
Full-Phase Report
Use after running the gate on all modules for a phase:
## Code QA — Phase [ID] — [PASS / FAIL]
| Module | format | lint | types | tests | coverage | Result |
|--------|--------|------|-------|-------|----------|--------|
| {package}.module | ✅ | ✅ | ✅ | N/M | N% | PASS |
Total: N/M tests passing | Coverage: N% | Overall: PASS / FAIL
### Failures requiring rework
(one row per failure, with Implementer action)
ADAPT — Package Name and Test Directory
Agent instruction: read from domain-context SKILL §FIXED — Package.
- Package name:
{package_name}
- Package root:
{package_root}/
- Test directory:
tests/
- Coverage threshold:
{coverage_threshold}%
ADAPT — Test Fixtures
Agent instruction: read from domain-context SKILL §FIXED — Validation scenario.
- Scenario name:
{validation_scenario_name}
- Fixture names (from
conftest.py): {fixture_list}
- Expected columns:
{column_list}
- Expected shape:
{shape}
These are the canonical fixtures. All new tests must use these (or derive from them)
rather than creating ad-hoc data.
ADAPT — Cross-Track Isolation Rules
Agent instruction: read from domain-context SKILL
§FIXED — Modelling tracks (or equivalent for this domain).
The domain-context SKILL defines which modules belong to which track and which
inter-module imports are prohibited. Apply these rules in the contract verification
checklist step "Cross-track isolation".
Any cross-track import is a P0 blocker — report immediately to the SCRUM Master.