I built a tool that draws architecture diagrams from a repository, where every edge cites the file, line and commit it came from.
Then I ran it against thirteen repositories it had never seen, and every single one of them found something wrong with it.
There were thirteen.
These are the ones worth writing down.
The list says nothing about those codebases.
It says something about testing: a tool that reads other people's repositories has to be tested against other people's repositories, and there is no substitute.
The rule the tool works by Nothing is drawn that cannot be cited.
Every edge in the output carries the file, the line and the commit that justifies it — click an arrow, see the import statement.
If a reference cannot be resolved to something in the repository, it is not quietly dropped and it is not guessed at.
It is reported as a gap.
That second half is what made these bugs findable.
A tool that silently drops what it cannot resolve looks perfect and is useless.
A tool that reports gaps by name and count tells you, loudly, every time it is confused.
Java: a library sharing your package prefix is not you Guava declares .
Truth is a separate library, and it lives in .
My resolver matched on package prefixes, so Truth looked like Guava's own code, and every reference to it became a gap against a package Guava does not contain. 834 false gaps — 28% of the repository.
The fix is to require the next path segment to look like a type before peeling, because peels to a package and peels to a class, and those are different shapes.
Java: a file importing its own nested type Java requires the import for a nested enum constant even inside the same file.
Treating that as a dependency has you drawing an arrow from a file to itself.
It accounted for all 137 remaining gaps on Spring Boot and all 34 on Guava.
Java: static imports point one segment too deep names a member, not a package.
Reading it as a package produced 106 facts asserting that gson depends on a published copy of gson.
Nested types left another 84 with the same shape.
Never a dependency on a published copy of yourself.
I would end up writing that sentence five times, once per language.
Go: the walker refused to look at directories named build I skipped directories called the way everyone skips .
Moby has four Go packages named .
All 53 imports of them were reported as gaps against directories the walker had declined to open.
Rust: a crate does not necessarily live in src/ This was the big one.
Deno's manifest says .
I had hardcoded . 3,896 gaps — 27% of every fact in the repository.
What makes this one worth writing down: the totals looked fine.
Deno is a large repository and thousands of unresolved references still left a plausible-looking number of resolved ones.
I found it by opening the diagram and seeing a shape that was wrong, not by reading a count. ** Rust: integration tests are their own crates** Cargo compiles every direct child of as its own crate.
So inside an integration test does not mean the library's — it means the one sitting beside the test.
Rust: use super::* in an inline test module The commonest shape in Rust, and I resolved it to the crate root.
That is a wrong answer rather than a gap, which is strictly worse: gaps get counted and reported, wrong answers just quietly inflate the fact count of every Rust repository that has tests.
Kotlin: fun interface is ordinary Kotlin, and was missing from my list of declaration modifiers.
So , and LeakCanary's were not in the type index at all.
Kotlin: a SCREAMING_SNAKE constant is not a type , , — 31 more of OkHttp's gaps.
Kotlin and Java are one namespace A Kotlin file importing a Java type from the same repository is a real edge.
An index built from one file extension cannot see the other, so 112 real edges in Spring Boot were reported as missing.
The declaration index now spans both.
The four I would have missed Here is the part I would rather not write.
I had verified the Rust adapter against Next.js and