repowiserepowise
Features
Code health
A defect-validated 1 to 10 score per file. Zero LLM.
Agent provenance
See how much of your code AI wrote, and whether it is healthy.
AI context (MCP)
Ten MCP tools that give your agent real codebase context.
Change risk
A 0 to 10 defect-risk score for any commit or PR.
Security
Reachability-aware CVE triage on your dependency graph.
Auto wiki
A documented wiki of your codebase that rebuilds itself.
Git intelligence
Hotspots, ownership, hidden coupling, and bus factor.
Architecture (C4)
C4 system context, containers, and components.
Decisions
Architectural decisions mined from eight sources.
Solutions
developers
Give Claude Code, Cursor, and any MCP client a queryable model of your repo.
teams
One shared index, one credit pool, one org install. The whole team on the same brain.
team leads
Flag the risky PRs, the hotspots, and the hidden coupling, on every pull request.
engineering leaders
See how much of your code AI wrote, whether it is healthy, and who owns it.
security
CVE triage that knows whether you actually call the vulnerable code.
enterprise
Self-hosted, air-gapped, and commercially licensed for the whole org.
Book a demo →
Guides
Code healthAI context & MCPGit intelligenceChange riskArchitectureAuto-wikiDecisions & ADRsAgent provenanceSecurityAll guides →
Compare
vs CodeScenevs DeepWikivs Sourcegraphvs Cursorvs GitClearvs SonarQubeAll comparisons →
PricingExploreBlogDocs
Star—Sign in
Start free
Blog/Use Cases

47 dependents, 23 hotspots: a React refactor without folklore

repowise team·May 8, 2026·11 min read

large codebase refactor

47 dependents, 23 hotspots: a React refactor without folklore
On this page
  • 47 dependents meant this React refactor was a coordination problem, not a code-style cleanup
  • The first pass: rank 23 hotspots before opening a single JSX file
  • What the graph showed that grep could not: callers, callees, and hidden fan-out
  • The 12 files that kept breaking reviews had one thing in common: nobody could answer who owned them
  • Co-change history separated real coupling from habit
  • What would have gone wrong with grep and a PR checklist
  • FAQ
  • How do you choose the first files in a large codebase refactor?
  • How do dependency graphs help with a React refactor?
  • What is the difference between hotspot analysis and code ownership analysis?
  • Why is grep not enough for planning a large React refactor?
  • How did the team know the chosen order reduced risk?

Forty-seven dependents is where a React refactor stops being a taste argument and starts being a large codebase refactor with real blast radius. The team in this case knew the change set was risky before they wrote a line of JSX, which is why the question was not “what should the architecture look like?” but “what do we touch first without breaking half the app?”

The answer was not folklore. It was a ranked list, built from dependency graphs, git history, and ownership signals, and it produced 23 hotspots before the first edit landed. That sequencing mattered more than the eventual refactor shape, because with 47 dependents the wrong first move would have turned the whole thing into a review swamp.

47 dependents meant this React refactor was a coordination problem, not a code-style cleanup

The module at the center of the change was not glamorous. It was a shared React surface that sat under a surprising amount of product code, and the dependency graph said 47 downstream dependents reached it directly or indirectly. That number changed the conversation immediately.

Nobody on the team could responsibly start by arguing about the ideal end state. Not because architecture questions were irrelevant, but because the blast radius was already known. A broad rewrite would have forced every reviewer to reason about hidden coupling at once, which is how refactors die: not from one bad file, but from 40 people holding different mental models of the same code.

So they treated the work like risk management. First identify what was actually central. Then rank the places where a mistake would hurt the most. Only after that did they decide which React files deserved attention.

BLAST RADIUS MAPBLAST RADIUS MAP

That is the point where a large codebase refactor becomes legible. You stop asking whether the code “should” be cleaner, and start asking which files control behavior, which ones create coordination cost, and which ones can wait.

A useful internal check here is the same one you would use to audit a codebase you've never seen before: find the entry points, map the fan-out, then inspect where ownership and churn overlap. The surprise is usually not that the code is messy. It is that the mess is uneven.

