Most code review looks at the lines that changed. A function gains a new direct call in the file being edited, reviewers see it. The problem case is indirect: a helper deep in another module starts calling your target because a default argument, a wrapper, a dispatch table or a registry entry was rewritten. The diff for your function is empty, the tests you wrote for it still pass, and yet someone has taken a new dependency on behavior you thought was frozen.
This is not a niche worry in static analysis. A study of 13 static analysis tools against dynamic analysis on 1000 Android apps found the tools failed to capture 61% of dynamically executed methods on average, and that higher precision in call graph construction went hand in hand with higher unsoundness, because frameworks invoke methods implicitly [1]. You cannot assume any tool sees every edge, so the useful posture is to freeze what your chosen extraction does see and force a human to look when it changes.
A recorded caller list is the smallest version of that idea. It is not a runtime assertion about who actually calls your function; it is a contract about who may call it as far as static analysis can tell. The guarantee is narrow and honest: if a new call site appears anywhere the extractor scans, the test fails and names the file and symbol.
There is a second reason to prefer a checked-in list over a one-shot visualization. Call graphs and code graphs are dynamic artifacts in the tools that produce them; Graph-Code's demo, for instance, parses a repository into a graph and queries it in Cypher to answer questions like maximum call chain length [2]. A picture helps a human once. A sorted text file in the repository is a regression baseline that runs on every commit and costs milliseconds.



