Writing · 2026-08-30
How I made a knowledge graph that checks itself
Structural answers about an entire microservice fleet come back in milliseconds, and each one can re-check itself against live source before anyone acts on it.
An engineer on my team wanted to remove a column. core.credential.card_number. The ticket asked one thing: what breaks?
That question used to cost a week. You grep across the repos, you read the hits, you miss the mobile app because it renames the field inside a DTO, and you learn about it in production. Nobody was lazy. The knowledge was real. It just lived in six people's heads, and the six heads were never in the room at the same time.
So I compiled it. At Genea, a physical-security company, I built a deterministic ontology graph over the company's entire microservice fleet. I call it an ontology graph rather than a knowledge graph because the difference is load-bearing: the entity types and the relation types were declared on purpose and reviewed, not scraped into a pile and named afterward. Keeping the word honest keeps the thing honest.
The pipeline is boring by design. Extractors read seven substrates: backend services, vendor protocols, code atoms, live database schema, frontend, cloud infrastructure, and the two mobile platforms. Each extractor writes a YAML manifest. Manifests go through Git review, like code, because a manifest is a claim about reality and a claim deserves a reviewer. A schema compiler unions the reviewed manifests into one typed graph, and it fails the build when what a manifest declares does not match what the extractor observed. Declared-versus-observed drift is a compile error, not a warning. What comes out is one atomic graph artifact with a catalog of typed query operations over it.
Answers return in milliseconds, with no model call. Same question, same answer, every time.
That property is worth being precise about. A model asked "what consumes this column?" returns something plausible, and plausible is not true. Worse, the gap is invisible. A traversal returns what the graph contains, so when it is wrong, it is wrong in a way you can inspect, reproduce, and fix yourself.
But a compiled graph has its own silent failure, and it is the interesting one. Code moves. The graph does not notice. Two weeks after a build, an answer can be confidently, precisely stale, and it looks exactly like a fresh one. That is where most code graphs quietly rot, and it is the part I spent the most time on.
Four structural operations take a verification flag. With it set, the query answers from the graph and then re-reads the live source behind every node in that answer, returning evidence per node. Here is the card_number query with verification on:
core.credential.card_number -> blast radius (verified)
node evidence status
auth-service / Credential models/credential.rb:41 ok
credential.issued (event) events/credential_issued.json:12 ok
sns:credential-events (topic) infra/topics.tf:88 ok
event-processor / handler handlers/credential.py:23 ok
admin-web / column binding src/credentials/table.tsx:60 ok
ios-app / CredentialDTO.card Models/CredentialDTO.swift STALE: field not found
5 of 6 nodes verified, 1 failed. This answer is not safe to act on.
Someone renamed the iOS field and the graph had not been rebuilt. The point is not that the drift was findable. The point is what the answer did about it. It did not hand back five good nodes and stay quiet about the sixth. It reported itself unsafe. A failed verification then routes the caller to a cache refresh or to spec evolution, depending on which side is actually wrong.
That is the whole idea in one line. "The graph is out of date" and "the code changed under you" are different problems with different owners, and a system that cannot tell them apart will be trusted at exactly the wrong moment.
I think this matters more than a smarter model, and I want to say why without overselling it. A stronger model raises the ceiling on what an agent can work out. It does not change what the agent is standing on. Hand a very capable model a stale premise and you get a very capable wrong answer, arriving faster and sounding better. The scarce thing inside a real engineering organization is not reasoning. It is a source of structural truth that is cheap to query, dull to verify, and willing to say when it has gone bad.
Here is what I cannot claim. This runs in one organization. My engineering team uses it daily, and that is the whole of the evidence. There are no outside deployments and no formal benchmark against a retrieval baseline. I have latency numbers and reproducibility, not a controlled study, and one team's habit is not a result.
What is still unsolved: verification proves the graph matches the source, and nothing in it proves the source is right.