Agent Trust & Assurance · Signed Data Products
A signature usually promises that nothing changed. This one promises something stronger — that nothing can change: same request, same governed SQL, same rows. A signed data product cannot answer differently, drift, or invent.
Trust & Assurance · visual story · companion architecture: Signed Data Products (OBDA)
A data product is not a query someone saved. It is a producer-declared subgraph of the ontology: which entities are exposed, the only joins assembly may ever use — each with its cardinality declared, never inferred — and the measures. The declaration is the manifest; the manifest is the contract.
The manifest freezes what the resolver said at authoring time (deployed: — rule M1), declares every join's cardinality explicitly (M3), and names the grain of every entity (M2). Nothing at consumption time is ever guessed.
The product lives as a gold node on the knowledge graph, holding member edges to the entities it exposes. Agents meet it while planning — rendered as a consumption contract, not a bare name — and the graph's own governance travels with it.
Every rule a manifest can break has a machine-readable code and a near-miss hint ("unknown measure 'TotalRevenue' — closest declared: line_revenue"). A consumer — human or model — corrects in one step instead of probing.
Before a product can be signed, the platform mechanically verifies that every request in its admissible space compiles to deterministic, aggregation-safe SQL. Seven checks; the report states exactly what evidence backed each one; the report itself becomes part of what is signed.
| Check | What it proves | Evidence |
|---|---|---|
| V1 | Every entity resolves to exactly its frozen deployed table — drift means "re-validate + re-sign" | schema / structural |
| V2–V4 | Join columns exist · the join graph resolves to a unique tree · every expression parses and transpiles | structural |
| V5 | The grain-safety matrix: every measure × dimension pair classified safe, or rejected naming the 1:N hop that would multiply rows | structural |
| V6 | The determinism battery — built from the admissible map itself, compiled twice, byte-identical | structural |
| V7 | Live probes: the battery executes at the real target; every declared N:1 and every entity key is spot-checked empirically against the data | live |
The compiler's core rule, executed as proof in CI: both forms run on a real engine against hand-computed truth — the naive join provably multiplies, the assembly provably cannot.
The gate does not trust the producer — it asks the data. During acceptance, a product deliberately declared Sales → SaleDetails as N:1, claiming SaleDetails unique on SaleID. The live probe ran the composite-safe uniqueness check against real Teradata and answered: "the data CONTRADICTS the declaration — 2 duplicate group(s) found." Not signable. Sign-off refused.
And the probes police the platform's own tests too: a fixture declaring a column that doesn't exist (Products.Category) failed V7 with the database's own Error 3810 — before anything could sign over it.
The probe agreed with the declaration — battery executes, cardinalities and keys verified empirically.
The data disagrees with the manifest. V7 fails naming the declaration; the product cannot sign.
No connection available — the gate proves everything it can and the report says mode: structural, honestly. The mode is attested content: it changes the report hash.
Most signatures attest a name. This one attests content and proof together: the signable hash binds the manifest and the validation report that passed it. Five conditions must hold, each individually refusable, each machine-readable — a signature that cannot be a rubber stamp.
The badge's live hash recomputes the same formula from the node's current state. An edited manifest, a refreshed report, a drifted deployment — each reads changed against the attestation, never silently intact. Re-validate, re-sign: the ratchet only turns forward.
A product signs only on a signed-and-intact ontology — the same compositional rule that governs the agent badge, extended one layer down. And it extends upward too: composed products demand signed members (Act VI).
Declare an agent surface-only, and the set of signed products on its surface is its entire data authority. Raw SQL is denied fail-closed at every tool chokepoint. The one exception is precise: the only raw statement it may execute is one the surface itself compiled this turn — edit a single character, and the contract is forfeit.
From the live acceptance: the lure turn — three raw-SQL attempts, three denials, zero rows, lane confined — then the natural question: the planner chose query_product first, a wrong measure was rejected with the fix named, one-step self-correction, and the compiled statement returned 32 rows from live Teradata.
A denied call never executed — so it counts as confined, not free-formed. The alternative would record the confinement working as the escape it prevented, and score the agent down for being protected. Found live; fixed at the root.
Prevention subsumes detection — but detection stays on as the audit of prevention. Free-formed SQL executed by a surface-only agent records a danger incident: "a hole report, not agent misbehaviour." It fires only on the breach, never routinely.
After the first denial the agent self-corrects to the surface. If denials keep appearing, the consumer needed something the surface doesn't offer — producer backlog, made measurable. The scorer that counts them never gates.
The same posture, for the other modality: requireSignedKnowledge restricts retrieval to collections whose integrity signature is signed-and-intact — a changed or unsigned corpus never backs this agent's answers.
When a governed answer ships, the consumption itself is sealed into the turn's Ed25519 provenance chain: the product, the exact request, the compiled statement's hash, the row count, and the trust state at the moment of consumption. The receipt is offline-verifiable — and it is checked against the turn's own record, so the seal and the display can never quietly disagree.
The receipt is a closed set of fields — a stray presentation field can never enter the seal — and the same canonical function that seals it is the one offline verification uses to re-derive it from the turn's displayed record. A receipt matching no recorded operation is a named mismatch, never a silent skip. The answer capsule shows the row (fitness_sales · trusted · 32 rows); "Export receipt" carries it inside the signed chain.
Products stack. A composed product declares member products and the bridging joins — nothing else — and flattens through the unchanged pipeline: the same gate, the same compiler, the same probes, bridges included. If the flat form passes, it signs without re-judgement: composition preserved determinism, and the gate proved it.
Live: fitness_360 signed over its two members, then answered a cross-member query through the bridge — 20 real rows of revenue by product type, governed lane, lineage-bearing hash in the provenance stamp.
Before its members were signed, the composed sign-off refused: "a composed product contains only SIGNED members — not signed-and-intact: phase_a_acceptance." The agent shield's bottom-up rule, one level down.
The composed badge recomputes its lineage from the members' current attestations — so a re-signed parent reads through as changed on every child. And the cascade is honest: a metadata-only change in the parent re-signs cleanly (the flat contract is byte-identical); a shape change forces re-validation first.
Every figure below is from the live acceptance runs on real Teradata — not projections, not a demo dataset.
Detection tells you an answer drifted. Prevention makes drift unreachable. The rest of the trust stack observes, grades, and enforces what an agent says. Signed data products go one layer deeper — they constrain what an agent can even reach, and then hand the reader a sealed, independently verifiable receipt for every number that crossed the boundary. Same request, same governed SQL, same rows. Signed.