refactor · git:20260206.c8d6258 · 2026-02-06 · sha256 a49d77f0cd1e062e

refactor git:20260206.c8d6258A

Immutable. This exact content is served forever at /api/v1/blob/a49d77f0cd1e062e.

---
name: refactor
description: "Safe codebase refactoring with characterization tests, incremental changes, and continuous verification. Automatically activates when users want to refactor code, extract methods/classes, simplify logic, reduce duplication, improve naming, restructure modules, or clean up technical debt."
disable-model-invocation: false
argument-hint: "<refactoring_description> [--scope file|module|project] [--interactive]"
allowed-tools: Read, Write, Edit, Bash, Grep, Glob, Task, TaskCreate, TaskUpdate, TaskList, TaskGet, WebFetch, AskUserQuestion
hooks:
  Stop:
    - hooks:
      - type: agent
        prompt: "Verify refactoring is safe and complete:\n\n1. **Behavior preserved**: Run the full test suite using the test command from Phase 0. All tests must pass — the same tests that passed before the refactoring must still pass.\n2. **No regressions**: Run linter and type checker. No new errors allowed.\n3. **Characterization tests**: If characterization tests were added in Phase 3, verify they still pass.\n4. **Clean diff**: Review git diff to confirm only intentional refactoring changes exist — no accidental behavior changes, debug code, or commented-out code.\n\nIf any verification fails, report it clearly and return decision: block with reason. Only allow stopping when the refactoring is verified safe.\n\nUse test commands discovered in Phase 0. If not available, discover them now from CLAUDE.md or project files."
        timeout: 180
---

# Refactor

Refactor code safely using characterization tests, incremental changes, and continuous verification. Every change preserves existing behavior while improving code structure, readability, and maintainability.

## Refactoring Goal

$ARGUMENTS

## Core Principle: Behavior Preservation

**CRITICAL**: Refactoring changes code structure WITHOUT changing behavior. Every step must be verified against existing tests. If tests break, the refactoring introduced a bug — revert and retry.

## Anti-Hallucination Guidelines

1. **Read before changing** — Never refactor code that has not been read and understood. Understand all callers and dependencies first.
2. **Test before and after** — Run the full test suite before starting. Run it again after every incremental change. The results must match.
3. **Characterization tests first** — If test coverage is insufficient for the target code, write characterization tests that capture current behavior BEFORE refactoring.
4. **Incremental changes** — Make one small, verifiable change at a time. Never combine multiple refactoring steps into a single edit.
5. **No feature changes** — Do not add features, fix bugs, or change behavior during refactoring. These are separate tasks.
6. **Reference real code** — Never make claims about code structure that has not been verified by reading the actual files.

## Quality Gates

This skill includes automatic refactoring verification before completion:

### Safety Verification (Stop Hook)

When attempting to stop working, an automated verification agent runs to ensure the refactoring is safe:

**Verification Steps:**
1. **Behavior preserved**: Full test suite passes (same results as before refactoring)
2. **No regressions**: Linter and type checker report no new errors
3. **Characterization tests**: Any tests added to capture behavior still pass
4. **Clean diff**: Only intentional structural changes exist

**Behavior:**
- ✅ **All verifications pass**: Refactoring marked complete
- ❌ **Any test fails**: Completion blocked, Claude reverts or fixes the breaking change
- ⚠️ **New lint/type errors**: Completion blocked until resolved

**Example blocked completion:**
```
⚠️ Refactoring verification failed:

Tests: ❌ FAILED (2 tests failing)
  - test_calculate_total: Expected 150.0, got 150
  - test_format_output: AssertionError: output format changed

Lint: ✅ PASSED
Type Check: ✅ PASSED

🔧 Refactoring introduced behavior changes. Revert the last change and retry
with a smaller step.
```

## Task Management

This skill uses Claude Code's Task Management System for strict sequential dependency tracking through the refactoring workflow.

**When to Use Tasks:**
- Multi-step refactoring across files or modules
- Extract method/class operations requiring dependency analysis
- Large-scale restructuring with many callers
- Work requiring progress tracking across sessions

**When to Skip Tasks:**
- Simple rename (single variable/function)
- Trivial formatting or style fix
- Single-line simplification

**Task Structure:**
Refactoring creates a strict sequential chain where each phase must complete before the next can start, ensuring characterization tests exist before any structural changes begin.

## Implementation Workflow

**Task tracking replaces TodoWrite.** Create task chain at start, update as completing each phase.

### Phase 0: Project Discovery (REQUIRED)

**Step 0.1: Create Task Dependency Chain**

Before refactoring, create the strict sequential task structure:

