Paths Subjects Questions Quizzes Pricing Search
Intermediate Open Free

A CLAUDE.md That Survived a Refactor Badly

Six months ago, a team wrote this into their project's CLAUDE.md:

## Authentication
All authentication logic lives in `middleware/auth.py`. Token
validation happens there before any route handler runs. If you need
to change how tokens are validated, that's the only file to touch.

Since then, the team migrated from a monolithic middleware file to a per-route dependency-injection pattern: token validation now happens in auth/dependencies.py, injected individually into each FastAPI route via Depends(get_current_user). Nobody updated the CLAUDE.md.

  1. Walk through what happens when a new contributor asks Claude Code to "add rate limiting to the token validation step," with this stale instruction still in place.
  2. Explain why this failure mode is more dangerous than simply having no instruction about authentication at all.
  3. Propose a process (not just "update the file") that would make this kind of staleness less likely to reach this point undetected.
Solution

1. What happens with the stale instruction in place:

Claude reads "all authentication logic lives in middleware/auth.py" as a confident, specific claim about the codebase — exactly the kind of concrete, verifiable-sounding instruction that's supposed to be trustworthy. It has no independent signal telling it this claim is six months out of date. So it very plausibly opens middleware/auth.py (which may still exist, perhaps now empty, deprecated, or repurposed), tries to add rate-limiting logic there, and either: adds dead code that never executes because nothing calls that file's validation path anymore, or gets confused when the file doesn't contain what the instruction describes and has to spend effort reverse-engineering the real structure anyway — effort the instruction was supposed to save. In the worst case, it partially succeeds in a way that looks plausible (rate-limiting code that compiles and even runs) but never actually gates the real per-route validation in auth/dependencies.py, shipping a security feature that silently does nothing.

2. Why this is worse than no instruction at all:

With no instruction, Claude would default to actually investigating — grepping for Depends(get_current_user), tracing how routes wire up auth, and finding the real, current structure. It would take a bit longer, but would very likely land on the truth. A confident, specific, wrong instruction actively short-circuits that investigation: it gives Claude a plausible, verifiable-looking answer that happens to be false, and specificity is exactly what makes an instruction more likely to be trusted and acted on without independent verification. Stale-but-precise information is more dangerous than absent information because it looks like the trustworthy kind of entry CLAUDE.md is supposed to contain, and preempts the very investigation that would have surfaced the real (correct) location.

3. A process to catch this before it reaches six months stale:

"Just update the file" doesn't scale because nobody is naturally prompted to remember CLAUDE.md exists during a refactor unless it's made part of the refactor's definition of done. A few concrete, durable practices:

  • Treat CLAUDE.md like code for review purposes: any PR that moves, renames, or restructures something CLAUDE.md references by path should be expected to grep for that path (or filename) across CLAUDE.md and .claude/rules/ as part of the PR, the same way you'd grep for other callers before removing an export. This can even be a lightweight CI check — a script that extracts backticked paths mentioned in CLAUDE.md and fails the build if any no longer exist on disk (this specific case, a path rename, is mechanically detectable even without full semantic understanding).
  • Prefer instructions that reference stable concepts with the path as a secondary detail, and periodically re-verify rather than assuming permanence — e.g. phrase it as "auth logic is centralized in one place (check for Depends(get_current_user) usage or an equivalent) — as of [date/version], that's auth/dependencies.py" rather than a bare unconditional path claim, so a reader (human or agent) is nudged to sanity-check rather than trust blindly forever.
  • Periodic audit, independent of any specific refactor: treat a stale-CLAUDE.md check as part of a recurring housekeeping pass (e.g., alongside dependency updates), since some refactors won't touch the exact grep-able strings CLAUDE.md uses and won't be caught by tooling.

The underlying point is that CLAUDE.md rot is a silent failure mode — it doesn't break a build or fail a test — so the fix has to be a process that surfaces it despite that silence, not a one-time cleanup.

Share this question

← Back to CLAUDE.md and Context Configuration practice

We use cookies for product analytics to improve OmniAtlas. See our Privacy Policy.