DEV Community

Ashish Patnaik
Ashish Patnaik

Posted on

Tangle: A Code Coupling Graph That Finds the Files Your PR Forgot

Tangle builds a code coupling graph from your git history instead of your imports, then uses it to find the files your pull request forgot, explain why they couple, and prove what it ruled out. Built on FalkorDB for the Graph Hacks competition.

You open a pull request with 40 files. Tests pass. CI is green. Three days later a bug report arrives for a file you never touched.

Nobody caught it because nothing in the repo tests that relationship. The two files break together in production. Nobody wrote that down anywhere git kept.

Your agent read every file in the diff and had no idea. It cannot know what it does not know.

๐Ÿš€ Live Demo ยท ๐ŸŽฅ YouTube Video Walkthrough ยท ๐Ÿ™ GitHub Repository

Where Tangle wins

Three methods got the same task: name the file the developer forgot, budget of 12 names each, 405 historical commits in next.js, 5,834 held-out files. Every method answered using only commits older than the one being scored.

method                        precision   recall      F1     MRR
Tangle (change coupling)           1.2%     9.6%   0.021   0.514
baseline: import graph only        0.9%     6.6%   0.016   0.413
baseline: plain co-change count    1.3%    15.9%   0.025   0.465

On the 2,325 cases where the forgotten file already had history:

method                        precision   recall      F1     MRR
Tangle (change coupling)           2.2%    19.7%   0.039   0.514
baseline: import graph only        1.6%    10.8%   0.028   0.413
baseline: plain co-change count    2.7%    32.0%   0.050   0.465
Enter fullscreen mode Exit fullscreen mode

Tangle used to rank best here, at an MRR of 0.694. Removing the confidence gate took that to 0.514, and I left the number where it landed. The looser filter returns more weak candidates ahead of the right one. That cost is real and it is written down in the README rather than rounded away.

Tangle beats the structural index on every measure. The import graph is what your IDE and your compiler already see. Tangle beats it on precision (2.2% vs 1.6%), recall (19.7% vs 10.8%), F1, and MRR.

Where it wins by a lot: the 99.7% nobody else sees

I ingested 35,771 commits from vercel/next.js. 143,113 of 143,488 coupling edges have no static import path. That is 99.7% of everything the graph knows about how the codebase moves, and every structural tool on your machine scores it zero by construction.

Take lerna.json and packages/next/package.json. They landed in the same commit 3,676 times. Neither imports the other. No compiler in that repo will ever warn you about changing one and missing the other.

Restrict the benchmark to that population, the files the import graph cannot reach at all:

Tangle                          1.6% precision   6.4% recall
baseline: import graph only          by construction: 0
Enter fullscreen mode Exit fullscreen mode

Where no structural index can go at all

Every tool I compared against reads your source. Tangle reads your history.

It tells you why. I recovered a ticket for 142,340 of 143,488 couplings (99.2%). Run tangle why on any pair and you get the PR, the author, the date, and how much of the coupling that ticket accounts for. Across the benchmark window, 64.4% of forgotten files had a ticket naming their coupling. A structural index has nothing to draw on here, because the reason for a coupling lives in a commit message, not in an import statement.

It checks itself. npm run verify recomputes every coupling from the commit log with no graph and no caching, then diffs it against FalkorDB. It caught a real bug in my own code: a pair-counting fault that had silently dropped a third of the edges, 93,502 stored against 143,488 actual. The graph had passed every smoke test the whole time. Current state on the 143k-edge graph: precision 1.000, recall 1.000, 25 of 25 stored counts recounted exactly from commits.

It routes the review. Ranked by how much of the affected files' history each person owns. The most prolific committer is often the wrong reviewer. Fixing the denominator in that calculation moved scores by 1.3x to 2.7x and corrected the ranking outright.

It states its own bounds. A vector index hands you the least dissimilar matches and no way to tell what it ruled out. Tangle returns a certificate saying exactly how much of the graph it searched:

