Engineering story · FAFOHive

A code explainer that is not allowed to invent

Compute the call graph first, narrate second: putting deterministic evidence in front of the model

3 min readFAFOHiveRusttree-sitter
A computed graph · the model is shown one proven path anchor, traverse and hydrate are database work; the model only narrates the lit path
When the graph cannot cover itno fallback to a free-form answer
"coverage
incomplete"
the whole answer
  • 294,033of 294,362 code chunks covered by the graph
  • 0model calls in a dependency trace
  • 19,000files, several languages, in the indexed monorepo

Ask a language model how a piece of code works and it will tell you, fluently, including call paths that do not exist. Engineers act on those answers. I built a code-intelligence service where the model may only describe edges that a computed graph has already proven. The graph is extracted from source with a parser, dependency traces are plain database traversals with no model involved, and the explainer narrates only the evidence it is handed. If the graph's coverage is incomplete for a query, the answer is "coverage incomplete".

The challenge

A monorepo of around 19,000 files across several languages, used daily by AI agents that must understand blast radius before changing a symbol. The service had to be fast enough for agents to call before every change, accurate enough to act on, and structurally unable to present fabricated structure.

Constraints

Multi-language: Rust, Python, C#, TypeScript and more in one index. Routine use, so it cannot take minutes. And no fabrication, because a wrong answer with a confident tone is worse than no answer.

My approach

Compute first, narrate second. Everything the model is allowed to say about structure is computed before the model sees the question. Symbol dependencies, callers, callees, implementations and imports come from a graph built by a parser, stored in a database, and traversed with bounded queries. The model's only job is to put a path it has been shown into plain language.

What I built

Edge extraction with tree-sitter into partitioned edge tables, with a resolver that moves edges from pending to active as their endpoints are indexed, and graph generations so an index can be rebuilt without serving a half-built graph.

One edge
Edge
Endpoint A indexed
Endpoint B indexed
both ends indexed: traversable
Graph generations
Generation n
Generation n+1
switch

Dependency tracing as a bounded breadth-first search in SQL, with no model in the loop.

Path explanation: a deterministic anchor, a bounded traversal between two points, hydration of the code on that path, and only then narration by a model of exactly that evidence.

A coverage check that returns "coverage incomplete" when the graph does not fully cover the files a query touches.

Every touched file covered
the model narrates the path
One file uncovered
the whole answer: "coverage incomplete"

Difficult decisions

No fallback. When the graph cannot answer, the obvious product move is to let the model answer free-form with a caveat. I did not build that path.

A refusal beats a plausible guess, because the caveat is the first thing a reader stops seeing.

Results

Tracing the blast radius of a symbol before changing it is a standing rule in my agents' operating doctrine, and this service is how they do it.

Technologies used

Rust · tree-sitter · PostgreSQL · Redis · Dense embeddings for semantic search · Bounded graph traversal · Model narration over supplied evidence

What this demonstrates

Putting deterministic evidence in front of models instead of asking models for evidence. It is the same instinct that runs through my governance work, applied to the question "how does this code work".