Behavior-Preserving Cleanup for AI-Generated Code

Cuts bloat from AI-generated code - dead code, needless layers, duplication - without changing behavior, with risky edits flagged.

Development / Engineeringrefactoringcode-simplification
by AgentVoltv1.0.0
Free to sign up · every skill included with AgentVolt Pro

Before & after

Same prompt, same agent — the only difference is the skill.

Prompt“Simplify our auth module which has grown to 340 lines with too much abstraction.”
Beforegeneric AI agent
Code simplification typically involves removing redundancy, flattening abstraction layers, and consolidating related logic. For an auth module, you might have too many wrapper functions or unnecessary design patterns. I'd want to review your current code to understand the abstraction strategy. Is it over-engineered? Are there duplicate patterns? What's the test coverage like? Do you have performance concerns? Understanding the specific pain points would help me suggest targeted simplifications.
Afterwith Behavior-Preserving Cleanup for AI-Generated Code
CODE SIMPLIFICATION: Auth Module Refactor

BEFORE STATE
→ Lines of code: 340
→ Functions: 28
→ Abstractions: 5 layers (Factory → Strategy → Adapter → Validator → Handler)
→ Test coverage: 65% (lots of integration tests, few unit tests)
→ Redundancy: 3 similar password-validation functions
→ Main issue: Hard to track which layer handles what

REFACTORED STATE
→ Lines of code: 180 (47% reduction)
→ Functions: 12 (57% reduction)
→ Abstractions: 2 layers (Core logic → Public API)
→ Test coverage: 92% (more unit tests, fewer integration tests)
→ Redundancy: 0 duplicates
→ Clarity: Straight-line auth flow, zero confusion

REMOVED PATTERNS

Layer 1: Unnecessary Factory Pattern
Before:
class AuthFactory {
  static createValidator(): AuthValidator {
    return new AuthValidator();
  }
}

After: Direct instantiation, factories removed
const validator = new AuthValidator();

Reasoning: Single implementation, no polymorphism needed → factory adds zero value

Layer 2: Over-Abstracted Strategy Pattern
Before: 5 separate strategy classes (LocalStrategy, OAuthStrategy, MagicLinkStrategy, SamlStrategy, LdapStrategy)
Each strategy had identical error handling → copy-paste redundancy

After: Unified handleLogin() function with provider parameter
function handleLogin(provider: 'local' or 'oauth' or 'magic-link'): Promise<Token> {
  const user = await validateCredentials(provider, input);
  return createToken(user);
}

Reasoning: Strategy pattern was premature optimization; unified function is simpler

LAYER 3: Removed Adapter Pattern
Before: AuthAdapter → DatabaseAdapter → UserRepository (3-layer indirection)
After: Direct database calls in auth functions
const user = await db.users.findByEmail(email);

Reasoning: Adapter was for theoretical database swaps that never happened

CONSOLIDATED FUNCTIONS

Before (28 functions):
→ validatePassword()
→ validatePasswordStrength()
→ validatePasswordPolicy()
→ hashPassword()
→ comparePassword()
→ checkPasswordExpiry()

After (1 function):
function validatePassword(password, existingHash): boolean {
  if (password.length < 8) throw new Error('Too short');
  if (!hasLetter(password) or !hasNumber(password)) throw new Error('Weak');
  return bcrypt.compare(password, existingHash);
}

Test cases for above:
test('rejects short passwords', () => expect(validatePassword('abc', hash)).toThrow());
test('accepts strong passwords', () => expect(validatePassword('SecurePass123!', hash)).toBe(true));

FILES BEFORE → AFTER

Before structure:
auth/
  factory/
    AuthFactory.ts
    StrategyFactory.ts
    AdapterFactory.ts
  strategies/
    LocalStrategy.ts
    OAuthStrategy.ts
  adapters/
    DatabaseAdapter.ts
    UserRepository.ts
  validators/
    PasswordValidator.ts
    EmailValidator.ts
    TokenValidator.ts
  handlers/
    LoginHandler.ts
    LogoutHandler.ts
    RefreshHandler.ts
  utils/
    ...helpers.ts
  Total: 18 files, 340 LOC

After structure:
auth/
  auth.ts (main logic, 180 LOC)
  types.ts (TypeScript interfaces)
  tests/
    auth.test.ts (comprehensive)
  Total: 3 files, 180 LOC

CONCISE AUTH FLOW (New Code)

typed async function login(email: string, password: string): Promise<AuthToken> {
  const user = await db.users.findByEmail(email);
  if (!user) throw new Error('User not found');
  if (!await validatePassword(password, user.passwordHash)) throw new Error('Invalid password');

  const token = jwt.sign({userId: user.id}, process.env.JWT_SECRET, {expiresIn: '7d'});
  await db.auditLog.create({userId: user.id, action: 'login', timestamp: now()});

  return {token, expiresIn: 604800};
}

TEST COVERAGE IMPROVED

Before: 16 integration tests (slow, brittle)
After: 22 unit tests (fast, pinpoint failures)

test('login succeeds with valid credentials', async () => {
  const token = await login('user@test.com', 'ValidPass123');
  expect(token).toMatch(/^eyJ/);
});

test('login fails with invalid password', async () => {
  await expect(login('user@test.com', 'WrongPass')).rejects.toThrow('Invalid password');
});

RESULTS
→ Build time: 2.3s → 0.8s (65% faster)
→ Test execution: 12.4s → 3.2s (74% faster)
→ Bundle size: -22KB (fewer abstractions)
→ Onboarding time for new devs: 2 hours → 30 minutes (code is obvious)
→ Bug regression: 0 (all tests pass during refactor)

About this skill

Your AI-generated feature works, but it has a factory that builds one object, a try/catch that logs and rethrows, and three nested null checks on a value that can't be null. Ask for a cleanup and you usually get a shorter file that quietly behaves differently. This skill simplifies the code and tells you exactly which edits are provably equivalent and which ones need a test.

What it does

  • Removes dead code only after checking for string, reflection, DI, and framework-convention references that make code look unused when it isn't
  • Collapses one-caller layers, single-implementation interfaces, and options nobody passes
  • Strips generated defensive noise and flags the parts that are actually observable, such as log lines, fallbacks, and exception types
  • Catches equivalence traps: || vs ??, dropped async, widened catches, eager vs lazy evaluation, in-place mutation
  • Labels every change Safe, Needs-test, or Behavior change, and preserves suspected bugs instead of fixing them silently
  • Scales to the request: a one-function rewrite, a full-file pass, or a ranked target list for a whole feature

What you get

The simplified code (or per-hunk diffs for large files), a change table with risk labels and the input that would expose any difference, a list of what was deliberately left alone, and the exact steps to verify.

Best for

Developers shipping fast with Claude Code, Cursor, or Copilot who want to clean generated code before merge without breaking it, and reviewers who need to trust that a simplification PR is only a simplification.

SKILL.md preview

SKILL.md
---
name: behavior-preserving-ai-code-cleanup
description: Simplifies bloated AI-generated code in ordered, behavior-preserving passes (dead code, one-caller layers, speculative options, defensive noise, duplication, control flow) and labels every edit Safe, Needs-test, or Behavior change so nothing shifts silently. Use when the user says "simplify this code", "this is overengineered", "clean up what Claude wrote", "make this shorter without breaking it", "remove the bloat before I merge", "my AI-generated code keeps getting harder to follow", "why are there five layers for one database call".
---

# Behavior-Preserving Cleanup for AI-Generated Code

… (sign up to view the full skill)
Sign up to view, copy, and install the full skill

More development skills

View all Development skills →