Skills

Install

$ npx ai-agents-skills add --skill code-review
Behavioral v1.1

Also Installs

Code Review

Two-stage code review: verify spec compliance FIRST, then assess code quality. Never reversed.

When to Use

  • Reviewing pull requests or code submissions
  • Validating implementation against requirements
  • Providing structured feedback on code
  • Ensuring spec compliance before quality assessment

Don’t use for:

  • General critical feedback on prompts/decisions (use critical-partner)
  • Debugging errors (use systematic-debugging)

Critical Patterns

✅ REQUIRED: Two-Stage Review (NEVER Reversed)

Stage 1: Spec Compliance (MUST come first)

  • Does code meet requirements?
  • Are all acceptance criteria satisfied?
  • Does behavior match specification?

Stage 2: Code Quality (ONLY after Stage 1 passes)

  • Is code maintainable?
  • Are best practices followed?
  • Performance considerations?
# ✅ CORRECT: Two-stage order

## Stage 1: Spec Compliance ✅
- ✅ POST /users creates user with email/password
- ✅ Returns 201 status with user object
- ✅ Email validation enforced
- ✅ Password hashed before storage
**Result**: Spec compliance PASSED

## Stage 2: Code Quality
- ⚠️ Password hashing uses deprecated bcrypt.hashSync (use async bcrypt.hash)
- ⚠️ No input sanitization for XSS prevention
- ✅ Error handling present
- ✅ TypeScript strict mode enabled

# ❌ WRONG: Quality feedback before spec check
"The code uses var instead of let" ← irrelevant if spec not met

Why this order?

  • Spec = correctness (does it work?)
  • Quality = maintainability (is it good?)
  • No point reviewing quality if behavior is wrong
  • Prevents wasting time on code that will be rewritten

✅ REQUIRED: File-by-File Analysis

Review each file separately with clear structure.

## File: src/services/UserService.ts

### Spec Compliance
- ✅ Implements registerUser as specified
- ✅ Returns Promise<User>
- ❌ Missing validateEmail method (required in spec)
- ❌ Password strength check missing (spec requires 8+ chars)

**Result**: FAIL - Fix spec issues before quality review

---

## File: src/repositories/UserRepository.ts

### Spec Compliance
- ✅ All CRUD methods present
- ✅ Returns correct types

### Code Quality (reviewed AFTER spec passed)
- Line 23: Use const instead of let (value never reassigned)
- Line 45-50: Extract validation logic to separate function
- Line 67: Add error handling for unique constraint violation

Benefits:

  • Clear scope per file
  • Easy to navigate review
  • Prevents context switching
  • Enables parallel fixes

✅ REQUIRED: Evidence-Based Feedback

Provide line numbers and specific examples.

# ❌ WRONG: Vague feedback
"Error handling could be better"

# ✅ CORRECT: Specific with evidence
**Line 34-38**: Error swallowed without logging or user feedback
```typescript
try {
  await updateUser(id, data);
} catch (error) {
  // Silent failure - user doesn't know what happened
}

Fix: Log error and provide user-friendly message

try {
  await updateUser(id, data);
  return { success: true };
} catch (error) {
  console.error('Failed to update user:', error);
  return {
    success: false,
    error: 'Unable to update user. Please try again.',
  };
}

**Evidence includes:**
- Line numbers (file.ts:34-38)
- Code snippets (what's wrong)
- Suggested fix (how to improve)
- Rationale (why it matters)

### ✅ REQUIRED: Stage 2 Quality Dimensions

Check these four dimensions when Stage 1 passes. Always cite file and line number.

**Security** (flag immediately — does not wait for Stage 2 order):

- Injections: SQL, NoSQL, command injection (parameterized queries? user input in queries?)
- XSS: `innerHTML`/`dangerouslySetInnerHTML` with user input not sanitized
- Auth: missing authentication checks, broken authorization, exposed credentials/secrets in code
- CSRF: missing tokens on state-changing endpoints
- Path traversal / SSRF: user-controlled file paths or URLs passed to `fetch`/`fs`

**Performance**:

- N+1 queries: loops that trigger individual DB calls
- Algorithmic complexity: O(n²) or worse in hot paths (nested loops over unbounded data)
- Resource leaks: unclosed files, connections, streams, event listeners
- Unbounded operations: queries/loops without pagination or size limits

**Correctness** (beyond spec — catches runtime failures):

- Null/undefined/empty input: are edge cases handled before use?
- Off-by-one: array bounds, pagination offsets, inclusive/exclusive ranges
- Race conditions: shared mutable state, concurrent writes without locking
- Type coercion: implicit conversions that may produce `NaN`, `undefined`, or `"0"`

**Maintainability**:

- Single responsibility: functions/classes doing more than one thing
- Test quality: tests are deterministic, independent, named descriptively
- Dead code / commented-out code: remove, don't archive in code
- Magic numbers/strings: extract to named constants

---

### ❌ NEVER: Review Quality Before Spec

If spec is not met, STOP. Do not proceed to quality review.

```markdown
# ❌ WRONG: Reviewing quality when spec fails