```
TaskCreate:
  subject: "Phase 0: Discover project workflow"
  description: "Identify test, lint, type-check commands from CLAUDE.md and task runners"
  activeForm: "Discovering project workflow"

TaskCreate:
  subject: "Phase 1: Analyze refactoring scope"
  description: "Map dependencies, callers, and test coverage for target code"
  activeForm: "Analyzing refactoring scope"

TaskCreate:
  subject: "Phase 2: Write characterization tests"
  description: "Ensure sufficient test coverage before making structural changes"
  activeForm: "Writing characterization tests"

TaskCreate:
  subject: "Phase 3: Incremental refactoring"
  description: "Apply refactoring in small verified steps"
  activeForm: "Refactoring incrementally"

TaskCreate:
  subject: "Phase 4: Final verification"
  description: "Run full test suite, lint, type-check — confirm behavior preserved"
  activeForm: "Verifying refactoring safety"

TaskCreate:
  subject: "Phase 5: Final commit"
  description: "Create conventional commit with refactoring summary"
  activeForm: "Creating final commit"

# Set up strict sequential chain
TaskUpdate: { taskId: "2", addBlockedBy: ["1"] }
TaskUpdate: { taskId: "3", addBlockedBy: ["2"] }
TaskUpdate: { taskId: "4", addBlockedBy: ["3"] }
TaskUpdate: { taskId: "5", addBlockedBy: ["4"] }
TaskUpdate: { taskId: "6", addBlockedBy: ["5"] }

# Start first task
TaskUpdate: { taskId: "1", status: "in_progress" }
```

**Step 0.2: Discover Project Workflow**

Use Haiku-powered Explore agent for token-efficient discovery:

```
Use Task tool with Explore agent:
- prompt: "Discover the development workflow for this project:
    1. Read CLAUDE.md if it exists - extract testing and quality conventions
    2. Check for task runners: Makefile, justfile, package.json scripts, pyproject.toml scripts
    3. Identify the test command (e.g., make test, just test, npm test, pytest, bun test)
    4. Identify how to run a single test file or specific test
    5. Identify the lint command (e.g., make lint, npm run lint, ruff check)
    6. Identify the type-check command if applicable (e.g., pyright, tsc, mypy)
    7. Note any pre-commit hooks or quality gates
    8. Check for code coverage tooling (e.g., pytest --cov, nyc, c8)
    Return a structured summary of all available commands."
- subagent_type: "Explore"
- model: "haiku"  # Token-efficient for discovery
```

Store discovered commands for use in later phases.

**Step 0.3: Run Baseline Tests**

**CRITICAL**: Run the full test suite BEFORE making any changes. Record the results as the baseline. Every subsequent test run must match or exceed this baseline.

```bash
# Run full test suite and record results
[DISCOVERED_TEST_COMMAND]
```

If tests already fail before refactoring, document the pre-existing failures. These are not caused by the refactoring and should remain unchanged (same tests fail with same errors).

**Step 0.4: Complete Phase 0**

```
TaskUpdate: { taskId: "1", status: "completed" }
TaskList  # Check that Task 2 is now unblocked
```

### Phase 1: Scope Analysis

**Goal**: Understand the full impact of the refactoring before touching any code.

**Step 1.1: Start Phase 1**

```
TaskUpdate: { taskId: "2", status: "in_progress" }
```

**Step 1.2: Parallel Scope Analysis**

Spawn two Explore agents in parallel to map the refactoring scope:

```
Agent 1 - Dependency & Caller Analysis (Explore, Haiku):
  prompt: "Analyze dependencies and callers for the refactoring target:

    Refactoring target: [DESCRIBE TARGET CODE]

    1. Read the target code — understand its current structure and public API
    2. Find ALL callers and dependents using Grep:
       - Direct function/method calls
       - Import statements referencing the target
       - Type references (if applicable)
       - Configuration or dependency injection references
    3. Map the dependency graph:
       - What does the target depend on?
       - What depends on the target?
       - Are there circular dependencies?
    4. Identify the public API surface:
       - Which functions/methods/classes are called externally?
       - Which are internal-only (safe to change freely)?
    5. Note any dynamic references (string-based lookups, reflection, decorators)

    Return:
    - Complete caller list with file:line references
    - Dependency graph (what depends on what)
    - Public vs internal API surface
    - Risks: dynamic references, external consumers, serialization"
  subagent_type: "Explore"
  model: "haiku"

Agent 2 - Test Coverage Analysis (Explore, Haiku):
  prompt: "Analyze test coverage for the refactoring target:

    Refactoring target: [DESCRIBE TARGET CODE]

    1. Find ALL test files that test the target code:
       - Unit tests directly testing target functions/classes
       - Integration tests exercising the target indirectly
       - E2E tests that flow through the target
    2. For each test, note:
       - What specific behavior it verifies
       - Which code paths it exercises
       - Which inputs and edge cases it covers
    3. Identify GAPS in test coverage:
       - Functions/methods with no tests
       - Code branches not exercised (error paths, edge cases)
       - Public API methods without direct test coverage
    4. Check for test patterns:
       - Test fixtures and helpers available
       - Mocking patterns used in the project
       - Test naming conventions

    Return:
    - List of test files with what they cover
    - Coverage gaps requiring characterization tests
    - Test patterns and fixtures available for reuse
    - Risk areas: untested code paths that refactoring could break"
  subagent_type: "Explore"
  model: "haiku"
```

