Quality Gates
agentful's quality gates ensure that all code entering your codebase meets production-ready standards. This comprehensive guide explains each gate, passing criteria, and how to troubleshoot failures.
Overview
All code must pass 6 quality gates before being marked complete:
- Tests Passing - All tests must pass
- TypeScript Clean - No type errors
- Lint Clean - No lint errors
- Dead Code Removed - No unused exports, files, or dependencies
- Coverage ≥ 80% - Test coverage threshold
- Security Clean - No vulnerabilities, secrets, or debug logs
The reviewer agent runs all checks after every code change. The fixer agent automatically resolves failures when possible.
Gate 1: Tests Passing
Purpose
Ensure all tests pass before accepting new code.
Check Command
npm testPassing Criteria
- Exit code: 0 (success)
- Failed tests: 0
- No test timeouts or crashes
Failure Scenarios
// ❌ Failing test
test('should authenticate user', async () => {
const result = await authenticate('user@example.com', 'wrong-password');
expect(result).toBeTruthy(); // Fails: result is null
});Common Issues
- Test timeouts - Increase timeout or fix async code
- Flaky tests - Tests that pass sometimes, fail sometimes
- Broken fixtures - Mock data not matching current code
- Missing setup - Tests not initializing dependencies
Auto-Fixable
The fixer agent can:
- Fix simple assertion errors
- Update outdated test data
- Increase timeouts for slow tests
- Remove duplicate or redundant tests
Manual Fixes Required
- Complex test logic failures
- Race conditions in tests
- Environment-specific test issues
Gate 2: TypeScript Clean
Purpose
Catch type errors at compile time, ensuring type safety.
Check Command
npx tsc --noEmitPassing Criteria
- Exit code: 0
- Type errors: 0
- No implicit any
Failure Scenarios
// ❌ Type error: Property does not exist
interface User {
name: string;
email: string;
}
const user: User = { name: 'John', email: 'john@example.com' };
console.log(user.age); // Error: Property 'age' does not exist
// ❌ Type error: Wrong type
function calculateTotal(price: number, quantity: number): number {
return price * quantity;
}
calculateTotal('10', 5); // Error: Argument of type 'string' not assignable to 'number'
// ❌ Type error: Missing return type
async function fetchData() { // Should specify Promise<User>
return await db.user.findFirst();
}Common Issues
- Missing type annotations - Functions without return types
- Implicit any - Parameters without types
- Wrong types - Type mismatches
- Missing imports - Types not imported
- Library types - @types packages not installed
Auto-Fixable
The fixer agent can:
- Add missing type annotations
- Fix obvious type mismatches
- Install missing @types packages
- Remove unused type imports
- Add proper interface definitions
Manual Fixes Required
- Complex type logic
- Generic type constraints
- Type assertion decisions
- Architectural type design
Gate 3: Lint Clean
Purpose
Enforce consistent code style and catch common errors.
Check Command
npm run lintPassing Criteria
- Exit code: 0
- Lint errors: 0
- Warnings: Allowed (not blocking)
Failure Scenarios
// ❌ Lint error: Unused variable
const unusedVar = 5; // Error: 'unusedVar' is assigned a value but never used
// ❌ Lint error: Inconsistent spacing
import{Component}from 'react'; // Missing spaces
// ❌ Lint error: Missing semicolon (if configured)
const value = 42 // Error: Missing semicolon
// ❌ Lint error: Console statement
console.log('Debug output'); // Error: Unexpected console statementCommon Issues
- Unused variables - Variables declared but not used
- Console statements - console.log left in code
- Formatting - Inconsistent spacing, quotes, etc.
- Import order - Imports not sorted correctly
- Naming conventions - Variables not following conventions
Auto-Fixable
The fixer agent can:
- Remove unused variables and imports
- Delete console.log statements
- Fix formatting issues (with --fix flag)
- Reorder imports
- Fix naming conventions
Manual Fixes Required
- Complex refactoring to fix issues
- Architectural lint rule violations
Gate 4: Dead Code Removed
Purpose
Eliminate unused code that bloats the codebase and creates maintenance burden.
Check Commands
# Try knip first (most comprehensive)
npx knip --reporter json 2>/dev/null
# Fall back to ts-prune
npx ts-prune 2>/dev/null
# Manual grep check
grep -r "export.*function\|export.*class" src/ --include="*.ts" --include="*.tsx"Passing Criteria
- Unused exports: 0
- Unused files: 0
- Unused dependencies: 0
- Unused imports: 0
Failure Scenarios
// ❌ Unused export
// src/utils/date.ts
export function formatDate(date: Date): string { // Never imported anywhere
return date.toISOString();
}
export function parseDate(str: string): Date { // Used in other files
return new Date(str);
}
// ❌ Unused file
// src/components/OldWidget.tsx
// Entire file never imported anywhere
// ❌ Unused import
import { unused, used } from './module'; // 'unused' never referenced
// ❌ Unused dependency
// package.json
{
"dependencies": {
"lodash": "^4.17.21" // Never used in code
}
}Common Issues
- Unused exports - Functions/classes exported but never imported
- Unused files - Files not imported by any other file
- Unused dependencies - Packages in package.json but not used
- Unused imports - Imports not referenced in file
- Commented code - Old code commented out instead of deleted
Auto-Fixable
The fixer agent can:
- Delete unused exports
- Delete unused files
- Remove unused imports
- Uninstall unused dependencies
- Remove commented-out code
Manual Fixes Required
- Determining if code is intentionally exported for library
- Code used in conditional imports
- Dynamic imports not detected by tools
Gate 5: Coverage ≥ 80%
Purpose
Ensure code is adequately tested to prevent regressions.
Check Command
npm test -- --coverage --reporter=jsonPassing Criteria
- Overall coverage: ≥ 80%
- File-level coverage: No individual file below 60%
Failure Scenarios
// ❌ Untested function
// src/utils/string.ts
export function capitalize(str: string): string {
return str.charAt(0).toUpperCase() + str.slice(1);
}
// No test file exists: src/utils/__tests__/string.test.ts
// ❌ Partially tested function
// src/services/user.ts
export async function createUser(email: string, password: string) {
if (await userExists(email)) {
throw new Error('User exists');
}
const hashed = await hashPassword(password);
return db.user.create({ data: { email, password: hashed } });
}
// Test only covers success case, not error caseCoverage Metrics
Track these metrics:
{
"lines": 85, // Percentage of lines executed
"functions": 90, // Percentage of functions called
"branches": 75, // Percentage of if/else branches taken
"statements": 85 // Percentage of statements executed
}All metrics should be ≥ 80%.
Common Issues
- Missing tests - New code without test coverage
- Untested branches - if/else not fully covered
- Error paths - try/catch error cases not tested
- Edge cases - Boundary conditions not tested
- Async paths - Promise rejections not tested
Auto-Fixable
The fixer agent can:
- Generate basic unit tests for untested functions
- Add test cases for missing branches
- Create tests for error paths
- Increase coverage by adding test scenarios
Manual Fixes Required
- Complex integration test setup
- E2E test scenarios
- Performance testing
- Testing with external dependencies
Gate 6: Security Clean
Purpose
Prevent security vulnerabilities and secrets in code.
Check Commands
# npm audit for vulnerabilities
npm audit --production
# Check for hardcoded secrets
grep -rE "(password|secret|token|api_key|apikey)\s*[:=]\s*['\"][^'\"]{10,}['\"]" \
src/ --include="*.ts" --include="*.tsx"
# Check for console.log
grep -rn "console\.(log|debug|warn)" src/ --include="*.ts" --include="*.tsx"
# Check for @ts-ignore
grep -rn "@ts-ignore\|@ts-nocheck" src/ --include="*.ts" --include="*.tsx"Passing Criteria
- Critical vulnerabilities: 0
- High vulnerabilities: 0
- Hardcoded secrets: 0
- console.log statements: 0
- @ts-ignore: 0
Failure Scenarios
// ❌ Hardcoded secret
const API_KEY = "sk-1234567890abcdef"; // NEVER commit this
// ✅ Use environment variables
const API_KEY = process.env.API_KEY;
// ❌ console.log left in code
async function login(email: string, password: string) {
console.log('Login attempt:', email); // Remove this
const user = await authenticate(email, password);
return user;
}
// ❌ @ts-ignore silencing error
// @ts-ignore
const data = JSON.parse(maybeInvalidJSON); // Fix the type instead
// ❌ npm audit vulnerability
// package.json
{
"dependencies": {
"lodash": "4.17.15" // Has known high-severity vulnerability
}
}Common Issues
- Hardcoded secrets - API keys, passwords in code
- Debug statements - console.log, console.debug left in
- Type suppressions - @ts-ignore hiding real issues
- Vulnerable dependencies - Outdated packages with CVEs
- Insecure configs - CORS settings, auth misconfigurations
Auto-Fixable
The fixer agent can:
- Remove console.log statements
- Replace hardcoded secrets with env vars
- Remove @ts-ignore and fix underlying type issues
- Update vulnerable dependencies
- Add .env.example entries for required env vars
Manual Fixes Required
- Complex secret management setup (Vault, AWS Secrets)
- Breaking dependency updates
- Architecture-level security changes
Quality Gate Workflow
1. Implementation
Agent implements feature:
// Backend agent creates auth service
export class AuthService {
async login(email: string, password: string) {
console.log('Login:', email); // Oops, left debug log
const user = await db.user.findFirst({ where: { email } });
if (!user) throw new Error('Invalid credentials');
return generateToken(user);
}
}2. Review
Reviewer agent runs all checks:
{
"passed": false,
"checks": {
"tests": { "passed": false, "failed": 2 },
"typescript": { "passed": true },
"lint": { "passed": false },
"deadCode": { "passed": true },
"coverage": { "passed": false, "actual": 65 },
"security": { "passed": false, "issues": ["console.log in auth.service.ts:5"] }
}
}3. Fix
Fixer agent resolves issues:
// Removed console.log
export class AuthService {
async login(email: string, password: string) {
const user = await db.user.findFirst({ where: { email } });
if (!user) throw new Error('Invalid credentials');
return generateToken(user);
}
}
// Added missing tests
// Improved coverage to 82%4. Re-Review
Reviewer runs checks again:
{
"passed": true,
"summary": "All quality gates passed"
}5. Complete
Orchestrator marks feature complete:
{
"authentication": {
"status": "complete",
"score": 100
}
}Monitoring Quality Gates
Check Status
# View latest review
cat .agentful/last-review.json
# View gate status in completion
cat .agentful/completion.json | jq '.gates'
# Run validation manually
/agentful-validateGate Status Output
{
"gates": {
"tests_passing": true,
"no_type_errors": true,
"no_dead_code": true,
"coverage_80": false,
"security_clean": true
},
"overall": 83.3
}Troubleshooting Gate Failures
Gate Fails Repeatedly
-
Check last-review.json:
cat .agentful/last-review.json | jq '.mustFix' -
Identify pattern - Same file failing?
-
Manual intervention - If fixer can't resolve, fix manually
-
Re-run validation:
/agentful-validate
Coverage Stuck Below 80%
-
Check by-file coverage:
npm test -- --coverage --reporter=json # Look at coverage report for low files -
Target lowest files - Add tests to worst files first
-
Test generation - Fixer can generate basic tests
-
Manual test writing - Complex scenarios need manual tests
Dead Code Keeps Returning
-
Check imports - Unused imports often reappear
-
Check generated code - Some tools generate unused code
-
Check barrel exports - index.ts files exporting unused items
-
Regular cleanup - Run knip periodically
Security Issues Won't Auto-Fix
- Secrets in old commits - Use git-secrets or BFG
- Breaking dependency updates - Manual update and testing
- Architecture issues - May require design changes
Customizing Gates
Adjust Coverage Threshold
Edit .claude/agents/reviewer.md:
### 6. Coverage Check
**FAIL if:** Coverage < 90% # Changed from 80%Add Custom Gates
Add new check to reviewer:
### 7. Performance Check
```bash
npm run benchmarkFAIL if: Response time > 100ms
### Disable Gates (Not Recommended)
Only disable if truly not needed:
```markdown
### 6. Coverage Check
**DISABLED:** Not applicable for this projectBest Practices
- Run locally before commit - Catch issues early
- Watch gate trends - Coverage going up or down?
- Address failures quickly - Don't let debt accumulate
- Keep tests fast - Slow tests discourage running them
- Review security regularly - Run npm audit weekly
- Monitor dead code - Run knip monthly cleanup
Next Steps
- Autonomous Development Overview - Back to overview
- Recovery Strategies - How fixer resolves issues
- Monitoring - Track gate status over time