Your Snowflake Schema Is Not a Contract
Picture a failure every data team has met. The revenue dashboard didn't crash. That would have been kinder. Instead it kept rendering, quietly wrong, for eleven days — because a column that had always carried a two-decimal number was rebuilt upstream as text, and everything downstream coerced, rounded, or dropped what it couldn't parse. No alert fired. No reviewer saw it coming. The warehouse did exactly what it was told, because a warehouse's job is to store structure, not to defend meaning.
Your Snowflake Schema Is Not a Contract
Picture a failure every data team has met. The revenue dashboard didn't crash. That would have been kinder. Instead it kept rendering, quietly wrong, for eleven days — because a column that had always carried a two-decimal number was rebuilt upstream as text, and everything downstream coerced, rounded, or dropped what it couldn't parse. No alert fired. No reviewer saw it coming. The warehouse did exactly what it was told, because a warehouse's job is to store structure, not to defend meaning.
We built the CoreModels Snowflake integration for that gap: the distance between what your warehouse enforces and what your team actually means.
The catalog tells you what, never what it means
Snowflake's INFORMATION_SCHEMA is thorough and honest about structure. It will tell you that a table has forty-one columns, that STATUS is VARCHAR, that CREATED_AT is TIMESTAMP_NTZ. What it cannot tell you is anything your team decided: which of the three customer tables is the canonical one, which values STATUS is allowed to take, whether ACCOUNT_ID is a governed reference to ACCOUNTS or a convenience copy that drifted years ago. Structure is queryable. Meaning is oral tradition.
That distinction stays invisible until someone acts on the wrong half of it — a new analyst joins on the plausible-looking column, a contractor "cleans up" a table nobody documented, a migration script assumes an ID is unique because its name ends in _ID.
Where meaning leaks in a Snowflake estate
The leaks are specific, and most Snowflake teams will recognize them immediately:
Keys are declarations, not enforcement. Snowflake accepts PRIMARY KEY and FOREIGN KEY declarations but treats them as informational. Because they don't enforce anything, many teams never declare them at all — which means every *_ID column is a join that somebody, someday, will guess. The relationship intent that shaped the schema is invisible to every tool and every newcomer.
There are no enforced CHECK constraints. The set of values a status column may hold — the thing that decides whether a filter is correct — lives in a wiki page, a Slack thread, or one senior engineer's memory. The warehouse will happily accept a fourth value your dashboards have never heard of.
VARIANT is schema-on-read, which too often means schema-in-nobody's-head. Semi-structured columns are one of Snowflake's best features and one of governance's worst blind spots: the inner shape of that JSON payload is invisible to the catalog, to consumers, and to any AI agent trying to reason about your data.
Comments are optional, so most tables have none. An undocumented table isn't just unfriendly; it actively resists governance, because there is nothing to audit a change against.
And change is silent. An ALTER TABLE or a CREATE OR REPLACE lands in seconds, with no gate between the person making the change and the hundred downstream consumers who inherit it.
What a fix has to look like
None of this is fixed by another catalog page, because catalogs describe; they don't commit. What's needed is closer to a contract with teeth:
- The intended meaning — identities, types, allowed values, keys, references, lineage — has to live somewhere the next
CREATE OR REPLACEcannot overwrite. - Getting it there cannot require handing warehouse credentials to yet another vendor.
- Reality has to be compared against intent continuously, producing findings a reviewer can act on — not a dump, a diff.
- And the comparison has to run where change is actually reviewed: in CI, on the pull request, before the change ships.
What we built
CoreModels builds that contract from artifacts you already have. You run three documented queries in Snowsight — one over INFORMATION_SCHEMA (required), one capturing SHOW PRIMARY KEYS and SHOW IMPORTED KEYS, one over ACCOUNT_USAGE.OBJECT_DEPENDENCIES — and upload the JSON results. No live connection, no credentials shared, ever.
From those extracts, import builds a governed model: each table and view becomes a governed Type identified as DB.SCHEMA.TABLE, each column becomes an Element with its native Snowflake type preserved exactly, declared primary keys become uniqueness checks, declared foreign keys become governed references, and object dependencies become lineage. Comments become descriptions — finally load-bearing.
Then the audit does what the warehouse never could: it compares. Coverage findings show what exists in the estate but isn't governed yet. Drift findings — field-type-drift, field-removed, dataset-removed, enum changes — show where reality has moved away from intent. And conformance findings target exactly the leaks above: semi-structured-column flags VARIANT, OBJECT, and ARRAY columns carrying ungoverned data; key-column-undeclared flags key-shaped columns with no declared key; table-no-comment flags the undocumented. The report comes back both machine-readable and as pull-request-ready markdown, and one number carries the gate: when the error count is greater than zero, the change violates governed meaning and CI fails the build. A status badge — green, yellow, red — makes the current state visible in any README.
That eleven-day silent breakage becomes a one-line finding on the pull request that would have caused it: the field drifted from the governed type, here is the subject, here is the severity, here is the diff of meaning. The reviewer decides — which is the whole point. The warehouse enforces structure; your team owns meaning; the audit makes the difference between them impossible to miss.
Your Snowflake schema is not a contract. But it can have one — one built from three queries you run yourself.
To try it against your own schema, start with the CoreModels Snowflake quickstart in our docs — it contains the exact extraction queries and API calls end to end.