**Step 1.3: Synthesize Analysis**

After both agents complete, synthesize findings:
1. Identify which parts of the target are safe to refactor (well-tested, internal-only)
2. Identify which parts are risky (untested, public API, dynamic references)
3. Determine if characterization tests are needed (Phase 2)
4. Plan the order of incremental changes

**Step 1.4: Get Approval for Large Refactorings**

If the refactoring involves: changes to >5 files, modifications to public APIs, moving code between modules, or changes affecting external consumers, use `AskUserQuestion` to present the scope analysis and get approval before proceeding.

**Step 1.5: Complete Phase 1**

```
TaskUpdate: { taskId: "2", status: "completed" }
TaskList  # Check that Task 3 is now unblocked
```

### Phase 2: Characterization Tests

**Goal**: Ensure sufficient test coverage exists to detect any behavioral change from the refactoring.

**Step 2.1: Start Phase 2**

```
TaskUpdate: { taskId: "3", status: "in_progress" }
```

**Step 2.2: Assess Coverage Needs**

Based on Phase 1 coverage analysis, determine which characterization tests are needed:

- **Well-tested code** (>80% path coverage): Skip to Phase 3
- **Partially tested** (some gaps): Add targeted characterization tests for untested paths
- **Poorly tested** (major gaps): Add comprehensive characterization tests before proceeding

**Step 2.3: Write Characterization Tests**

For each coverage gap identified:

1. **Read the target code** to understand current behavior (including edge cases)
2. **Write tests that capture current behavior exactly**:
   - Test the function/method with representative inputs
   - Test edge cases (null, empty, boundary values)
   - Test error paths (invalid inputs, failure modes)
   - Test return values AND side effects
3. **Run the characterization tests** — they must ALL pass against the current (pre-refactoring) code
4. **Name tests clearly**: Use prefix `test_char_` or equivalent to distinguish characterization tests from behavioral tests

```
Example characterization test (Python):
  def test_char_calculate_total_with_discount():
      """Characterization: captures current discount calculation behavior."""
      result = calculate_total(items=[100, 200], discount=0.1)
      assert result == 270.0  # Current behavior: discount applied to sum

  def test_char_calculate_total_empty_items():
      """Characterization: captures current behavior with empty input."""
      result = calculate_total(items=[], discount=0.1)
      assert result == 0.0
```

**IMPORTANT**: Characterization tests document CURRENT behavior, not desired behavior. If the current code has a quirk, the test captures that quirk. The refactoring must preserve it.

**Step 2.4: Verify Characterization Tests**

Run the full test suite (including new characterization tests). All must pass.

```bash
[DISCOVERED_TEST_COMMAND]
```

**Step 2.5: Complete Phase 2**

```
TaskUpdate: { taskId: "3", status: "completed" }
TaskList  # Check that Task 4 is now unblocked
```

### Phase 3: Incremental Refactoring

**Goal**: Apply the refactoring in small, verified steps. Each step must pass all tests.

**Step 3.1: Start Phase 3**

```
TaskUpdate: { taskId: "4", status: "in_progress" }
```

**Step 3.2: Plan Incremental Steps**

Break the refactoring into the smallest possible independent steps. Each step should be:
- **Self-contained**: Makes sense on its own
- **Verifiable**: Tests can confirm behavior is preserved
- **Reversible**: Easy to revert if something breaks

Common refactoring step sequences (see `references/patterns.md` for details):

| Refactoring Type | Step Sequence |
|---|---|
| Extract method | 1. Create new method with copied code → 2. Test → 3. Replace original with call → 4. Test |
| Extract class | 1. Create class with methods → 2. Test → 3. Delegate from original → 4. Test → 5. Update callers → 6. Test |
| Rename | 1. Add new name alongside old → 2. Test → 3. Update callers → 4. Test → 5. Remove old name → 6. Test |
| Move function | 1. Copy to destination → 2. Test → 3. Re-export from source → 4. Update callers → 5. Test → 6. Remove source → 7. Test |
| Simplify conditional | 1. Extract condition to named variable/method → 2. Test → 3. Simplify logic → 4. Test |
| Remove duplication | 1. Identify shared pattern → 2. Extract shared code → 3. Test → 4. Replace first usage → 5. Test → 6. Replace next usage → 7. Test |

**Step 3.3: Execute Each Step**

