Contracts
A contract is a governed interface to analytical data, and the thing consumers actually query.
A contract is the centerpiece of Gaur: a named, validated definition of what callers may query on a dataset and exactly how each value is calculated. Contracts are the only thing consumers see. Tables and models sit behind them.
Why contracts
Tables and models are flexible, which makes them easy to query inconsistently. Two teams join the same tables slightly differently and get different revenue numbers. An AI agent writes SQL that quietly double-counts. The data is fine; the interface is the problem.
A contract removes that freedom on purpose. It declares a fixed set of dimensions and measures, defines each measure's calculation exactly once, and validates that the whole shape is provably correct before it publishes. Every caller then reads the same answer for the same question.
What a contract gives you
- One definition. A measure like
revenue_usdis written once, in one contract. Every app, dashboard, and agent that uses it computes it the same way. - Correct, or rejected. The shape of the contract is checked when it's authored; the shape of each query is checked when it runs. Combinations that would silently inflate or skew numbers are rejected with a clear message, never served.
- A stable surface. Callers depend on the contract's names, not on the underlying schemas. You can refresh data or restructure models beneath a contract without breaking what calls it.
- Scoped access. Row-level security inside the contract limits what each caller can see, driven by context passed at query time.
What's in a contract
A contract is a JSON document with five top-level parts:
| Part | Purpose |
|---|---|
sources | The tables and models the contract reads, and how they join. |
dimensions | The attributes callers may group and filter by. |
measures | The values callers may aggregate. |
filters | Fixed conditions always applied (every caller sees the filtered view). |
rls | Row-level security, evaluated per call. |
Anatomy of a contract walks through each
part in detail using Jaffle Shop's product_performance as the example.
How a contract is queried
Callers never write SQL against a contract. They send a structured query that names dimensions and measures the contract has declared:
{
"contract_name": "product_performance",
"query": {
"dimensions": [{ "name": "category" }],
"measures": ["revenue_usd", "cogs_ratio"],
"filters": [{ "field": "category", "operator": "eq", "value": "jaffle" }],
"sorts": [{ "field": "revenue_usd", "direction": "desc" }],
"limit": 50
}
}Gaur validates the query against the contract, injects row-level security, compiles it to SQL, runs it against its own copy of the data, and returns governed rows. See Querying contracts for the consumer side.
In this section
Anatomy of a contract
Sources, dimensions, measures, filters, and row-level security, walked
through with the Jaffle Shop product_performance contract.
Measures
Standard, rolling, and derived measures, and why additivity matters.
Rules and limitations
The single-fact rule, fan-out and chasm, the join-key rule, and what contracts can't do.
JSON schema
The canonical JSON Schemas for contract definitions and queries.
Before authoring anything beyond a single-source contract, read Rules and limitations. Gaur rejects unsafe contracts by design, and knowing the rules up front saves rework.