A graph that cannot say no

A graph with no ontology and no reflection is a more elegant value that still determines nothing and constrains nothing. This month's discussion brings the numbers that prove it, and does not read them that way.

Jesús Pérez
July 2026 filled the conversation with typed graphs for agents, on a thesis that is correct — an untyped edge carries one bit; a typed one carries meaning — and with independent benchmarks that back it. But those same benchmarks say something their popularisers do not finish: one system collapsed to 6.6 average F1 against 59.8 the moment somebody other than its authors evaluated it, and a five-hop chain at 85% per-hop accuracy is worth 44%. The problem is not missing structure. It is that structure, alone, obliges nothing. And the gap the article itself declares empty — a linter for typed edges — has been running here for a while.
A graph that cannot say no

If you got here through the term graph engineering, that is the only time I will use it. It surfaces once more, at the end, inside the title of the article being cited — somebody else’s title is not mine to edit. Not because it is contemptible — the substance is real and has a decade of research behind it — but because a piece that hangs on a word born on X eleven days ago expires when the word does. What follows rests on things that will still be there: a migration with a number, a validator that runs, and a published results table.

The diagnosis is right

The thesis going around is a good one, and it is worth saying so before disagreeing with anything: an untyped edge carries one bit of information. It says two things are related. A typed one — supersedes, depends_on, contradicts, caused — says how, and that is what separates a pile of links from something you can reason over.

The canonical example is a decision chain: why X was dropped. The answer lives in no single document; it lives in the structure joining the decision record, the thing it replaced, and the incident that triggered it. Similarity search retrieves ten notes mentioning X and not one that explains it, because “these three belong to one causal chain” is not a property similarity can see.

So far, agreed. The disagreement starts at the conclusion.

The numbers say more than is being read in them

The independent 2026 benchmarks exist and are public. They are worth looking at without the enthusiasm filter.

In GraphRAG-Bench (arXiv:2506.05690), on the novel corpus, the by-task reading comes out like this:

TaskBest graph methodVector RAG with rerank
Complex reasoning53.38% (HippoRAG 2)42.93%
Contextual summarization64.40% (GraphRAG local)51.30%
Fact retrieval60.14% (HippoRAG 2)60.92%

And the per-query cost, from the same work: ~880 tokens for vector RAG, ~1,008 for HippoRAG 2, and up to 331,375 for GraphRAG’s global search.

The two margins above are real and wide. But the third row is the interesting one, and it is the one the popularisation walks past: on simple fact retrieval the best graph method loses to vector search. Not ties: loses, while adding redundant context. The paper’s own summary puts it less diplomatically than it has been quoted: GraphRAG underperforms conventional RAG on many real-world tasks.

Structure is not a monotonic improvement. It is a bet that wins on some questions and loses on others, and costs between three and four hundred times more.

The case that proves the thesis

The sharpest figure of the year is in the HippoRAG 2 paper (arXiv:2502.14802), in its results table. LightRAG scores 6.6 average F1. HippoRAG 2, in the same table, 59.8.

LightRAG had published excellent results. On its own benchmark, evaluated by its own authors. The moment somebody else measured it, it fell by almost a factor of ten.

Read that twice, because it is not a reproducibility anecdote. LightRAG is a graph. It has nodes, edges, extraction, retrieval. It satisfies in full the description everyone is discussing this month. And it constrained nothing: nothing inside the system could contradict its author, so the only possible contradiction came from outside, late, and all at once.

A graph that cannot say no to anything is not half a graph. It is a more elegant value.

The arithmetic that kills the project

There is a second figure, and it is not a citation: it is a power.

Entity resolution — deciding that “Dr. John Smith”, “J. Smith” and “John” are one node, and that “Mercury the planet” and “Mercury the element” are two — fails with a probability that compounds multiplicatively along a traversal.

0.95⁵ = 0.77      five hops at 95% per hop → 77% trustworthy
0.85⁵ = 0.44      five hops at 85% per hop → 44%

At 85%, your impressive five-hop traversal is a coin flip.

And notice what that does to the build order. The expensive part is not graph algorithms: it is deciding what is the same thing. Which is to say, the expensive part is not the structure. It is the determination.

What nobody has claimed

The article that opened this conversation ends by naming two things that, it says, exist nowhere. One is an eval proving that typing improves answers. The other, verbatim:

“A linter for typed edges. Nothing validates a vault’s graph: unknown types, dangling targets, missing inverses, contradiction cycles. Zero tools.

Here it pays to be exact, because the temptation to say “we already had that” is strong and would be dishonest in two ways. First: he scopes his gap to plain markdown, to a vault you open in your editor. Ontoref is not markdown; its graph is declared in typed NCL. We are not claiming his gap. Second, and more important: claiming priority is the fastest way to widen an audience without qualifying anybody.

What can be said is the concrete part. That linter — unknown types, dangling targets, inverses — is exactly what validate ontology runs here, and its output is two lines:

61 nodes · 175 edges · 0 findings · vocabulary: 9

