Five promises every dataset should make before an AI agent reads it
An AI support assistant gave a customer the wrong refund amount. The model was fine. The prompt was fine. The problem was one column.
Upstream, a team changed amount from dollars to cents. Nobody told the pipeline. Every number the assistant read was now 100 times too large, and it repeated them politely.
This is the kind of failure a data contract prevents.
A data contract is a written promise between the people who produce a dataset and the people who use it.
It says what the data looks like, what values are allowed, how fresh it will be, and who to call when it breaks.
Think of it like an API for a table. A web API has a fixed request and response shape. A contract gives a table the same kind of shape.
1. Shape. The columns, their names, and their types. amount is a DECIMAL in dollars, not an integer in cents.
2. Valid values. status is one of open, closed, or refunded. amount is never negative.
3. Completeness. ticket_id is never NULL and never duplicated.
4. Freshness. New rows land within one hour. If the newest row is older than that, something is wrong.
5. Ownership. A named team owns the table and is told when a check fails.
None of this is new. What is new is that AI systems read data without a human looking at it first. A dashboard with a wrong number gets noticed. An agent with a wrong number just answers.
flowchart LR
A[Source system] --> B[Bronze table]
B --> C{Contract checks}
C -- pass --> D[Silver table]
C -- fail --> E[Quarantine table]
D --> F[AI agent or dashboard]
E --> G[Owner alerted]Delta tables can store some promises directly. The table itself then refuses bad writes.
CREATE TABLE IF NOT EXISTS workspace.default.support_tickets (
ticket_id STRING NOT NULL,
status STRING NOT NULL,
amount DECIMAL(10, 2),
created_at TIMESTAMP NOT NULL
);
ALTER TABLE workspace.default.support_tickets
ADD CONSTRAINT valid_status CHECK (status IN ('open', 'closed', 'refunded'));
ALTER TABLE workspace.default.support_tickets
ADD CONSTRAINT non_negative_amount CHECK (amount >= 0);Now try to insert a bad row:
INSERT INTO workspace.default.support_tickets
VALUES ('T-100', 'pending', 25.00, current_timestamp());Delta rejects the whole write and tells you which constraint failed. Bad data never reaches the table.
Freshness and duplicates need a small check of their own, because they depend on many rows, not one:
SELECT
COUNT(*) - COUNT(DISTINCT ticket_id) AS duplicate_ids,
timestampdiff(MINUTE, MAX(created_at), current_timestamp()) AS minutes_since_last_row
FROM workspace.default.support_tickets;If duplicate_ids is above zero, or the minutes are above your promise, stop the pipeline before the AI layer reads it.
An LLM does not know your units, your codes, or your rules. It trusts what it is given.
A contract moves that knowledge out of people's heads and into the table. The agent then reads data that has already been checked, and the failure shows up as a clear error for an engineer, not a wrong answer for a customer.
status = 'pending'.It takes about ten minutes, and you will remember it the next time a column quietly changes.