For a long time I believed data contracts were close to the answer, and I told people to start there. The problem I was trying to solve was ownership. In most organizations the database schema has become a kind of non-consensual API. Downstream teams build models and reports on top of a producer's table, the producer never agreed to serve any of that, and one ordinary schema change quietly breaks the pipeline that happens to generate most of the revenue. A contract fixes that at the boundary. It turns the producer's output into an API-like agreement that the engineer emitting the data owns and the consumers depend on, and the first time you watch one catch a breaking change before it ships, the idea sells itself. So I told teams to pick one impactful use case, put a contract on it, and bring producers and consumers together around that boundary.
I spent a few years doing exactly that with organizations that wanted contracts everywhere. I watched what happened when they tried to push past a few critical boundaries toward the kind of coverage where someone could honestly tell an auditor yes, we are there. The closer I looked, the clearer it became that they were not going to get there, and not because they lacked budget or talent. Some of them had plenty of both.
This post is the argument I arrived at by the end of that. Complete contract coverage in a large enterprise is not a tooling problem you can grind your way through. It was never going to be, because the binding constraint is not technical. And the thing you actually needed underneath the contracts all along is lineage, which is also, as it turns out, the most reliable path to the contract coverage you wanted in the first place.
What contracts are genuinely good at
I want to be fair to contracts before I take anything away from them, because the value is real and I am not arguing against it.
A data contract is a codified agreement about data that a producer and a consumer both already know matters. For the handful of elements where everyone agrees that if this breaks, the business goes down, a contract is exactly the right control. It takes a known, agreed, critical boundary and turns it into something enforced automatically, on every change, without anyone having to remember to check. That is a genuine capability, and the teams that apply it to their most important boundaries are right to do so. Keep contracts for precisely that. Nothing below is a reason to stop.
The data that hurts you is the data nobody flagged
There is an old framing, usually attributed to a former US Secretary of Defense, that divides what we deal with into known knowns, known unknowns, and unknown unknowns. It is a useful way to see where contracts help and where they cannot.
Contracts do their best work on the known knowns. A field everyone understands, on a boundary everyone agrees is critical, governed by an expectation everyone has discussed. They help less with the known unknowns, the data you are aware of but do not fully understand, because writing a contract requires you to state what correct looks like, and you cannot state it for data you have not yet figured out. They do almost nothing for the unknown unknowns, the data nobody thought about at all.
That last category is the problem, because the data that fails an audit or quietly poisons a model is rarely the data someone understood well enough to nominate for a contract. It is usually the field nobody thought to flag, produced by a service two teams away, consumed by a model whose owner never knew the field existed. Contracts are a mechanism for protecting things you already decided to protect. The failures that hurt most come from the things you never knew to look at.

The barrier is organizational before it is technical
The hard part of contract coverage is not the spec, the registry, or the validation. The hard part is that complete coverage requires organization-wide agreement, and organization-wide agreement on almost anything is rare.
A contract enforces what people have already agreed about a piece of data. It cannot produce the agreement. That distinction is the whole problem. The enforcement is automatable, and modern tooling automates it well: once two teams have settled what a field means, who owns it, and what correct looks like, software can check that boundary on every change forever. What software cannot do is reach across a bank and get those teams to settle the question in the first place. Consent between teams with different incentives, different deadlines, and different definitions of correct is structural and cultural work, and the organization keeps moving underneath whatever agreement you reached. You can automate the enforcement of a contract. You cannot automate the consent the contract is supposed to encode. Better tooling lowers the cost of the step that was never the one stopping you.
The practitioners who actually tried to roll contracts out across an organization describe the same wall, and it is worth listening to them rather than to vendors. Adrienne Vermorel, summarizing the field, put it plainly: data contracts are a people problem dressed in YAML syntax, and the teams that succeed treat the organizational change as the primary work and the tooling as secondary. She has also described the failure mode directly: a company-wide standard is proposed, a specification document is written, and six months later the only contracts that exist are the ones the proposer wrote themselves.
Parth, writing about why the agreement does not hold, framed the contract as a social object. It codifies an agreement between teams with different incentives and different definitions of correctness, and like any agreement between parties with asymmetric power, it only holds when both sides believe there are real consequences for breaking it. A YAML file does not create that belief. Organizational structure does, and most organizations are not arranged to supply it.
The public record points the same way. The best-documented successes cap well short of everything. GoCardless reported roughly thirty contracts in six months, covering fifty to sixty percent of their asynchronous inter-service communication, and described it as a big culture shift that is easy to let slide into something people feel they have to do rather than something they want to do. Thomas Nys wrote up a much-cited rollout whose title is literally about getting to sixty percent coverage, and that sixty percent is of asynchronous data communication, not of the organization. These are the successes. They are real, and they are partial, and the partiality is structural rather than a sign that the teams did it wrong.
My own reversal is the strongest version of this. After talking to dozens of companies, the conclusion I could not avoid was that what is required for a successful producer-defined contract implementation often does not align with the organizational maturity of the business, and that an application developer will never comprehensively understand how their data is being used downstream. Convoy, where I worked on this, needed a dedicated team driving adoption, not a side project. Change is constant in three places at once, in the code, in the business, and in the org chart, so the agreement you reached last quarter already describes a company that has since reorganized, inherited services, and moved on. Once no single team can see the whole system, no single team can drive complete agreement across it, and no amount of automation produces that agreement on its behalf.
I thought contracts could be unit tests
The mental model I had wrong is worth naming, because I suspect others share it. I assumed contracts could behave like unit tests: cheap, everywhere, enforced automatically on every change, a green checkmark that gradually covers the whole codebase.
But unit tests and even integration tests rarely span an entire organization, and they rarely cover the seams between loosely connected services owned by different teams. They cover a repository because a repository has one owner and one test suite. Expecting contract coverage to blanket a bank the way a test suite blankets one repository asks a local mechanism to do a global job. The data's journey is not local. It crosses dozens of independently owned services before it ever lands somewhere you can observe it, and a control that lives at one boundary was never going to cover a path that long.
Contracts do not give you provenance

