Before I let Claude change a function, I ask what reaches it
Part of the Change Impact guide. Start with Code Change Blast Radius: A Safer Way to Code with AI
checkAdminOrOwner is a small permission check. Give it a role and it tells you whether that role is an owner or an administrator. Open its definition and there is very little to read.
Changing it is another matter.
In the cal.diy revision I used for this experiment, that check appears in shared application code, React components and API services. A signature change starts in one file, then follows imports into packages you would never discover by reading the definition alone.
This is the question I want answered before Claude starts editing: which parts of the application depend on this function, and which of those relationships have we actually checked?
I build Pharaoh, which gives AI agents a structural map of a repository over MCP. I used it alongside native code search for this investigation. Both workflows could find the relevant names; the interesting difference in these runs was the work needed to assemble the answer.
Start with a change, not an overview
The example comes from Pharaoh-so/cal.diy at 54343aa6. The function definition accepts a membership role and acts as a TypeScript type guard.
A general request to explain this repository would leave Claude with an enormous amount of ground to cover. I asked a narrower question:
I'm going to change the signature of checkAdminOrOwner. List every
function that calls it, directly or indirectly (up to 3 hops), and
every HTTP endpoint that could be affected. Answer concisely.
The depth matters. A direct reference identifies a place to inspect, while an indirect path explains how an application feature reaches it. I want the answer bounded enough to verify, with the boundary visible rather than buried under a confident claim about the whole system.
One path out of the utility file
Here is one chain I checked against the pinned source. The arrows mean "calls":
listUserInstalledConferencingApps
-> getUserConferencingApps
-> getConnectedApps
-> checkAdminOrOwner
getConnectedApps uses the role check while building connected-app information. The API's getUserConferencingApps calls that helper through a shared package. The conferencing controller calls the service.
That chain gives a reviewer somewhere useful to go. Open the implementation, check the type assumptions, then examine the controller behavior. A dependency path tells you what may need attention; whether a particular edit breaks it still depends on the edit.
The role check also narrows a type. Changing its arguments while preserving that narrowing is a different change from returning a plain boolean, even if the new function looks equivalent at a glance.
What the saved runs measured
On October 16, 2026, I ran this prompt three times in each configuration. The saved sessions record the same model ID, claude-opus-5-5, and two conditions: without Pharaoh and with Pharaoh. These are historical measurements of those workflows.
| Run | Without Pharaoh | With Pharaoh | Without: recorded API cost (USD) | With: recorded API cost (USD) |
|---|---|---|---|---|
| 1 | 34.717 s | 16.292 s | 0.20724 | 0.11235 |
| 2 | 33.083 s | 15.760 s | 0.16826 | 0.06683 |
| 3 | 28.276 s | 18.726 s | 0.14633 | 0.05227 |
| Mean | 32.03 s | 16.93 s | 0.17395 | 0.07715 |
The native sessions made 11 to 14 tool calls. The Pharaoh sessions made two each. For this question, the latter workflow reached an answer in about half the time, at about 56% less recorded API cost.
Those costs come from the saved session records, including the provider's accounting for those sessions. They exclude Pharaoh subscription charges and map construction. On a flat-rate Claude subscription, using fewer tokens does not mean your bill falls by that percentage.
The result also depends on the workflow around the tools. The saved result does not preserve every invocation flag or plugin version. These figures compare the recorded conditions; they cannot isolate how much of the difference came from the graph, the instructions or caching.
The grading error I found while writing this
The original grader marked some native answers as missing getUserConferencingApps or getEventTypesAppIntegration. Those answers included ConferencingAtomsService.getUserConferencingApps and EventTypesAtomService.getEventTypesAppIntegration.
The name was there.
Our matching rule rejected a method name when a dot came immediately before it. That is a grading bug, and it matters because it made the native answers look less complete than they were. After accounting for qualified names, all six answers mention all eleven expected items for this question.
Mentioning the expected names still does not establish that every statement is correct. It does not check whether a path has the right direction, whether the answer adds unsupported callers, or whether the proposed edit would work. I have checked the source chain above; I am not presenting an accuracy percentage for the complete answers.
This experiment supports a narrower claim: structural context reduced the investigation time and recorded API cost for this prompt. It does not support a claim that native Claude missed those two methods.
How I use the result before editing
I ask for production callers and detected entry points first. Then I open the affected source, confirm the assumptions around the proposed change and add tests at the boundary that matters.
Pharaoh's interactive map describes the last completed map of the default branch. It does not see my uncommitted edits or an unmerged feature branch. I check that the source revision and map agree before treating a returned path as evidence about the code in front of me.
I also search separately for tests, configuration and string references. Blast-radius results exclude test-file callers, static analysis can miss runtime dispatch, and a three-hop query cannot describe an arbitrarily deep chain. A short answer is useful when it makes those limits clear.
I use the code change blast radius workflow to decide what to verify, then open the source.
The saved suite has counterexamples too. On a module overview in the same dataset, the Pharaoh workflow averaged 22.91 seconds against 15.12 seconds natively. For a rename plan, it averaged 16.95 seconds against 16.01. I still use ordinary search when the question is an exact name or a small patch. The code impact analysis guide covers the broader investigation.
Try the investigation yourself
Check out the pinned cal.diy revision in a separate directory and run the prompt above in fresh sessions. For the Pharaoh condition, use a repository whose mapped default branch matches that revision, then ask your client to call get_blast_radius for checkAdminOrOwner with a depth of three.
Keep the final answers and check their paths against source. Record the model, tool configuration and any differences in the files available to each session. A time saving is only useful if the answer gives you enough verified information to make the change.
The change-impact docs cover this workflow. To try it on your own repository, connect Pharaoh. The free plan keeps one repository live per workspace. Pick a function you were already going to change and follow one returned path all the way back to the feature it serves.