The 9 is the entire number of edge types that exist. Not a convention, not a recommended list: a closed enum with its inverse map frozen, reconciled in a numbered migration — 0043 — because before it the enum declared four types nobody used and omitted four that were in active use, and the edge records were uncontracted, so the divergence stayed dormant with nothing to bite it.

A dangling target is not documented: it fails Hard. A type outside the vocabulary is not warned about: it fails. The difference between those two sentences is the whole matter.

Describing versus obliging

The graph being proposedontoref (on+re)
Edgestypedtyped and closed-vocabulary (9 kinds)
Vocabularyconventionenum with a frozen inverse map
A violationis documentedis refused (Hard)
Identitya wikilinkdeclared id; dangling edge = failure
Changeoverwritessupersedes, with a signed witness
A node’s authoritytyped warrant: by virtue of what does it exist?

The row with no counterpart is the last one, and it is what separates an ontology from an index. warrant does not ask what a node says or what it connects to: it asks by virtue of what it is there. A retrieval graph does not need to answer that, because its job ends when it finds the document. A governing graph does, because its job starts when somebody tries to contradict it.

His graph describes. This one obliges. And a graph that cannot say no to anything is documentation with better typography.

The uncomfortable half

It would be comfortable to end there. It is not available, because this same week the project published case file 63/0, and it says the opposite of what one would want in a post.

Ontoref has had a bitemporal store for months: both times, retraction, supersession, declared in an accepted ADR. And the code feeding it emitted not one retraction, left the second time empty on every operation, and restarted its clock on every pass, filing July underneath May. Sixty-three days of drift. Zero reconciliations. And throughout, validate ontology answered 0 findings, truthfully: it measures structural integrity, and nobody had declared a state called “the projection is fresh”.

We had the linter this month declares nonexistent, and we also had the bitemporal store the article takes as solved elsewhere. And we had spent two months using the second one wrong, in silence, while the first answered that everything was fine — because we were asking the wrong piece.

That does not weaken the thesis: it is the thesis. Having a capability and using it differ by an amount nobody notices, and the only way that distance becomes visible is if something refuses. Not a document describing it. Something that refuses.

So what the episode left is not the fix but a gate that rejects the commit touching the graph without reconciling, and a debt written into the case file itself: that gate checks freshness, not bitemporal conformance. An extractor rewritten monotemporally tomorrow would pass green. It is declared there, with the address of what would settle it, instead of resting on somebody remembering.

The witness is not absolute either

Here is the obvious objection, and it is better asked of oneself before somebody else asks it: if your graph can say no, have you not swapped one dogma for another?

Start with this text’s own figures. 53.38% is not a fact about graphs. It is a fact about one corpus — a novel — with one specific reader (Llama-3.3-70B-Instruct), on one date, over a task taxonomy somebody decided. Strip those coordinates and it becomes a slogan; and as a slogan is exactly how it has travelled this month. A datum with no context, no moment, no reference and no purpose is not a datum: it is a loose number looking for a sentence to take it in.

The same holds for the witness, and the protocol says so before anyone asks. A witness here is a signed receipt of an act, and what it attests is bounded by explicit decision: it certifies structure, never truthfulness (ADR-050). It proves that a check ran, on what input, and what it returned. It does not prove the world is so. It is unquestionable inside its coordinates — this check, this input, this instant — and means nothing outside them.

The bitemporal store is that same renunciation turned into data. It does not say “X is true”. It says “X held from t₁, as far as the record knew at t₂”. It is, literally, the photograph of an instant with its coordinates written on the back — and that is why there are two times and not one.

So the answer is neither “let us declare the truth” nor “everything is relative”. Both disable the same mechanism from opposite sides: one turns it into dogma, the other into decoration. What survives is more modest and more useful: the scope travels with the claim. A gate that declares what it does not check. A figure that carries its corpus and its date. A fact that carries its two times.

And the case file above is what happens when the coordinate is lost. The extraction treated the projection as the state rather than as a dated photograph, so it overwrote instead of superseding; and the clock that should have dated it restarted at 1 on every pass. The instant was there. What was missing were its coordinates. Without them, sixty-three days of history read exactly like a healthy present.

What is left when the wave passes

This month’s conversation will end the way the previous ones did: the term will wear out and what can be executed will remain. Of everything written these two weeks, what survives is short and already in the papers:

  • A small typed core. Ten to twenty verbs, closed. It coincides with what is nine here.
  • Route by question type. Vector for simple lookups — where the graph loses — graph for chains.
  • Temporal supersession. Facts expire, they do not die.

And a fourth that is not in the papers and decides whether the rest is worth anything: something has to be able to say no. A vocabulary you cannot violate. A dangling target that breaks the build. A rule that, when you contradict it, does not warn you: it stops you.

Without that, structure is a more elegant value. And 0.85⁵ is still 0.44, however good the graph looks.

Amendment · 31 July 2026

Two days after this text, the same author published the second part — How to Do Graph Engineering in a Markdown Vault — and built the linter. The sentence quoted above, «Zero tools», no longer describes his repository. It describes the fortnight in which it was written.