The first pass: rank 23 hotspots before opening a single JSX file

The team’s first pass used a dependency graph and git history to identify 23 hotspots. Not 23 files they happened to dislike. 23 files that scored high on a mix of fan-out, churn, ownership gaps, and review pain.

The ranking logic was blunt on purpose:

  1. Start with the dependency graph.
  2. Pull the files with the largest blast radius.
  3. Overlay git history for churn and co-change.
  4. Check ownership signal and reviewer history.
  5. Keep only the files where multiple signals agreed.

That last step mattered. A file could be central but stable. Another could be noisy but isolated. They did not want to confuse “annoying” with “urgent.”

hotspotdependentsownership %recent churnco-change partnerwhy it was ranked early
src/components/SharedShell.tsx4718%highsrc/routes/AppRouter.tsxcentral fan-out plus weak ownership
src/hooks/useFeatureFlags.ts3124%highsrc/components/Nav.tsxchanged with routing and auth work
src/utils/formatters.ts2812%mediumsrc/components/Table.tsxbroad utility reuse, review churn
src/components/FilterBar.tsx1941%highsrc/pages/Search.tsxrepeated breakage in adjacent UI
src/state/queryClient.ts179%highsrc/api/client.tsshared behavior, low bus factor

Scroll the table sideways to see every column.

The key move was choosing the first 23 hotspots before touching JSX. That sounds obvious until you watch teams do the opposite: open the most visible component, make a local fix, then discover the real dependency knot three PRs later.

We got one thing wrong initially. The first ranking pass over-weighted churn. A file with a lot of commits is not always a dangerous file. Sometimes it is just a file people use as a dumping ground. Once the team added ownership percentage and co-change history, several “obvious” candidates fell out of the top tier.

HOTSPOT RANKING SHEETHOTSPOT RANKING SHEET

The practical effect was simple: they were no longer debating architecture in the abstract. They were deciding which files had earned the right to be touched first.

What the graph showed that grep could not: callers, callees, and hidden fan-out

Grep is good at finding symbols. It is bad at telling you what those symbols are doing to the rest of the app.

The team used a tree-sitter graph to get syntax-aware structure across React files, then walked callers and callees to understand fan-out from entry points. That exposed relationships grep would never have made obvious: a shared component used by multiple routes, a utility imported by both the UI and a background job, a hook that looked local but sat under a cross-cutting state layer.

A small example made this concrete.

noderoledownstream impact
SharedShell.tsxentry pointroute layout, auth gate, nav, telemetry wrapper
useFeatureFlags.tsshared hookconditional rendering across 11 components
formatters.tsutilitytables, detail views, export paths
FilterBar.tsxUI controlsearch, analytics, saved views

Scroll the table sideways to see every column.

The worked example that changed the order of attack was SharedShell.tsx. On the surface it looked like a layout component. In the graph, it was an entry point that fed navigation, auth state, and telemetry into multiple branches. That meant a small change there could destabilize behavior in places that had never been in the same PR before.

Once they saw that, they stopped treating the refactor as “replace one component.” They treated it as “reduce the number of ways the component can surprise us.”

That is where dependency graphs earn their keep in a large codebase refactor. They do not tell you what to build. They tell you what not to break first.

If you want the mental model to scale, this is close to what indexing docs, graphs, and ownership at scale looks like in practice: a graph is only useful when it is paired with the other signals that explain why a node matters.

The 12 files that kept breaking reviews had one thing in common: nobody could answer who owned them

The most useful ownership signal was not “who committed here last.” It was whether anyone could confidently say who should review changes here.

Twelve files kept failing that test. They were not always the most complex files, but they had low ownership percentage, fragmented reviewer history, and a bus factor that was too close to one. In other words, they were shared in the worst way: everyone depended on them, and nobody felt responsible for them.

That slowed the refactor more than the code itself did. Reviewers hesitated. Authors over-explained. Small changes got routed through too many people because there was no obvious owner to bless the direction.

