A Governed dbt Estate, One Week In
Here is the same Thursday, twice.
A Governed dbt Estate, One Week In
Here is the same Thursday, twice.
Before. A pull request lands that reworks the orders mart. The reviewer scrolls through four hundred lines of SQL and YAML, approves it because the tests pass, and moves on. Two of the changed columns feed a churn model owned by another team; nobody on the PR knows that. The schema.yml says the model has nine columns; it now has eleven. A week later someone asks in a channel whether order_status still includes returned, and three people give three answers.
After. The same pull request opens, and CI compiles the manifest and audits it against the governed model. A comment appears on the PR within a couple of minutes: one error — a column's type drifted from the governed definition — two warnings about key-shaped columns with no tests, and a note that a newly added column isn't governed yet. The build fails on the error. The author fixes the type, the audit goes green, and the reviewer approves a change whose semantic impact they can actually see. Nobody asks about order_status in a channel, because the allowed values are a governed taxonomy anyone — human or AI agent — can look up.
That delta is the product. Let us walk through the week.
Monday: the estate becomes visible
The first import takes minutes: you post the manifest.json your project already produces (plus the catalog if you want warehouse-real column types), and CoreModels builds the governed picture — models, seeds, snapshots and sources as types, columns as elements, accepted_values as taxonomies, relationships as references, and the dependency map as lineage. The response is honest bookkeeping, not a black box: how many datasets and fields were added, how many lineage edges landed, and an explicit list of anything the import had to approximate.
For the first time, "what do we actually have?" has a queryable answer. A status call tells you how many datasets are governed. The lineage that used to live only inside dbt's docs site is now part of the same model as the definitions — so "what depends on this column's type?" stops being a research project.
Tuesday: the badge and the gate
The repo README gets an SVG badge served straight from the audit history: green when the last run was clean, yellow for warnings, red for errors, gray before any runs exist. It is a small thing that changes behavior — schema health becomes something everyone sees on every visit, not something one platform engineer knows.
The CI gate goes in the same day with the ready-made GitHub Action we ship: compile the manifest with dbt parse (no warehouse connection needed for the audit), post it to the machine-to-machine audit endpoint with a user API key, fail the build when the error count is above zero. Findings arrive as inline annotations and a sticky PR comment with the full human-readable report. Teams that want a stricter posture fail on warnings instead.
Wednesday: a meaning change, done once
A steward decides order_status gains a value: partially_refunded. In the before-world this is a scavenger hunt — update the test in one repo, the docs in another place, tell the BI team, hope. In the after-world it is one change to the governed taxonomy, made deliberately by a human with the right role.
Then the loop closes. CoreModels generates a contracts file from the governed model — enforced dbt model contracts with per-column data types, not-null constraints, unique tests, accepted_values drawn from the taxonomies and relationships drawn from the references. That lands in the dbt repo as a normal pull request: engineers review a contract diff instead of hand-editing YAML, and dbt itself enforces the result from then on. Change meaning once; every derived artifact follows.
Thursday: drift in both directions
The gate catches estate-side drift: a PR that would change what a column means fails before merge. But drift has a second direction — the governed model itself evolves, and yesterday's estate may no longer conform. One call re-audits the estate snapshot stored at import time against the current governed model, no fresh artifacts required. After Wednesday's taxonomy change, the re-audit reports exactly which models are now out of step with the new meaning, and the run is recorded in the history.
That history is the part teams don't know they need until they have it: a rolling trail of audit runs — when, what triggered it, how many errors and warnings, which finding codes — per vendor project. "Are we getting better or worse?" becomes a trend you can read, not a feeling.
And there is a third direction most dbt tooling cannot see at all: drift above the project. Model contracts do not apply to sources, so when the warehouse schema moves underneath sources.yml — an ingestion tool renames a column, a platform team retypes one — nothing in dbt notices until a run fails. Because the governed workspace is not dbt-only, the fix is structural: import the warehouse estate itself alongside the dbt estate (a couple of INFORMATION_SCHEMA queries, no credentials handed over), reconcile the two so each dbt source is pinned to the physical table it reads, and let the same audit machinery watch the upstream side on its own schedule. The boundary that contracts can't reach gets the same gate, badge and history as everything else.
Friday: the questions answer themselves
By the end of the week the texture of daily work has shifted. An analyst wants to know whether customer_id on a mart is guaranteed to resolve — the governed reference says yes, and the generated contract tests it. An engineer planning a refactor checks lineage before touching a column instead of after breaking one. A new joiner reads the governed model instead of interviewing veterans. An AI assistant connected over MCP answers "which models feed the revenue exposure, and what type is order_total?" from governed fact rather than plausible guesswork.
Nothing about how you build changed: same repo, same dbt build, same review flow, no credentials shared, nothing new to run in production. What changed is that the estate now has a definition to be checked against — continuously, on every PR, in both directions, with the receipts recorded.
The before-Thursday is where most dbt teams live today. The after-Thursday takes roughly a morning to set up: the dbt quickstart in the CoreModels docs goes from manifest.json to a passing CI gate step by step.