Claude Code Refactor Scope Becomes Too Broad

You asked for a small change, got a 5-file diff. Set a hard editable-file list in the prompt + use `FOLLOWUPS.md` to capture adjacent issues without fixing them.

You asked Claude Code to rename a function in billing.ts. The diff comes back with 12 files changed, 200 lines added, including a “consistency pass” across 4 unrelated modules, formatting changes you didn’t want, and a “minor improvement” to the import order in 8 files. The original task was 5 minutes; review is now 30.

Without an explicit boundary, Claude follows code paths it considers “related.” Imports lead to callers, callers lead to other modules, modules have their own inconsistencies, and suddenly your one-file task is a refactor. The fix: pin the editable file list, redirect adjacent issues to a FOLLOWUPS.md instead of fixing them, and reject scope creep at review.

Common causes

Ordered by hit rate, highest first.

1. Prompt didn’t name the file boundary

“Rename getUser to findUser” doesn’t say where. Claude renamed it everywhere — including legacy code paths you’ve been migrating away from, where the rename actually broke the migration.

How to spot it: Re-read your prompt. If it doesn’t list specific files, the boundary was implicit and Claude expanded.

2. Agent followed import/call chains into adjacent files

Claude renamed getUser in service.ts, then updated all 8 call sites across the codebase. Each call site is a legitimate touch — but the cumulative scope is 9x what you intended.

How to spot it: Diff includes a “core” file change + many small call-site updates. Each is necessary; together they’re scope expansion.

3. Agent applied a consistency pass unprompted

Claude noticed half the files use import type and half don’t. While renaming, it “harmonized” them across 6 files. None of that was asked for.

How to spot it: Diff has changes unrelated to the rename (import-order, formatting, naming). These are pure scope creep.

4. CLAUDE.md or prompt authorized “clean up while you’re at it”

# CLAUDE.md
- Improve code quality where you see opportunities
- Fix obvious issues during related work

Innocent-looking rules; standing authorizations for scope expansion.

How to spot it: grep -i "improve\|clean up\|while you're\|opportunit" CLAUDE.md. Each match is a creep authorization.

5. Refactor by nature touches many files

Some refactors genuinely span the codebase (rename a public API, migrate a state library). The scope is real, but the bundling into one PR is the problem — should have been split.

How to spot it: The diff is legitimately required. The bug is “one mega-PR” instead of “PR chain.”

6. Agent’s “test fix” cascaded

Tests failed after the core change. Claude “fixed” them by updating expectations, mocks, and fixtures across many test files. Some legit (matching the new signature), some are masking failures.

How to spot it: Many test file changes accompany the rename. Audit which ones are signature updates vs which are silently weakening assertions.

Shortest path to fix

Ordered by ROI. Steps 1 and 2 fence the agent at the prompt layer.

Step 1: Hard editable-file list in the prompt

Editable files (DO NOT touch anything else):
- src/services/user.ts
- src/services/user.test.ts

For any other file:
- If the change requires touching it, STOP and ask before editing.
- Do NOT make consistency / formatting / cleanup changes anywhere.

The “stop and ask” line lets Claude flag genuine cascades without unilaterally expanding.

Step 2: Redirect adjacent issues to FOLLOWUPS.md

If you spot issues in files outside the editable list:
- Do NOT fix them.
- Add a line to `FOLLOWUPS.md` describing the issue and its file:line.
- These become future tasks, not this PR.

Now Claude can be “helpful” without expanding scope. Every helpful spot becomes a documented future task.

Step 3: Audit prompt + CLAUDE.md for creep authorizations

grep -in "improve\|clean up\|while you're there\|opportunistically" \
  CLAUDE.md src/**/CLAUDE.md prompts/*.md

Replace each with a tighter rule:

- Do NOT make changes outside the immediate task scope.
- Adjacent issues go in FOLLOWUPS.md, not into the current PR.

Step 4: For received over-broad PRs, revert outside-scope files

Don’t merge as-is, don’t reject entirely — revert the out-of-scope files:

git diff --stat HEAD
# Identify files outside the intended scope
git checkout HEAD -- <out-of-scope-files>

# Re-run tests, ensure the core change is still good
pnpm test

Keep what was asked for, drop what wasn’t. The PR shrinks to the intended scope.

Step 5: For genuine multi-file refactors, split into a PR chain

If the rename truly requires updating 8 callers, ship it staged:

PR 1: Add `findUser` alongside `getUser` (no caller changes; both exist).
PR 2: Migrate callers in `src/services/billing/` (3 callers).
PR 3: Migrate callers in `src/api/` (5 callers).
PR 4: Remove `getUser`.

Each PR is reviewable in 5 minutes. The diff total is the same; the reviewability is 10x.

Step 6: Verify tests weren’t weakened

For each test file in the diff:

# Diff just the test file
git diff -- src/services/user.test.ts

# Look for: removed expect/assert lines, added .skip, broadened type checks
git diff -- src/services/user.test.ts | grep -E '^-.*expect|^-.*assert|^\+.*skip'

If assertions got removed or tests skipped, the “test fix” was a regression hidden as a fix. Restore the original tests and re-prompt to fix the production code instead.

Prevention

  • Every code prompt has an explicit editable-file list with a “stop and ask” rule for anything outside
  • Maintain a FOLLOWUPS.md so Claude can surface adjacent issues without acting on them
  • Audit CLAUDE.md for “improve while you’re there” authorizations; remove them
  • For genuine multi-file refactors, split into a PR chain instead of one mega-PR
  • Spot-check test diffs — assertion removal or skip additions are creep disguised as fixes
  • Review against the original scope, not the final diff — the diff may look reasonable on its own

Tags: #Troubleshooting #Claude Code #Debug #Scope creep