Even in the rare slice where contract coverage is genuinely complete, all that buys you is good provenance for that slice. Everywhere coverage is partial, which is almost everywhere, the data still fails the audit, still fills the model with garbage, and still breaks when something upstream changes. A contract sitting at a boundary checks that the data crossing it matches an agreed shape. It is not a map of where the data came from.
Provenance is a property of the code that produced and moved the data, and it is recovered by reading that code. Ask the questions that actually come up: where did this field come from, what logic shaped it, which contract if any does it cross on the way out, what depends on it, and what breaks if it changes. A contract can answer the third question for the one boundary it governs. The rest were never going to come from a contract nobody wrote, for data nobody thought to flag.
What I argue for now
What I argue for now is provable provenance through automated, code-level lineage across everything that matters, which at a minimum means everything on the balance sheet and everything teams actually depend on, with contracts reserved for the known, agreed criticals and placed on top of that map.
The reason this is a different bet from full contract coverage is that lineage can be read from the code that already exists, rather than negotiated team by team. Reading code does not require agreement. It does not wait for a producer two floors away to adopt a standard, attend the working group, and maintain the schema through their next reorg. Automation can reach a level of completeness on lineage that manual agreement will never reach on contracts, because it is doing a fundamentally different kind of work. One reads what is already true. The other tries to make hundreds of teams agree on what should be true and keep agreeing as everything changes.
The goal was never coverage. It was trustworthy data.
This part took me longest to see, and it reframes everything above. The thing I was actually chasing with contracts was never a coverage number. It was data I could trust and prove: data I could stand behind in an audit, feed to a model without poisoning it, and trace when something looked wrong. Contracts were a means to that end. Somewhere along the way the means became the goal, and teams started measuring themselves on percent-covered instead of on whether they could actually answer where a number came from.
Provenance is the goal. Lineage read from code is how you get it, and it does not wait on agreement. Once you can see where data is produced and where it flows, two things follow. You can prove the origin of any figure that matters, contract or no contract, which is the thing an auditor, a model owner, and a debugging engineer all actually need. And you can see which boundaries are genuinely load-bearing, so the contracts you do write land on exactly the lines worth holding instead of being spread thin across a thousand interfaces nobody can defend. Lineage draws the map. Provenance is what the map gives you. Contracts hold the few lines on it where people have agreed and the agreement is worth enforcing.
So I did not give up on contracts. I keep them for the known, agreed criticals, because where people genuinely agree, a contract is the right control. But I stopped treating coverage as the finish line. The finish line is data you can prove: provenance for everything on the balance sheet and everything teams depend on, with contracts sitting on top of that map where the agreement already exists.
This is the problem we work on at Gable: lineage read from the code that produces data, so a team can prove where a number came from and put the contracts that are worth the fight in exactly the places that carry weight. I changed my mind about where to start, and about what I was really after. The answer was never coverage. It was provable data.
Good luck.
-Chad






.avif)

.avif)
%20(1).avif)