Skip to content
Cartograph

How it works

The claim is that every answer can be checked. That requires three things to be true: the chunk a citation points at has to be a meaningful unit of code, the line range has to be the real range in the real file, and the commit has to be pinned. Everything below exists to hold those three properties.

1 · Indexing

A repository is downloaded as a tarball from the codeload endpoint rather than cloned. No git binary is needed, it is one request, and the endpoint resolves a branch or tag to a commit SHA — which is exactly the pin every citation needs. Vendored directories, lockfiles, minified bundles and anything with a NUL byte in its first block are skipped: a bundled dependency tree is mostly other people's code and would dominate retrieval for every question about the project itself.

Nothing is written to disk. The archive is decompressed in memory and only files that will be indexed are decoded, so a repository carrying a 90 MB binary asset costs the bandwidth but not the memory.

2 · Chunking on definition boundaries

This is the part that makes citations worth anything. A fixed-size window cuts a function in half, so the retrieved passage is a loop body with no signature and no name, and the line range points at something meaningless on its own. Cartograph parses each file with tree-sitter and splits on definitions instead: functions, methods, classes, structs, traits, types.

Nesting is resolved by preferring the outermost definition that fits the size budget. A 40-line class becomes one chunk; a 600-line class becomes one chunk per method, each labelled with the class it came from. Emitting both would index the same lines twice, which double-counts evidence in retrieval and inflates any citation-accuracy measurement.

Code that belongs to no definition — imports, module constants, top-level script bodies — is collected into its own chunks rather than dropped, because “where is this configured” is usually answered by exactly that code. Three invariants are asserted in CI on every commit: no chunk claims a line another chunk claims, nothing with content is dropped, and every chunk sits inside its file.

Twelve grammars ship as prebuilt wheels. A language whose grammar is unavailable degrades to line-based chunking rather than failing the index, and /api/v1/languages reports what the running build can actually parse instead of asserting a list.

3 · Three-arm retrieval

Prose retrieval has two useful signals: vector similarity and term frequency. Code has a third that is stronger than either. When a question names an identifier, the definition of that identifier is almost certainly the answer, and neither cosine similarity nor ts_rank_cd reliably ranks it first. An exact index lookup does, every time, in about a millisecond.

embed(query) ─┐
├─ RRF fusion ─ per-file cap ─ top_k
full text ────┤
symbol match ─┘

Fusion is Reciprocal Rank Fusion, using ordinal position only. Cosine similarity lives in [-1, 1], ts_rank_cd is unbounded, and a symbol match has no natural score at all, so adding the three together would require inventing a normalisation that breaks on the next repository. The symbol arm carries a weight above 1.0 because an exact identifier match is the strongest evidence available.

A per-file cap follows fusion. Without it, one large module fills the whole context window and the answer cites eight ranges from a single file.

4 · Citations and refusal

Passages are numbered in the prompt and shown with their real line numbers from the file, so when the model refers to a line it is quoting the file rather than counting its own context. Markers are then resolved back to chunks and renumbered to only what was actually cited. A marker that resolves to nothing is removed and counted, because an unresolvable citation is precisely the failure this project exists to make visible.

When the retrieved code does not contain the answer, the model emits a sentinel token and the API reports an abstention. Detecting refusal by string-matching apologies is unreliable and unmeasurable; a sentinel is neither. Abstention is scored in both directions, so a pipeline cannot look good by refusing everything.

5 · What it grades itself on

Questions are labelled with the files that should be cited. Four numbers are reported together, because the gaps between them are the diagnosis:

File citation accuracy
The answer cited a file that actually contains the answer. This is the headline number, because it is the thing a reader checks.
Symbol citation accuracy
The cited passage was the right definition, not merely the right file. A 900-line module makes file-level accuracy easy.
Retrieval recall
An expected file made it into the retrieved set at all.
Citation validity
Every marker resolved to a passage that was actually retrieved.

High recall with low citation accuracy is a grounding problem: retrieval found the file and the model cited something else. Both low is a retrieval problem. Chasing the wrong one is how a week gets wasted, which is why both are shown rather than a single composite score.

Deliberate limits

Reference counts are mentions. Resolving true call sites needs per-language scope analysis. Counting files that mention a defined name is crude, but it reliably ranks the handful of names holding the architecture together above the hundreds that do not, which is all the tour needs. It is labelled as what it is.

Import resolution is best-effort. Mapping a module specifier to a path is genuinely ambiguous. Anything that cannot be placed is kept as an external edge with the raw specifier rather than guessed at, because a wrong edge in a graph shown to a human is worse than a missing one.

Embeddings run on CPU in-process. The hosted embedding API answers this deployment's egress IP with an edge-level 403 before the request reaches their service. bge-small is a weaker model than the hosted one, and also about thirty times faster than the round trip it replaces. Which provider is live is reported on /readyz.

The rate limiter is in-process. With more than one replica the effective limit multiplies by the replica count. That is an accepted trade for a single small deployment; a shared limiter belongs in Redis.

LLM-as-judge is not ground truth. Citation accuracy is scored deterministically against labelled paths, which avoids the problem for the headline metric. Where judgement is involved, the per-question results are stored so any score can be audited.