Recording that here instead of editing the paragraph is deliberate. Two days before this post went out, this project accepted a decision that says precisely this (ADR-078): amending is the horizontal move of a text that still holds, and the alternative — correcting in silence — is how a claim ages without anybody noticing. That decision measured its own case first: seventy-seven of seventy-seven decision records edited after their first commit, and not one amendment recorded. A post that spends a section on figures travelling without their coordinates does not get to lose its own.

What the second part builds: a small taxonomy with inverses, edges in frontmatter, supersession that retrieval respects, a lint over five failure classes, and a bounded recall budget. On four of the five, what is written above stands — and on three it is worth being exact rather than generous:

  • his lint warns; validate ontology fails Hard. The whole distance is in that verb, and it is the same distance this post is about.
  • his six types are a taxonomy he chose and documents. The nine here are a closed enum with a frozen inverse map, reconciled in a numbered migration.
  • his «missing inverse» failure class cannot occur here: reciprocity is derived from the inverse map and never stored, so there is nothing to omit. That is an adaptation of Z39.19 §8.1.1, not a shortcut around it.

The fifth has no counterpart here, and that is the honest half of this amendment. His recall budget puts a number where this project has none: a ceiling on how much context enters a prompt, an abstention rule when relevance is uncertain, and fail-closed on a retrieval error. Here, context provision is governed in who may provide it and what is authoritative (ADR-074: a carrier invokes the governed surface, it never copies it) — and it is not bounded. No ceiling anywhere in the view schema, no abstention rule, and a session hook that empties the whole inventory on every entry. Checked, not assumed; filed as bl-042. It is the case file above one layer up: a surface that cannot say this is too much is also a more elegant value.

So the table has gained a row, and it is his. The row with no counterpart is still the last one — warrant — and now it is not the only asymmetry in the page.


Sources

Every figure in this text was checked against the primary source, not against its popularisation. Each one, with its exact origin:

Xiang, Wu, Zhang, Chen, Hong, Huang and Su · “When to use Graphs in RAG: A Comprehensive Analysis for Graph Retrieval-Augmented Generation” (GraphRAG-Bench) — arXiv:2506.05690 : Table 2, novel corpus: complex reasoning 53.38% (HippoRAG 2) against 42.93% (RAG with rerank); contextual summarization 64.40% (GraphRAG local) against 51.30%; fact retrieval 60.92% (RAG with rerank) against 60.14% (HippoRAG 2). Figures 8-9, per-query cost: ~880 tokens for vanilla RAG, ~1,008 for HippoRAG 2, up to 331,375 for GraphRAG’s global search. Its own abstract is where the sentence this post does not soften comes from: GraphRAG underperforms vanilla RAG on many real-world tasks.

Jiménez Gutiérrez, Shu, Qi, Zhou and Su · “From RAG to Memory: Non-Parametric Continual Learning for Large Language Models” (HippoRAG 2) — arXiv:2502.14802 : Table 2, average F1 with Llama-3.3-70B-Instruct as the reader: HippoRAG 2 59.8 · NV-Embed-v2 (7B) 57.0 · HippoRAG 53.1 · GraphRAG 49.6 · RAPTOR 48.8 · LightRAG 6.6. On 2WikiMultiHopQA: HippoRAG 2 71.0 F1 against NV-Embed-v2’s 61.5 — the 9.5 points quoted around are that subtraction, not a separate figure.

Rasmussen, Paliychuk, Beauvais, Ryan and Chalef · “Zep: A Temporal Knowledge Graph Architecture for Agent Memory”arXiv:2501.13956 : The per-edge bitemporal model — when a fact was true in the world and when the system learnt it — that underwrites supersession over overwriting. It is the prior art this post claims nothing from: it exists, it is public, and it got there first.

The hop arithmetic : 0.95⁵ = 0.7738 and 0.85⁵ = 0.4437. Not a citation from anyone: it is a power, and a calculator settles it.

The article that opens the conversation : “What Is Graph Engineering? A Field Guide for Builders”, Eugeniu Ghelbur, 21 July 2026, in The AI Operator (theaioperator.io). The quote about the linter that does not exist comes from there, as does the credit for gathering and ordering the benchmarks. This text disputes his conclusion, not his work.

On the ontoref side, everything asserted is inspectable in the repository: the closed nine-kind edge enum and its inverse map (code/ontology/schemas/core.ncl), migration 0043-edge-kind-vocabulary-reconciled, the output of ontoref validate ontology, and ADR-041, which declares the bitemporal model that case file 63/0 documents as unmet.


The protocol, its decisions and its graph are declared in NCL and can be queried: ontoref.dev. Case file 63/0 — the full autopsy of the sixty-three days — is at /case-files/cases/the-store-written-in-a-single-time.

Was this useful? Rate it
Got something to add? Tell me what you think, what you'd suggest, or whether we should keep exploring this topic.
· reads

We use cookies to help this site function, understand service usage, and support marketing efforts. Cookie Policy for more info.