For EACH incremental step:

1. **Make the change** — one small structural change using Edit tool
2. **Run tests immediately** — using discovered test command
   ```bash
   [DISCOVERED_TEST_COMMAND]
   ```
3. **If tests pass** — proceed to next step
4. **If tests fail** — STOP. Analyze the failure:
   - Is it a behavioral change? → Revert and find a smaller step
   - Is it a test that needs updating? → Only if the test was testing implementation details (not behavior)
   - Is it a pre-existing failure? → Compare with baseline from Phase 0

**CRITICAL**: Never skip the test run between steps. Never batch multiple steps before testing. The discipline of test-after-every-change is what makes refactoring safe.

**Step 3.4: Handle Complex Refactorings**

For refactorings spanning multiple files:

1. **Update the target first** — make the structural change in the primary file
2. **Update callers one at a time** — change each caller individually, testing after each
3. **Clean up** — remove old code, update imports, testing after each removal

For refactorings requiring temporary duplication:

1. **Create the new structure** alongside the old
2. **Test** — both old and new should work
3. **Migrate callers** one at a time to the new structure, testing after each
4. **Remove the old structure** once all callers are migrated
5. **Final test** — full suite

**Step 3.5: Complete Phase 3**

```
TaskUpdate: { taskId: "4", status: "completed" }
TaskList  # Check that Task 5 is now unblocked
```

### Phase 4: Final Verification

**Step 4.1: Start Phase 4**

```
TaskUpdate: { taskId: "5", status: "in_progress" }
```

**Step 4.2: Run All Quality Checks**

Run all quality checks using discovered commands from Phase 0.

**Quality Gates Checklist**:
- [ ] Full test suite passes (matches or exceeds Phase 0 baseline)
- [ ] Characterization tests pass (behavior preserved)
- [ ] No new linting errors introduced
- [ ] No new type errors (if typed language)
- [ ] Code is cleaner/simpler than before (the purpose of refactoring)
- [ ] No accidental behavior changes
- [ ] No debug code, commented-out code, or TODO comments left behind
- [ ] All callers updated (no dangling references)

**If any check fails**: Fix the issue before proceeding. Do not commit broken code. Keep task as `in_progress` until all gates pass.

**Step 4.3: Review the Diff**

Read the complete diff to verify only intentional changes exist:

```bash
git diff
```

Look for:
- Unintended behavioral changes
- Leftover debug statements
- Unnecessary whitespace or formatting changes
- Missing import updates
- Orphaned code that should have been removed

**Step 4.4: Complete Phase 4**

```
TaskUpdate: { taskId: "5", status: "completed" }
TaskList  # Check that Task 6 is now unblocked
```

### Phase 5: Final Commit

**Step 5.1: Start Phase 5**

```
TaskUpdate: { taskId: "6", status: "in_progress" }
```

**Step 5.2: Create Commit**

If `/cc-arsenal:git:commit` skill is available, use it. Otherwise, create a conventional commit manually:

```bash
git add [files modified]
git commit -m "refactor: [concise description of structural change]

- [What was restructured and why]
- [Key technique used: extract method, rename, simplify, etc.]
- [Impact: files changed, callers updated]

No behavioral changes."
```

**Commit message guidelines for refactoring:**
- Type: `refactor:` (always — this is a structural change, not a fix or feature)
- Subject: Describe WHAT was restructured
- Body: Explain WHY this improves the codebase
- Footer: Always include "No behavioral changes." to signal safety

**Step 5.3: Complete Phase 5 and Refactoring**

```
TaskUpdate: { taskId: "6", status: "completed" }
TaskList  # Show final status - all tasks should be completed
```

### Phase 6: Summary Report

Report to the user with:
- **Refactoring performed**: What structural changes were made
- **Technique used**: Extract method, rename, simplify, move, etc.
- **Files modified**: List with brief description of changes
- **Behavior verification**: Test results before and after (matching)
- **Characterization tests added**: List of new tests if any
- **Code quality improvements**: Metrics if available (reduced duplication, fewer lines, better naming)
- **Commit info**: Commit hash and message

## Additional Resources

For detailed refactoring patterns, step sequences, and safety practices, see:
- [references/patterns.md](references/patterns.md) - Refactoring catalog with step-by-step procedures

## Important Notes

- **Always run Phase 0 first**: Never assume which tools are available
- **Tests before and after every change**: This is non-negotiable
- **Characterization tests for untested code**: Never refactor code without test coverage
- **One step at a time**: Never combine multiple refactoring operations
- **No behavior changes**: Refactoring changes structure only — if tests break, revert
- **Ask when unsure**: Better to clarify scope than to over-refactor
- **Minimal scope**: Refactor only what was requested — resist the urge to "improve" adjacent code
- **Document the change**: Clear commit message explaining what and why