Claims are edges, not rows
Why Grivara models a claim as a typed edge instead of a row — and how a three-layer ontology (conceptual, contract, provenance) makes every decision auditable.
When a regulator asks why we flagged a claim, we have to give three different answers — and they all have to point to the same truth.
The CTO wants to know which model fired. The SIU lead wants the pattern: which prior claims look like this one, and how do we know. The state insurance examiner wants the receipts: which PDF, which page, which sentence, signed off by which adjuster. Same question, three audiences, three vocabularies. If your data model only speaks one of them, you'll fail the other two on every audit.
Most claims platforms model a claim as a row in a table. Columns for everything — claimant ID, policy ID, loss amount, status. Joins everywhere. It looks fine on a slide and falls apart the minute someone asks why.
We model a claim as something else. A junction. A point where six kinds of entity meet, where the edges carry the meaning, and where every decision downstream is reachable by walking the graph. That's the headline. The rest of this post is the proof.
Three ontologies, not one
Most "AI claims platforms" pick one of three ontologies and force everything through it.
Some sell you a conceptual model — ER diagrams in the sales deck, then SQL underneath that quietly drops the relationships. Others ship a message contract with protobuf or Pydantic everywhere; every agent emits a typed object, but ask for the audit trail and you get a stack of logs. A few build an immutable provenance log — append-only, queryable forever, semantically empty.
Each of these is necessary. None is sufficient.
One table
A claim is a row. Joins to claimants, policies, vehicles. Decisions are written into status columns or a sidecar audit log. Asking why requires a developer.
Three layers
Conceptual entities for humans. Typed contracts for agents. A provenance graph for auditors. Each layer points to the one below. Asking why traverses the graph until it hits a PDF.
The three layers map to the three audiences from the opening: conceptual to the SIU lead, contract to the CTO, provenance to the regulator. Each is the right answer to a different question. The trick is making them all describe the same claim without drifting.
The conceptual layer: six entities, seven edges
The conceptual ontology is the shape every other layer answers to. It's small because an adjuster has to hold the whole thing in their head — not in a wiki tab they keep open. It's typed because vagueness is how rings hide; ambiguity in a node class means a fraud pattern can pose as a clerical one. Six entities, seven edges, every label a word a claims VP would say out loud.
Six entities: Claim, Policy, Claimant, Vehicle, Provider, Loss Event. That's it. Not thirty, not eighty. Six is enough to express every claim we've seen across auto, property, commercial, and health — and small enough that an adjuster can hold the whole picture in their head.
Seven typed edges: FILED_BY, COVERED_BY, DAMAGED, ABOUT, TREATMENT, TREATED_BY, INVOLVES. The edge labels do the real work. Look at TREATED_BY (claimant ↔ provider) and TREATMENT (claim ↔ provider). Same provider sits at one end of both. Different other end. The first edge says "this person sees this doctor." The second says "this specific claim cites this provider's bill." Collapse them and you lose the distinction that catches a provider-side ring.
That's the whole secret of the conceptual layer: edge labels carry more information than node types. You can stand up a knowledge graph with twenty node classes and still miss organized fraud if the edges are unlabeled. The opposite — six entities with carefully typed edges — catches it.
Six detectors hang off this ontology, each one reading a specific subset of edges. Graph collusion reads TREATED_BY and TREATMENT. Tabular risk reads COVERED_BY and FILED_BY. Multimodal reads ABOUT, INVOLVES, DAMAGED. The detectors aren't features bolted on. They're projections of the ontology — change which edges exist and a detector either stops working or stops being needed.
The contract layer: bronze, silver, gold
The conceptual layer is what humans see. The contract layer is what specialist agents pass to each other. Grivara's pipeline runs six specialists — intake, coverage, fraud, compliance, comms, orchestrator — plus a reviewer agent behind each one. Every handoff between them is a typed Pydantic object. No free-form text. No "the fraud model returned a score" implicit handshake.
The contract has three tiers, borrowed from medallion architecture and bent to fit the claim domain.
- BronzeImmutable, addressable by checksum
Raw documents
ClaimDocumentRaw— FNOL, estimates, photos, EOBs, repair invoices. Stored once. Identified by SHA-256. Never edited, only superseded. If a document moves between systems, the checksum moves with it. - SilverProvenance attached
Typed evidence atoms
EvidenceAtom { atom_id, atom_type, value, confidence, provenance_span }. Every fact extracted from a bronze document becomes one atom.provenance_spanis a byte range pointing back into the source PDF.confidenceis the extractor's score, 0–1. Everything downstream reads atoms, not raw text. - GoldVersioned, queryable
Derived signals + verdicts
ClaimSignal(a single computed number with acalculation_version) andRiskSnapshot { fraud_score, fraud_band, coverage_posture, compliance_posture, uncertainty_score }. The fraud agent reads atoms, writes signals, hands the snapshot to governance. Governance reads the snapshot and writes aGovernanceDecision.
The load-bearing field is provenance_span on the silver layer. It's a byte range, like pdf:doc_8821:page=4:bbox=[124,330,512,358]. Every typed fact extracted from a document — "damage estimate is $14,200", "loss date is 2026-03-14", "claimant has two priors in 24 months" — carries one. The gold snapshot doesn't carry its own evidence; it points to the silver atoms it was computed from, which point back to bronze.
Versioning matters here. calculation_version on a ClaimSignal is a string like fraud_v_2026_04_18. When we re-tune a detector — change a threshold, swap a model, fix a bug — old snapshots keep their old version tag and stay queryable. Nobody silently rewrites history. If an SIU lead is reviewing a decision from six months ago, they see exactly what the system saw then.
This is the layer where the CTO buy-in lives. Once a team understands that every gold field has a typed silver lineage and every silver atom has a bronze checksum, the question "is this system auditable?" stops being a question.
The provenance layer: the audit trail is a graph
The third layer is the one most vendors skip, then bolt on as a log file under regulatory pressure. We started here.
Every claim that enters the system writes itself into a graph database, and every action downstream becomes a node connected to it. The node labels are deliberately small:
(:Claim)— one per claim(:ClaimDocument)— bronze documents attached to the claim(:EvidenceAtom)— silver atoms extracted from documents(:PipelineRun)— one per end-to-end agent run(:FinalDecision)— what the pipeline recommended(:ApprovalDecision)— what the human chose
And the edges tell the story:
(:Claim)-[:HAS_DOCUMENT]->(:ClaimDocument)(:ClaimDocument)-[:PRODUCES]->(:EvidenceAtom)(:Claim)-[:HAS_RUN]->(:PipelineRun)(:PipelineRun)-[:FINAL_DECISION]->(:FinalDecision)(:FinalDecision)-[:APPROVED_BY]->(:ApprovalDecision)(:Claim)-[:LINKED_TO]->(:Claim)— the cross-claim collusion edge
What this gets you: the audit trail is a graph traversal, not a log file. When an examiner asks "why did you flag CLM-8817?", the answer is a single query, three lanes wide:
- Match(c:Claim)$claim_id:HAS_RUN(r:PipelineRun):FINAL_DECISION(f:FinalDecision)
- Optional match(f:FinalDecision):APPROVED_BY(a:ApprovalDecision)
- Optional match(c:Claim):HAS_DOCUMENT(d:ClaimDocument):PRODUCES(e:EvidenceAtom)
c, r, f, a, collect(d) AS docs, collect(e) AS atomsOne traversal returns the whole decision tree. The model's recommendation, the human's override (or sign-off), every document the model looked at, every atom it extracted. The regulator wanted receipts. This is receipts.
LINKED_TO is the interesting edge. It's how a confirmed-fraud claim from last quarter influences a new claim arriving today. When SIU confirms CLM-8201 as fraud, we write LINKED_TO edges to its graph neighbors with weights derived from shared claimants, providers, attorneys, and dates. Two weeks later, a new claim shares a body shop with CLM-8201 — the graph already knows, the score already moves, no retraining needed. We covered the propagation math in another post.
Why three is the right number
The honest objection here is: three layers is more moving parts than one table. Why bother?
| Layer | Consumer | Change rate | Failure mode |
|---|---|---|---|
| Conceptual | Humans (SIU, adjusters, buyers) | Years. v1 has been stable since launch. | Wrong ontology → adjuster mental model breaks. |
| Contract | Agents (intake, fraud, governance, comms) | Months. Re-versioned per agent release. | Schema drift → one agent emits, another can't parse. |
| Provenance | Auditors (regulators, internal SIU, appeals) | Append-only. Never rewritten. | Missing edge → "we can't reconstruct why we decided." |
The short answer: each layer has a different consumer, changes at a different speed, and fails in a different way. Squashing them together gives you a schema that's bad at all three jobs and a database migration every time anything moves.
Different consumer is the obvious one. The SIU lead doesn't want to read protobuf. The agent doesn't want to parse human-friendly labels. The auditor wants a graph, not a Pydantic class diagram. Force them through one schema and each one gets a worse version of what they'd ask for.
Different speed is the one that surprises people. The conceptual ontology has been stable since launch — six entities, seven edges, no churn, v1 is the only version we've shipped. The contract layer gets re-cut every time an agent ships. The provenance graph is append-only and will be forever; rewriting it is what regulators call "tampering."
And failure stays local. If silver extraction misreads a PDF, you re-extract atoms from bronze. If gold scoring goes wrong, you re-score from silver. The conceptual model almost never breaks because it almost never changes. Mixing the layers means every one of those failures becomes a migration. Keeping them separate means most failures are contained to one tier.
The cost is real — three schemas to keep in sync, three layers to debug when something goes wrong. We pay it because the alternative is being unable to answer the regulator's question, and that one isn't optional.
The non-negotiable: a human is always the terminal node
Look back at the provenance graph. The trail always ends at (:ApprovalDecision) — a real adjuster, a real reason code, a real timestamp. Not optional. Not skippable. Not silently auto-approved when confidence is high.
This is why the ontology is shaped the way it is. The graph isn't decorative. It encodes our governance posture into the topology itself: every path the system walks ends at a human. If you were to write the same system without the terminal ApprovalDecision node, you'd have a different product — faster, cheaper, and the kind of thing that gets a carrier in front of a state insurance commissioner.
If the three-layer ontology is the substrate, the detectors that read from it are the surface. We wrote one of them up in detail.
Related
Inside graph collusion
How a 3-hop neighborhood becomes a single fraud number an adjuster can trust.
Product
Agentic fraud detection
The six detectors hanging off ontology v1, and how they fuse into one verdict.