Post-incident reviews of AI system failures follow a pattern: the model was fine. The prompt was fine. What changed was three teams upstream — an application engineer renamed order_status values during a refactor, the change deployed on a Tuesday, and by Friday the churn model was scoring on garbage and the RAG index was embedding half-empty documents. Nobody did anything wrong by their own lights. That's precisely the problem: the pipeline had consumers but no contract.
Data contracts are the boring, transformative fix. Here's what they are, what belongs in one, and how to introduce enforcement without declaring war on your producer teams.
What a data contract actually is
A data contract is a versioned, machine-readable agreement between a data producer and its consumers, covering four things:
- Schema — fields, types, nullability, allowed enum values, key uniqueness.
- Semantics — what the data means: units, timezones, whether
revenueis gross or net, whether deletions arrive as tombstones or hard deletes. Most contract violations that hurt are semantic, not structural: the column is still aDECIMAL, it just means something different now. - SLAs — freshness (data lands within N minutes of the event), completeness (≥99.5% of expected volume), and availability of the interface itself.
- Change policy — how evolution happens: what's additive (new nullable fields, fine), what's breaking (renames, type changes, enum removals), notice periods, and deprecation windows.
The operative words are versioned and machine-readable. A contract that lives in a wiki is documentation; a contract that lives in a repo, expressed in a schema language, checked in CI, and enforced at runtime is infrastructure:
contract: orders_events.v3
owner: team-commerce
schema:
order_id: { type: string, required: true, unique: true }
status: { type: enum, values: [placed, paid, shipped, delivered, cancelled] }
amount_usd: { type: decimal, required: true, min: 0, semantics: "gross, USD, tax-inclusive" }
occurred_at: { type: timestamp, semantics: "UTC, event time not ingest time" }
sla:
freshness: 15m
completeness: 99.5%
evolution:
breaking_changes: require 30-day notice + consumer sign-off
Why AI workloads raise the stakes
Classic analytics degraded gracefully under bad data — a dashboard looked odd, an analyst noticed. AI consumers fail silently and downstream:
- Feature pipelines happily compute features from corrupted inputs. The model doesn't error; its predictions just get worse, and you find out via business metrics weeks later. A null-rate spike in one high-importance feature is invisible in a model's HTTP status codes.
- RAG corpora inherit every upstream defect at query time. Documents ingested with a broken metadata field lose their entitlement tags or their freshness ordering; the retrieval layer serves stale or unauthorized content with full confidence.
- Training sets snapshot upstream defects permanently. A two-week enum drift in a source table becomes a permanent artifact of every model trained on that window, and no amount of downstream monitoring will explain why the model behaves oddly on that segment.
The common thread: AI systems convert data defects into behavior defects, and behavior defects don't stack-trace back to the offending column. Contracts move detection from "weeks later, via a business metric" to "at the point of change, via a failing check."
Enforcement: the three gates
A contract without enforcement is a vibe. Enforcement happens at three points, in increasing order of runtime cost:
Gate 1 — CI, at the producer. The contract lives beside the producer's code. A schema migration or a change to event-emitting code that violates the contract fails the producer's build, before deployment. This is the cheapest and most effective gate because it converts a data incident into a failed PR — and it's what makes contracts producer-owned rather than a downstream complaint mechanism.
Gate 2 — the pipeline boundary. Ingestion validates arriving data against the contract: types, enums, ranges, null rates, volume against expected baselines. Violations route to a dead-letter queue with the contract clause cited; clean data flows on. The critical design decision is quarantine, don't crash: one malformed partition shouldn't halt the platform, but it also must never silently merge into the lakehouse. At one logistics client, boundary validation now quarantines roughly 0.02% of daily volume — and every quarantine event is a defect that previously would have reached the feature store.
Gate 3 — consumption-time assertions. Feature pipelines and embedding jobs assert the specific invariants they depend on (this join key is unique; this timestamp is monotonic; this text field is non-empty for ≥99% of rows). These are your last line of defense and your best diagnostics — when Gate 3 fires and Gates 1–2 didn't, the contract is missing a clause, and you add it.
Rolling contracts out without a civil war
The failed pattern: a platform team mandates contracts for all 400 tables, producers experience it as bureaucracy, adoption stalls at the kickoff deck. The pattern that works is consumer-driven and incremental:
- Start from the AI systems' actual dependency graph. Trace your top models and RAG pipelines back to their sources — typically 15–30 tables cover the highest-value consumers. Contract those first.
- Write the first draft yourself. The consuming team drafts the contract from observed data (profiling tools generate 80% of it), then negotiates it with the producer. Producers accept contracts they get to edit far more readily than contracts they're assigned.
- Turn enforcement on progressively. Weeks 1–4: monitor-only, violations logged, dashboard shared. Then Gate 2 quarantine. Then Gate 1 CI checks, which by that point defend the producer from their own surprises — and that's the moment producers become the contract's advocates rather than its subjects.
- Make ownership visible. Every contract has a named owning team and a pager route. Data quality without ownership is a suggestion.
The economics are unambiguous once you've watched both worlds. Retraining a model on a corrupted window, re-embedding a 2M-document corpus, or explaining to a regulator why a decision system consumed unvalidated data — each costs more than a year of contract maintenance for the entire dependency graph. Contracts are how data engineering stops being the tier everyone blames and becomes the tier everyone builds on — which is what "AI-ready data" actually means, once the slideware is set aside.
WRITTEN BY
Sanjay Mehta
VP of Engineering
Sanjay runs Ilmora's delivery practice — data platforms, cloud, and automation programs for regulated industries. Sanjay writes about data engineering, DevOps, and the operational realities of shipping enterprise systems on schedule.
