A is an agreement between whoever produces a dataset and whoever consumes it: what the columns mean, at what grain, how fresh the data will be, who owns it, and which changes count as breaking. For most of the time the idea has existed, that agreement has been treated as documentation. A schema in a wiki, a service-level promise nobody measured, and a Slack channel where consumers complained after a column changed under them.
That framing was always a bit limp, and teams could tell, which is why so few of them maintained contracts with any discipline. The cost was real and the payoff was a tidier wiki. What changes the calculation is the arrival of a consumer that does not complain, does not notice, and does not stop.
Three consumers, three different failures
Picture one schema change at the source. A field that used to mean "net amount" is quietly repurposed to "gross amount" by an upstream team solving their own problem. Neither the column name nor the type changes, and the data still flows. Three consumers are downstream, and they fail in three completely different ways.
The human analyst pulls the number into a spreadsheet, glances at it, and something nags. The margin looks off. They have a feel for the right magnitude, built over years, and the new value trips it. They go digging and eventually find the change. Slow, manual, but self-correcting, because a person carries a model of what the number should be.
The dashboard is more brittle and, for that reason, safer than it sounds. If the change renames or drops the field, the chart breaks visibly: an error, a blank panel, a measure that won't resolve. Someone notices because the thing they look at every morning is broken. A loud failure is an annoying failure and an honest one.
The agent is the dangerous case. It was asked a question, it queried the field, it got a number, and the number was the wrong kind of number. Nothing about it looked wrong. The query was valid, the result was well-typed, the response was fluent and confident and formatted to two decimal places. The agent did not have the human's instinct for magnitude or the dashboard's brittleness. It had a value, it used it, and it returned an answer that will survive the meeting because everything about its surface says "correct."
One change, three consumers. The human and the dashboard fail in ways someone notices. The agent only fails safely if a machine-checkable contract sits on its path. Author's illustration.
The agent does not stop
A broken contract does not halt an agent the way a missing column halts a dashboard. The agent keeps going and becomes confidently wrong, and its output is more persuasive than the human's hunch and more polished than the dashboard's error. The failure is silent and the answer is convincing, which is the worst combination a consumer can have.
Why the agent raises the stakes from documentation to runtime
A contract that lives in a wiki protects the human, a little, by giving them somewhere to check when their instinct fires. It does nothing for the agent. The agent never reads the wiki at decision time and would not pause to consult it if it did.
For the agent to fail safely, the contract has to be a thing a machine can evaluate at the moment data is used, not a paragraph a person could read if they thought to. That is the shift. The contract stops being a description of the agreement and becomes an assertion that runs: this field is non-null, within this range, of this meaning, as fresh as promised, and if it isn't, do not proceed to the answer.
The wiki page was advisory. The runtime check is a brake.
This is the same move made years ago without anyone calling it a contract. A certified measure that refuses to when its inputs are missing is a contract enforced at runtime. We just never had to make it explicit, because a human was always there to notice when the dashboard went strange. The agent removes that human, so the assertion has to become explicit and machine-checkable, or there is nothing between a quiet schema change and an automated wrong decision.
The breakage that takes a week and would be one line
I have traced this exact shape of failure more than once, and it wears the same clothes every time, anonymised here to sector and shape. A downstream process depends on a status field from an upstream operational system. For years the field carries a small set of values, and one of them effectively means "closed." An upstream team, modernising their own application, repurposes that value to mean something subtly different, a sub-state that is not really closed. They have no idea anyone downstream leans on the old meaning. Nobody ever told them, because the dependency lives in a transformation written by someone who has since moved on.
Nothing breaks loudly. The data keeps flowing, the types hold, the jobs run green. A monthly figure drifts, someone questions it, and the trace back through the layers takes the better part of a week of careful work to land on a single repurposed code in a source system two hops upstream. The whole failure would have been caught at the boundary by one assertion: this field's allowed values are this set, and a change to them requires a heads-up. Not a platform. Not a governance programme. One checkable statement about one field that mattered, and a way to fire when it is violated.
An API for your data, and the part it can't enforce
I have been using "data contract" as if the term were settled, and it mostly is. Its origin explains both what the idea is good for and what it quietly is not.
The name is borrowed, on purpose, from contracts. The data-engineering version surfaced around 2021 and 2022, in Andrew Jones's work at GoCardless, in Chad Sanderson's writing, and in a template PayPal open-sourced that grew into the now kept under the . The pitch never changed: the same way an API is a contract between two services, a data contract is the agreed interface between whoever produces a dataset and whoever consumes it. Sanderson gave it the sharpest edge. If there is no contract, your consumers are reading your production database's schema directly, and that schema becomes a non-consensual API, an interface nobody agreed to expose, that breaks the instant the producer refactors a table they had every right to think was their own .
Set beside a data product, the contract is the interface, not the whole thing. A data product is a dataset a team owns and publishes for others to depend on; the contract is the agreement fixed to its edge that says what you may rely on. The data-mesh writing that popularised supplied the raw materials, domain ownership, service levels, a stable published surface, without ever using the words "data contract" . So the contract stands apart from both: the smaller, sharper thing that makes either one safe to build on.
Where it gets muddled, and where the muddle starts to matter for , is the line between a contract and a . They are different tools doing different jobs. A contract is an enforceable agreement about how data is shaped and how it behaves: these columns, these types, these allowed values, this , this owner, and which changes count as breaking. A semantic layer is where meaning lives: what "active customer" means, which metric is authoritative, the definitions a consumer reads to interpret a number correctly. One guards structure at the boundary. The other supplies meaning at the point of use. An agent needs both, and the gap between them is where the worst failure hides, because a contract can confirm a field still holds the values it promised and still cannot tell you those values quietly changed meaning.
What goes in the contract
The contracts worth maintaining are small and specific. The useful contents are roughly:
- Meaning and grain. What each column is, in words, and what one row represents. The grain stated in plain language is the single most under-recorded and most consequential thing.
- Allowed values and ranges. The set a status code is permitted to take, the bounds a numeric is expected within. This is what would have caught the anecdote above.
- Freshness. How current the data is promised to be, so a consumer can refuse a stale answer rather than serve it confidently.
- Ownership. Who to talk to, and who is on the hook when it breaks. A contract with no owner is a wish.
- Breaking-change policy. An explicit list of what the producer must not change without telling consumers, and how the warning arrives.
That is it. A contract that tries to describe everything describes nothing anyone maintains. A contract that nails the half-dozen things that decide whether an automated answer is safe is a tool.
The objection, and where the effort actually pays
Contracts add friction, and most small teams will not maintain them. Pretending otherwise is how this idea stalled the first few times it was fashionable. Benn Stancil's objection from that first wave still stings: a contract turns a technology problem into a people problem, and the data team is usually the powerless party, asking a busier upstream team to please sign something . The sharpest recent critique is quieter and harder to wave off, that the practice stayed at the level of classification rather than construction, producing tidy descriptive artifacts instead of interfaces that actually fail when they are violated . Writing a contract for every staging table is ceremony that will be abandoned within a quarter, and rightly.
So I do not argue for contracts everywhere. I argue for them on the handful of datasets that feed a decision or an automation, and nowhere else. The table two analysts use to explore does not need one; if it is wrong, they will notice, because they are humans with instincts looking at their own work. The table an agent queries to authorise a refund, adjust a price, or report a regulated figure needs one, because the consumer there has no instinct and the failure there is silent and expensive. The discipline is knowing which tables crossed the line from convenience to consequence, and contracting exactly those.
What is actually checkable in 2026
It helps to be precise about what the tooling can enforce today versus what is still aspirational, because the gap is the whole risk surface.
Checkable now, cheaply, with tools most teams already run: schema shape, types, non-null, allowed-value sets, numeric ranges, referential integrity, row-count and null-rate drift, and freshness against a load timestamp. If a field has an allowed-value set and the set changes, you can fail the pipeline on it today. None of this is research. The standards even consolidated while the discourse was looking the other way: the Open Data Contract Standard reached v3.1.0 in late 2025 and absorbed its main rival, so there is finally one agreed place to write these rules down . enforces the structural half of a contract at build time, and engines like Soda compile the same standard into checks that actually run .
Not reliably checkable yet: . The field that still passes every structural check because its type, range, and nullability are unchanged, and yet now means something subtly different, the way "net" quietly became "gross." That is the breakage that hurts most and the one no automated check catches, because by every machine-measurable property the data is fine. Catching it still depends on a human who knows the domain, an owner who announces the change, and a breaking-change policy that treats "this column now means something else" as breaking even when the schema is identical. The tooling polices structure. Meaning is the semantic layer's job to hold and the contract's job to defend, and semantic drift is the failure that lives in the join between them, where the contract has run out of properties it can check and the meaning was never written down to begin with.
A brake on the confident consumer
A data contract is not paperwork between teams, and it never really was, even when we filed it as documentation. It is the assertion that lets you trust an automated answer enough to act on it without re-checking it by hand. For a human consumer that trust was supplied by instinct, and for a dashboard by brittleness. The agent has neither, so the trust has to be made explicit, machine-checkable, and placed on the path the agent travels.
Coverage was never the point. Put the brake on the one consumer that will otherwise keep driving confidently after the road has changed.
Final thought
Write contracts for the tables where being wrong is silent and costs something. Skip them everywhere else.
Data Contracts for Humans, Dashboards, and Agents · July 2026 · An opinion piece. The schema-change anecdote is anonymised from delivery work; the read on where contracts pay for themselves is my own argument. Tooling-capability claims are referenced below.
References9
- 1Bitol / Linux Foundation AI & Data, "Open Data Contract Standard (ODCS)", v3.1.0 (released 2025-12-08), project repository and specification. github.com ↗ Accessed 2026-06-28
- 2dbt Labs, "Model contracts" documentation (structural enforcement at build time, dbt Core 1.5+), with "Tests" and "Source freshness". docs.getdbt.com ↗ · docs.getdbt.com ↗ Accessed 2026-06-28
- 3Andrew Jones, "Improving Data Quality with Data Contracts", GoCardless Engineering (Medium), December 23, 2021. medium.com ↗
- 4Chad Sanderson, "The Rise of Data Contracts", Data Products (Substack), August 22, 2022. dataproducts.substack.com ↗
- 5Jean-Georges Perrin, "PayPal open-sources its Data Contract Template", May 1, 2023, later contributed into the Open Data Contract Standard under Bitol. jgp.ai ↗ · github.com ↗
- 6Zhamak Dehghani, "Data Mesh Principles and Logical Architecture", martinfowler.com, December 3, 2020. martinfowler.com ↗
- 7Benn Stancil, "Fine, let's talk about data contracts", benn.substack.com, September 23, 2022. benn.substack.com ↗
- 8Ananth Packkildurai, "Data Contracts: A Missed Opportunity", Data Engineering Weekly, January 20, 2026. dataengineeringweekly.com ↗
- 9Soda, "Data contracts" documentation (soda-core compiles ODCS contracts into executable checks). docs.soda.io ↗ Accessed 2026-06-28