plugins/nw/skills/nw-quality-framework/SKILL.md
Quality gates - 11 commit readiness gates, build/test protocol, validation checkpoints, and quality metrics
npx skillsauth add nwave-ai/nwave nw-quality-frameworkInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
All pass before committing:
Note: Reviewer approval (formerly Gate 12) and Testing Theater detection (formerly Gate 13) enforced at deliver-level Phase 4 (Adversarial Review via /nw-review), not per step.
Definition: Acceptance tests pass because test fixtures create the expected end-state directly, rather than exercising production code through the driving port. Tests verify the correct outcome from the WRONG source.
Detection: After GREEN phase, run git diff --name-only. If files_to_modify
from the roadmap step have NO changes but tests flipped from RED to GREEN, this is
Fixture Theater. The test fixtures are implementing the feature, not production code.
Litmus test: Delete the new production code (or revert production files to pre-GREEN state). If tests still pass, it's Fixture Theater.
Prevention:
files_to_modify MUST appear in git diffgit diff --stat shows only test files changed after GREEN, BLOCK the COMMITProvenance: 2026-05-02, RCA docs/analysis/rca-systematic-duplication-despite-design.md. Outcomes-registry catches duplicate outcomes (same input/output contract). It does NOT catch the failure mode where a NEW outcome is genuinely different but should have extended an existing component instead of being shipped as a parallel implementation in a new file.
This rule is language-agnostic: it applies to any source file regardless of host language. Examples in this section use multiple languages to underscore that.
Rule: before creating a NEW source file under a path that already contains ≥1 file in the same role/layer, the crafter MUST emit an Extension Justification block. The block has exactly four lines:
WHY-NEW-FILE: <relative-path-of-new-file>
CLOSEST-EXISTING: <relative-path-of-the-most-similar-existing-file>
EXTENSION-COST: <one sentence on what extending CLOSEST-EXISTING would require>
PARALLEL-RATIONALE: <one sentence on why a separate file is justified instead>
Trigger: applies when ANY of these are true for the proposed new file:
domain/rules/e3b_cherry_pick.<ext> when e3_non_empty.<ext> exists; or new internal/handlers/login.go when signup.go exists; or new src/services/Email.cs when Sms.cs exists)use / require / using / include / import) overlaps an existing sibling by ≥50%E3Rule ↔ E3bRule, LoginHandler ↔ SignupHandler, EmailService ↔ SmsService, PgRepository ↔ MysqlRepository)Not triggered when:
__init__.py / conftest.py; Go doc.go; Rust mod.rs; TypeScript index.ts re-export shim; Ruby version.rb; Java/Kotlin empty package-info.java. The rule of thumb: if removing the file's contents (keeping the empty file) leaves the package importable, it is a marker — not a component.Enforcement: the crafter's PREPARE phase MUST inventory existing files in <target-path>/ before producing the first file-write. If the inventory is non-empty for a target path AND the new file is not a marker per the exclusion above, the Extension Justification block is mandatory before each new-file write. Reviewer agents flag missing blocks as a HIGH severity finding.
Self-test for the rationale: a valid PARALLEL-RATIONALE answers the question "what would break or what would become awkward if this lived inside CLOSEST-EXISTING?". Non-answers like "different concern", "cleaner separation", "single responsibility" are rejected — those are the phrases a parallel-creation bias produces without effort. Concrete answers cite at least one of: incompatible interface/signature, different lifecycle (init order, hot-reload, deployment unit), incompatible dependency set, divergent target/runtime (e.g. server-side vs client-side, native vs WASM), or DESIGN-table-recorded boundary that already adjudicated the split.
Why this is a discipline rule, not a structural detector: structural detectors (call-graph + body-shape match) live in project tsunami and are language-aware by design. Extension Justification is the cheap behavioral nudge that runs at WRITE-time on any LLM-driven crafter regardless of target language. The block makes the bias visible to the reviewer; it does NOT block the write. If the rationale is weak, the reviewer catches it at Phase 4 (Adversarial Review).
After every TDD cycle, Mikado leaf, or atomic transformation:
# 1. BUILD
dotnet build --configuration Release --no-restore
# 2. TEST
dotnet test --configuration Release --no-build --verbosity minimal
# 2.5. QUALITY VALIDATION (before committing)
# - Edge cases tested (null, empty, malformed, boundary)
# - No silent error handling (all errors logged/alerted)
# - Real data golden masters included where applicable
# - API assumptions documented
# 3. COMMIT (if tests pass)
# Use appropriate format below
# 4. ROLLBACK (if tests fail)
git reset --hard HEAD^ # Maintain 100% green discipline
For commit message formats, load the collaboration-and-handoffs skill.
Track: cyclomatic complexity (reduction) | maintainability index (improvement) | technical debt ratio (reduction) | test coverage (maintenance) | test effectiveness (75-80% mutation kill rate at Phase 2.25) | code smells (systematic elimination across 22 types).
For mutation testing integration, load the property-based-testing skill.
9 design constraints for clean OOP code in the hexagonal core (Jeff Bay, ThoughtWorks Anthology). Apply during GREEN and COMMIT phases.
| # | Rule | Rationale | Layer |
|---|------|-----------|-------|
| 1 | One indentation level per method | Forces decomposition | Domain, Application |
| 2 | No else keyword | Guard clauses, early returns | Domain, Application |
| 3 | Wrap all primitives and strings | Value objects | Domain |
| 4 | First-class collections | Domain collection types | Domain |
| 5 | One dot per line | Law of Demeter | Domain, Application |
| 6 | No abbreviations | Intention-revealing names | All |
| 7 | Small entities (<50 LOC classes, <10 LOC methods) | SRP | Domain, Application |
| 8 | Max 2 instance variables per class | Promotes decomposition | Domain |
| 9 | No getters/setters | Tell, don't ask | Domain, Application |
Getters are acceptable in these cases:
Rule 9 applies strictly to domain entities and application services. Behavior through commands, not data access.
For EVERY driven port adapter, complete this table:
| Port | InMemory Behavior | Cannot Model | Covered By | |------|-------------------|-------------|------------| | (port name) | (what InMemory returns) | (real condition it can't model) | (test name that covers the gap) |
If "Covered By" is empty for any row, the test suite has a blind spot. Flag as HIGH.
For EVERY InMemory test double, verify it validates inputs like the real adapter:
| Test Double | Validates None? | Validates empty strings? | Validates ranges? | Matches real preconditions? | |-------------|----------------|------------------------|-------------------|---------------------------| | (double name) | YES/NO | YES/NO | YES/NO | YES/NO |
If any cell is NO, the test double is a liar — it accepts inputs the real adapter rejects. Flag as HIGH.
A permissive test double creates invisible wiring bugs: tests pass, production crashes.
For EVERY external system (subprocess, API, DB):
Consequence rules:
Gate name: Delta-first paradigm coverage on state-mutating code.
Criterion: Tests on installer-class, sync-class, or hook-registration code that mutate user-observable state in ≥2 slots MUST declare universe and expected deltas via assert_state_delta, OR explicitly document a bypass justification citing one of the named bypass conditions.
Why this gate exists: bug #48 regression class — "test asserts post-state property without verifying surrounding state remained unchanged." Production code writes to additional state slots; tests that only assert on the primary output slot miss these mutations silently. Empirical evidence: 4/7 installer test files (57% hit rate) exposed previously-untracked mutations during migration, including:
attribution.trailer written silently — post-state test only checked returncodecontent.full transitioned None → str — test never declared content.full in universeAddressable scope: ~28% of the suite (installer + sync + hook tests). NOT applied to pure-function tests, schema validators, or interaction tests — those retain standard assertion style. Gate does not block commits from the other 72%.
How to verify at review:
tests/installer/, tests/des/integration/, tests/sync/ import assert_state_delta.Bypass conditions (any one sufficient to exempt a test):
assert result.returncode == 0)validate_prerequisites() failure pathmock.assert_called_with(...))Full details: nWave/skills/nw-tdd-methodology/SKILL.md section "Delta-First Test Paradigm (state-mutating code)".
testing
Acceptance test creation methodology for the DISTILL wave. Domain knowledge for the acceptance designer agent: port-to-port principle, prior wave reading, wave-decision reconciliation, graceful degradation, and document back-propagation.
testing
Methodology for minimizing test count while maximizing behavioral coverage - behavior definition, anti-pattern catalog, consolidation patterns, stopping criterion, coverage-preserving validation
testing
Methodology for minimizing test count while maximizing behavioral coverage - behavior definition, anti-pattern catalog, consolidation patterns, stopping criterion, coverage-preserving validation
development
Design mandates for acceptance tests - hexagonal boundary, business language abstraction, user journey completeness, pure function extraction, 3 Pillars (domain language / chained narrative / production composition), and the layered ATD discipline (Universe-bound assertion, layer-dependent PBT mode, two-tier acceptance, example-based sad paths)