dbt logoUse case

The Consumers dbt Can't See

Ask a dbt team who consumes their marts and you get a confident list: the BI dashboards, the declared exposures, maybe a semantic layer. Ask the *warehouse* the same question and the list is longer and stranger — a reverse-ETL job syncing `customers` into a CRM, a feature pipeline reading `orders` into a model store, another team's scheduled export three schemas away. Every one of those readers depends on your mart's schema. Not one of them is protected by anything dbt can enforce.

The Consumers dbt Can't See

Ask a dbt team who consumes their marts and you get a confident list: the BI dashboards, the declared exposures, maybe a semantic layer. Ask the warehouse the same question and the list is longer and stranger — a reverse-ETL job syncing customers into a CRM, a feature pipeline reading orders into a model store, another team's scheduled export three schemas away. Every one of those readers depends on your mart's schema. Not one of them is protected by anything dbt can enforce.

That is not a criticism of model contracts. Contracts do their job: when a contracted model changes shape, your dbt build fails, in your repo, for your engineers. But a contract is a promise, and dbt only shows the promise to people running dbt. The reverse-ETL job doesn't run dbt build. The ML pipeline can't read your schema.yml. When you retype a column deliberately and correctly — governed change, reviewed PR, green build — the external consumers find out the way they always find out: something breaks downstream, on their side, on a Tuesday.

"We have a data contract" usually means "we have a document"

The data contract movement saw this problem clearly, and it settled the format question: the Open Data Contract Standard, stewarded under the Linux Foundation, is the YAML a modern contract is written in — ODCS v3.1.0 as of late 2025. What the movement has not settled is enforcement. Most contract tooling today stores contracts: the document lands in a catalog, gets a version number, and sits there as documentation. Nothing continuously checks that the schema it describes is still the schema that ships. A consumer holding the contract holds a claim about the past.

Two failure modes follow. The contract goes stale silently — the mart evolved, nobody regenerated the document, and the consumer is now integrating against fiction. Or the contract is maintained by hand, which means it is one more YAML file duplicating what the SQL already says, decaying at exactly the rate the schema.yml files it was supposed to improve on decay.

Generate the contract from the thing the audits enforce

The CoreModels approach is to make the contract a derived artifact of governed meaning, not a parallel document. The flow for a dbt team:

  1. Import the marts. Post target/manifest.json (plus the catalog for warehouse-real column types) to the dbt import endpoint. Models become governed types, columns become elements with types, accepted_values become taxonomies, relationships become references. No warehouse credentials — build artifacts only.
  2. Audit and record. The first audit establishes the baseline and lands in the rolling history. From here on, the CI gate and scheduled re-audits keep checking the estate against governed meaning, and every recorded run carries a timestamp, a fingerprint of the artifacts examined, and per-code finding counts.
  3. Export the contract. From the governed model, CoreModels exports an ODCS v3.1.0 document through its transformation engine — the same neutral model that generates dbt contract YAML in one direction produces a standards-format external contract in the other. One source of meaning, two enforcement surfaces: dbt-native contracts for the people inside the project, ODCS for everyone outside it.

The part that changes the conversation with consumers is the trail. Because the contract is generated from the same definitions every audit checks, the audit history is the contract's enforcement record: a dated sequence of runs, each one evidence that the estate did — or did not — still match the meaning the contract came from. When drift lands, it shows up as findings with stable codes, the status badge goes red, and (if the project opted in) a Slack notification fires on the clean-to-dirty transition. "Does this contract still hold?" stops being a question about a document's modification date and becomes a question the history endpoint answers with receipts.

The round trip matters too

Contracts also arrive from outside — a partner publishes an ODCS document, a platform team standardizes on contract-first design. The ODCS coder decodes as well as encodes, so an external contract can be imported into the governed model and audited against, the same as any estate. A contract nobody governs is a wish; a contract inside the governed loop is a definition with an enforcement history, whichever direction it traveled first.

None of this asks the consumers to adopt anything. The ODCS file is plain, standard YAML they can read with any tooling or none; the badge is an SVG in a README; the history is there if they ask. The work on your side is one import, one audit, one export — and the discipline, which the machinery now carries instead of a human, of never letting the promise and the schema drift apart silently.

The import and audit mechanics are the standard dbt connector flow, covered end to end in the dbt quickstart that ships with CoreModels.