Beyond the 2 file(s) you changed, Tangle found 67 file(s)
coupled strongly enough to travel. 70 of 58,759 files (0.1%)
and 966 of 143,488 coupling edges (0.7%) were inspected.
No path below confidence 0.3 was taken.
Enter fullscreen mode Exit fullscreen mode

An agent can check whether an answer deserves its weight before acting on it.

What the measurement changed

The benchmark also earned its keep by telling me where I was wrong. Two of those fixes shipped.

Hop budget. I was walking two hops. One hop against two put top-1 accuracy at 9.9% versus 3.4%. The second hop was filling the list with weakly connected files that happened to share many commits with some node two steps away.

The confidence gate. The gate read max(co/changesA, co/changesB), which prefers 3 co-changes out of 3 commits (ratio 1.0) over 60 out of 100 (ratio 0.6). No threshold on that ratio fixes it. A Wilson lower bound moved F1 from 0.019 to 0.025 and cut wrong predictions from roughly 425,000 to 32,000.

I also tried blending the import graph into the coupling ranking. Every blend weight from 0 to 4 scored identically. Coupling and imports turn out to be near disjoint on this repo, so the files surviving the gate are precisely the ones imports cannot reach. I deleted the code rather than ship a no-op with a good story attached.

The honest limit

A plain shared-commit count reaches 32.0% recall against Tangle's 19.7% on mature files. On recall alone that one-line git log beats the method. I kept the table at the top of this post because you should know that before you trust the rest.

The gap is ranking, not gating. Tangle names something in 2,155 of those 2,325 cases, so it is not returning empty lists. It orders 9.0 names where the baseline orders 11.8. Closing that needs a better score, and I could not find one: six orderings were tried, and blending a Wilson bound in measured worse (0.0708 against 0.0774).

One number here went to zero. In 576 cases Tangle returned an empty warning list, and in none of them was the forgotten file coupled to the diff. Before I removed the confidence gate it was 456 of 1,032. The caveat line stays, because 1,755 held-out files had no co-change partner at all and no history-based method can reach those.

Where it runs

File -[:COUPLED]-> File      co-change, directional confidence
File -[:IMPORTS]-> File      static imports
File -[:TOUCHED_IN]-> Commit
Commit -[:AUTHORED]-> Person
Ticket -[:EXPLAINS]-> File   the why
Enter fullscreen mode Exit fullscreen mode

FalkorDB is a graph database, and it runs the traversal. algo.PageRank over COUPLED returns the load-bearing files that everything else routes through. algo.betweenness returns the bridges between clusters. algo.WCC splits the repo into subsystems.

npx tangle ingest --repo vercel/next.js
npx tangle check --files src/a.ts,src/b.ts
npx tangle why --repo vercel/next.js --couplings
npx tangle verify --repo vercel/next.js
npx tangle structure --repo vercel/next.js
Enter fullscreen mode Exit fullscreen mode

An MCP server ships with it, so Claude Code, Cursor, and Codex query the graph directly. tangle_check runs before an agent finishes a change. A GitHub Action posts the missed files on the pull request. Open source, TypeScript end to end.

Performance after tuning: import scan across 24,547 files went from 147.6 seconds cold to 10.0. Full ingest 315 to 124. Verify on the 143k-edge graph completes in about 31 seconds.

Where this goes

The recall number is the problem to beat. A file that changed three times in its life gives a co-change method almost nothing to key on, and no threshold fixes that. More history does.

What holds up today: the reason a coupling exists, a ranking that puts the right file at the top more reliably than the alternatives, and a way to check the graph is not lying to you. On 99.7% of next.js couplings those are the claims I can make, and every one is checkable.

Repo, the full back-test, and the limitations are in the README.


Tangle is a FalkorDB Graph Hacks entry. Every number above comes from a run you can reproduce with npm run backtest.

Top comments (0)