file groupownership %review churnbus factorimpact on refactor
shared layout14%high1repeated review loops
feature flag layer19%high2ambiguous contract changes
formatting utilities11%medium1slow sign-off on trivial edits
route shell8%high1no clear decision maker

Scroll the table sideways to see every column.

The lesson was not “add more owners” in the abstract. It was that weak ownership is a sequencing constraint. If a file has no clear reviewer, it should move earlier only if its blast radius justifies the coordination cost. Otherwise it becomes a bottleneck that masks the rest of the plan.

That is also why codebase visibility for engineering managers is not a luxury feature. When the team can see ownership percentage, review churn, and dependents in one place, the refactor plan stops being a social negotiation.

Co-change history separated real coupling from habit

Git history was the filter that kept the graph honest.

The team looked at co-change pairs over the same history window used for churn. That surfaced which files truly moved together during past work. It also exposed a common trap: broad cleanup PRs make unrelated files look coupled when they are only adjacent in habit.

One pair mattered:

  • SharedShell.tsx and AppRouter.tsx had been changed together across several feature launches and auth fixes.
  • The significant commit messages were consistent: route gating, shell behavior, session handling.

That was real coupling. If one changed, the other often needed a corresponding change.

One pair did not:

  • formatters.ts and docs/README.md showed up together in a few historical commits.
  • The commit messages made it clear those were cleanup passes and documentation sweeps, not evidence of runtime dependency.

That distinction mattered because co-change history is easy to misuse. If you treat every repeated pair as a dependency, you end up prioritizing old PR habits instead of system behavior.

pairco-change historysignificant commit messagesinterpretation
SharedShell.tsx + AppRouter.tsxfrequentauth, routing, shellreal coupling
FilterBar.tsx + Search.tsxmoderatesearch UX, filterslikely coupling
formatters.ts + README.mdoccasionalcleanup, docshabit, not coupling
queryClient.ts + api/client.tsfrequentrequest flow, retriesreal coupling

Scroll the table sideways to see every column.

The before/after decision note that changed the plan was almost boring:

  • Before graph + git signals: FilterBar.tsx looked like an early candidate because it was visible and flaky.
  • After graph + git signals: it moved down, because its dependents were modest and its churn mostly tracked a neighboring search flow.
  • Meanwhile SharedShell.tsx moved up, because it had the largest blast radius, weak ownership, and repeated co-change with the routing layer.

That is the kind of evidence that persuades a skeptical staff engineer. Not “this feels central,” but “this file has the highest combination of dependents, churn, and coordination risk.”

If you want a broader frame for why this matters, codebase visibility for engineering managers is the right mental model: the point is not just seeing the code, but seeing which decisions are expensive to reverse.

What would have gone wrong with grep and a PR checklist

A grep-first workflow would have found symbols. It would not have found blast radius.

A PR checklist would have asked whether tests passed, whether types compiled, and whether docs were updated. Useful questions, all of them. None of them would have told the team which 23 hotspots to touch first, or which files were risky because nobody owned them, or which modules had hidden fan-out through entry points.

The misses would have been specific:

  • missed dependencies behind shared React entry points
  • missed owners on files with repeated review churn
  • missed coupling that only showed up in co-change history
  • missed the fact that some “obvious” files were noisy but not central
  • missed the reason the chosen order reduced risk: it started where blast radius and coordination cost were both highest

That last part is the difference between a refactor plan and a cleanup wishlist. The team did not start with the prettiest files. They started with the files that could most easily derail the rest of the work.

That is why the 47 dependents mattered so much. It forced the team to stop pretending the refactor was about code style and start treating it as a sequencing problem with measurable risk. Once they had the graph, the history, and the ownership signal, the first 23 hotspots were not a debate. They were the only sane place to begin.

FAQ

How do you choose the first files in a large codebase refactor?

Start with the files that have the highest blast radius, then rank them by ownership gaps, churn, and co-change history. The first files should be the ones where a mistake would hurt the most and where the evidence for prioritization is strongest.

How do dependency graphs help with a React refactor?

