Follow One Column: Where the Machine Stops and a Person Starts
Trust in a governance tool is not established by a promise on a landing page. It is established by being able to point, precisely, at the places where automation ends and human judgement begins — and by those places being the same ones every time.
Follow One Column: Where the Machine Stops and a Person Starts
Trust in a governance tool is not established by a promise on a landing page. It is established by being able to point, precisely, at the places where automation ends and human judgement begins — and by those places being the same ones every time.
So let us follow a single BigQuery column through CoreModels: from the extract, into the governed model, through an audit, and back out as DDL. At every step, the same question. Who decided?
Step 1 — the column leaves your project on your terms
analytics.events.event_value, typed NUMERIC, is_nullable = NO, with a description somebody
wrote last year. It reaches CoreModels because an engineer ran a documented query against
INFORMATION_SCHEMA and uploaded the JSON result as an artifact named information_schema.
That is the entire ingress path. CoreModels never holds your Google credentials and opens no connection to your GCP project. A live-sync capability exists in the connector capability model and is deliberately deferred: we would rather the boundary be visible and slightly inconvenient than invisible and trusted by default. You can read the artifact before you send it.
Who decided? You did, when you chose what to export.
Step 2 — the import adds, and refuses to overwrite
The column becomes a governed Element on a governed Type identified as project.dataset.table. Its
is_nullable = NO becomes a NotNull check. Its exact native type string — NUMERIC, not our
interpretation of it — is preserved on the Google BigQuery Metadata mixin attached to the node.
Now the important part. Import is additive. New tables and columns are created; nodes that are
already governed are never mutated and never deleted, no matter what the fresh extract says. The
import response tells you so numerically: datasetsAdded alongside datasetsSkippedExisting. If
the estate has diverged from the model, an import does not quietly "fix" it in either direction.
(Vendor metadata values — the native type string, materialization, physical name — are refreshed on
re-import, because that is estate bookkeeping rather than governed meaning, and we keep those two
categories apart on purpose.)
Who decided? Nobody yet. Structure arrived by machine; meaning has not been touched.
Step 3 — the approximation is recorded, not hidden
NUMERIC is an exact decimal type. The governed model represents it as a double, which is close and
not identical — so the mapping is marked as approximated rather than presented as exact, as are
BIGNUMERIC, DECIMAL, BIGDECIMAL, BYTES, TIME, GEOGRAPHY, INTERVAL and RANGE.
STRUCT, ARRAY and JSON columns carry inner schemas the extract cannot see, so they are
governed as approximated strings, and a dedicated audit rule (semi-structured-column) warns on
every table where those ungoverned inner schemas hide.
Lossiness in CoreModels is a success channel, not an apology. A successful import can still report
exactly what it approximated or dropped, and does — each record carrying a kind, the path it applies
to, and an explanation in words. Even operational limits are reported plainly: on a very large
estate, if the encoded snapshot exceeds the storage cap, the import completes and says
snapshotStored: false, with a lossiness record explaining that fresh-artifact audits still work
while snapshot-based re-audits have nothing to run against.
The same discipline governs what BigQuery itself lacks. BigQuery enforces no primary or foreign keys, so the connector reads none and — more importantly — invents none. A governance layer that fabricates keys the warehouse never enforced is not documenting your estate; it is writing fiction about it.
Who decided? The rules did, visibly, and they told you what they gave up.
Step 4 — drift arrives as evidence, not as an edit
Six weeks later the column's type changes upstream. The next audit compares the fresh extract
against the live governed graph — there are no stale stored fingerprints in the comparison; the
graph itself is the baseline — and emits a finding: section Drift, severity Error, code
field-type-drift, subject analytics.events.event_value, message "Field type changed since the
last import", detail carrying the governed type and the estate type side by side.
That finding does not change anything. The audit verb is strictly read-only and runs at Viewer
role. Even recording the run into the rolling history is opt-in — the caller sets recordHistory
explicitly, because the audit stays read-only unless asked. The one deliberate exception proves the
rule: the re-audit verb, which checks the stored estate snapshot against the current governed model,
always records its run, because leaving a trail is its entire purpose.
Everything the trail produces — the history, the counts and codes per run, the artifact fingerprint, the green/yellow/red/gray badge — is bookkeeping about governance. None of it touches governed meaning.
CoreModels can go one step further and hand you a proposal: given a fresh extract, it returns a plan in which every operation is classified — new material, estate bookkeeping, or meaning-affecting — with the estate and governed values aligned for review and the lossiness each operation would incur declared up front. It writes no governed meaning. It is a document to argue with.
Who decided? Still nobody. The system has produced evidence and, at most, a proposal.
Step 5 — the change lands through your review process
Someone reads the finding and decides what the model should now say. That change is made in CoreModels deliberately, by a person with the rights to make it — import is an Admin-role operation; audit, re-audit, history, badge and generate all run at Viewer.
Then the loop closes outward, and stops at a reviewable artifact. Generation emits
coremodels_bigquery_tables.sql from the governed model — CREATE TABLE IF NOT EXISTS statements,
NOT NULL where the model requires it, OPTIONS(description=...) on tables and columns, governed
allowed-value sets and references written into those descriptions because BigQuery enforces neither
keys nor check constraints. Views are skipped, with the skip declared as lossiness, because
generating derived objects would overstate what the model knows.
Nothing is executed against your project. The script's own header states the posture: meaning changes belong in CoreModels; regenerate this script rather than editing it. You review the diff and deploy it through the process your team already trusts.
Who decided? A person, twice — once about the meaning, once about the deployment. That is the design.
Why the sequence matters
Each step alone looks like modesty. Together they are the trust contract: credentials stay yours, governed nodes change only when a person changes them, every approximation is on the record, every drift claim is coded and fingerprinted, and anything that reaches your warehouse passes through your own review. Governance you can audit is the only kind worth failing a build on.
The Google BigQuery quickstart spells out every call in this path, including what each response contains.