## Spec Compliance
- ❌ Email validation missing (required)
- ❌ Password not hashed (critical security issue)
- ❌ Missing error handling for duplicate emails

## Code Quality ← SHOULD NOT EXIST
- Use const instead of let
- Add JSDoc comments
- Extract magic numbers to constants

# ✅ CORRECT: Stop after spec failure

## Spec Compliance
- ❌ Email validation missing (required in spec section 2.1)
- ❌ Password not hashed (critical security issue - spec section 3.2)
- ❌ Missing error handling for duplicate emails (spec section 2.3)

**Result**: STOP

**Action Required**: Fix all 3 spec compliance issues. Code quality review will follow after spec passes.

**Priority**:
1. CRITICAL: Hash passwords before storage (security)
2. HIGH: Add email validation (data integrity)
3. HIGH: Handle duplicate email errors (user experience)

Decision Tree

Reviewing code?
  → Stage 1: Check spec compliance
    → Spec PASSED? → Proceed to Stage 2 (quality)
    → Spec FAILED? → STOP, provide spec feedback only

Reviewing a PR?
  → File-by-file analysis
  → Two-stage per file

Multiple files changed?
  → Review critical files first (core logic, security)
  → Then supporting files (tests, docs)

Need general critical feedback on approach?
  → Use critical-partner (not code-review)

Debugging an error in existing code?
  → Use systematic-debugging (not code-review)

Reviewing architectural decisions?
  → Use critical-partner or brainstorming

Edge Cases

Spec is ambiguous: Flag ambiguity before review. Ask: “Spec says X, but could mean Y or Z. Which is correct?”

Partial implementation: Review completed parts only. Note: “Reviewed implemented features. Features X, Y not yet implemented.”

Breaking changes: Check if intentional and documented. Flag unintentional breaks.

Performance regressions: If spec includes performance requirements, verify with benchmarks.

Security issues: Always flag security issues regardless of stage. Security > process.


Checklist

  • Stage 1 (spec compliance) completed BEFORE Stage 2
  • If spec fails, quality review SKIPPED
  • Each file reviewed separately
  • Line numbers provided for all issues
  • Evidence-based feedback (code snippets + fixes)
  • Recommendations prioritized (critical → high → medium → low)
  • Security issues flagged immediately
  • Breaking changes identified
  • Test coverage assessed (if applicable)

Example

# Code Review: User Registration Feature

## Summary
4 files reviewed — spec compliance PASS ✅, code quality PASS with 3 minor suggestions ⚠️

---

## File: src/services/UserService.ts

### Stage 1: Spec Compliance ✅

- ✅ registerUser accepts email/password (spec 2.1)
- ✅ Returns User object without password (spec 2.2)
- ✅ Email validation enforced (spec 2.3)
- ✅ Password hashed with bcrypt (spec 3.1)
- ✅ Duplicate email returns 409 error (spec 2.4)

**Result**: Spec compliance PASSED

### Stage 2: Code Quality

**Line 23-25**: Use async bcrypt.hash instead of deprecated hashSync
```typescript
// Current (deprecated)
const hashed = bcrypt.hashSync(password, 10);

// Recommended
const hashed = await bcrypt.hash(password, 10);

Line 45: Extract magic number to constant

// Current
if (password.length < 8) throw new Error('Password too short');

// Recommended
const MIN_PASSWORD_LENGTH = 8;
if (password.length < MIN_PASSWORD_LENGTH) throw new ValidationError('Password too short');

Line 67-70: Add JSDoc for public method

/**
 * Registers a new user with email and password
 * @param email - User email address (validated)
 * @param password - Plain text password (will be hashed)
 * @returns User object without password
 * @throws ConflictError if email already exists
 * @throws ValidationError if input invalid
 */
export async function registerUser(email: string, password: string): Promise<User>

Overall Assessment

Spec Compliance: ✅ PASS (all requirements met)

Code Quality: ⚠️ PASS with minor improvements (3 non-blocking suggestions; production-ready as-is)

Security: ✅ No issues (passwords hashed, inputs validated, no sensitive data leaked)

Recommendation: ✅ APPROVE with suggestions


---

## Resources

- [critical-partner](../critical-partner/SKILL.md) - General critical feedback
- [code-conventions](../code-conventions/SKILL.md) - Code standards and organization
- [typescript](../typescript/SKILL.md) - Type safety review
- [systematic-debugging](../systematic-debugging/SKILL.md) - Debugging methodology
- [verification-protocol](../verification-protocol/SKILL.md) - Evidence-based verification