They show callers, callees, and fan-out around shared components, hooks, and utilities. In React, that often reveals that a file you thought was local is actually an entry point for many downstream dependents.

What is the difference between hotspot analysis and code ownership analysis?

Hotspot analysis asks where change risk is concentrated, usually by combining churn with complexity or dependents. Code ownership analysis asks who can confidently review or maintain the file, which is why ownership gaps can slow a refactor even when the code is not especially complex.

Why is grep not enough for planning a large React refactor?

Grep finds symbols, not system shape. It cannot tell you which files have the largest blast radius, which ones are weakly owned, or which ones are coupled through past changes rather than direct imports.

How did the team know the chosen order reduced risk?

Because the first 23 hotspots were selected before editing JSX, using dependency graph data, git history, and ownership signals together. That let them start with the files that were most central and most coordination-heavy, instead of discovering those risks mid-refactor.

Run this on your own codebase

repowise indexes a repo and generates the docs, the dependency graph and the MCP tools an agent reads from. Free for two public repos.

Index your repo freeBrowse the guides

On this page

  • 47 dependents meant this React refactor was a coordination problem, not a code-style cleanup
  • The first pass: rank 23 hotspots before opening a single JSX file
  • What the graph showed that grep could not: callers, callees, and hidden fan-out
  • The 12 files that kept breaking reviews had one thing in common: nobody could answer who owned them
  • Co-change history separated real coupling from habit
  • What would have gone wrong with grep and a PR checklist
  • FAQ
  • How do you choose the first files in a large codebase refactor?
  • How do dependency graphs help with a React refactor?
  • What is the difference between hotspot analysis and code ownership analysis?
  • Why is grep not enough for planning a large React refactor?
  • How did the team know the chosen order reduced risk?

Related posts

use-cases10 min read

Case Study: We Build repowise With repowise

repowise is developed against an index of itself: every pull request is gated by the same risk and health checks we ship. The setup, measurements, and limits.

2026-07-04Read →
use-cases11 min read

Onboard Engineers Faster on Any Codebase

Onboard engineers faster on any codebase with an auto-generated wiki and 10 MCP tools that recover the why behind legacy code. See the 30-day approach inside.

2026-06-26Read →
use-cases14 min read

How to Read a Codebase You Didn't Write

Read an unfamiliar codebase fast by treating the first pass like an incident review, not a refactor: four lenses, an hourly workflow, and a repeatable audit memo.

2026-05-20Read →

Index your repo free

Index your repo freeRead the docs
repowiserepowise

Codebase intelligence for AI agents. Open source under AGPL-3.0, hosted SaaS for teams.

Features
  • Code health
  • Agent provenance
  • AI context (MCP)
  • Change risk
  • Security
  • Auto wiki
  • Git intelligence
  • Architecture (C4)
  • Decisions
Solutions
  • For developers
  • For teams
  • For team leads
  • For engineering leaders
  • For security
  • For enterprise
Compare
  • vs CodeScene
  • vs DeepWiki
  • vs Sourcegraph
  • vs Cursor
  • vs GitClear
  • vs SonarQube
  • vs Snyk Code
  • vs Codacy
  • vs Code Climate / qlty
  • vs Qodo
  • vs Greptile
  • vs Swimm
  • vs CodeRabbit
  • vs CodeGraph
  • vs Graphify
  • vs Serena
  • vs code-review-graph
  • All comparisons
Guides
  • Code health
  • AI context & MCP
  • Git intelligence
  • Change risk
  • Architecture
  • Auto-wiki
  • Decisions & ADRs
  • Agent provenance
  • Security
  • All guides
Product
  • Pricing
  • PR Bot
  • Browse indexed repos
  • Health leaderboard
  • Book a demo
Resources
  • GitHub
  • Docs
  • Benchmarks
  • Blog
  • Discord
About
  • Founder
  • Architecture
  • Contact
Legal
  • Privacy
  • Terms
  • Security
All systems normal
© 2026 repowise. AGPL-3.0.hello@repowise.dev
Featured on Aura++