Governance that outlives the people who wrote it
Most data governance fails the same way. Someone writes a naming standard, circulates it, gets nodding in a meeting, and eighteen months later half the estate follows it and half does not, because the three people who cared have moved on and nothing in the system ever enforced it. The document was never the mechanism. The mechanism is a convention that is cheaper to follow than to ignore, an owner whose name is on a specific object, and a contract that makes a change visible to everyone it affects before it happens.
This session covers three things you can actually decide: how many words your organisation is allowed to have for one concept, what a name is required to tell a reader, and what the interface between a team that produces data and the teams that consume it must state in writing. The examples come from this course's own running dataset - a marketplace called Bazaar, 12 merchants, 985 orders and 1,060 payment attempts across 2026-04-01 to 2026-06-29, in SGD - and its published contract, which is a real file you can read at semantic/contract.yaml.
One concept, one word, everywhere 6 min live
Bazaar's business says merchant. So nothing anywhere in the estate is allowed to say vendor, seller, partner or supplier for the same thing. This sounds like a style preference and is not. Every extra word for one concept is a place where two teams can build two different numbers and both be right, and a place where a new analyst has to ask a question that should never have existed.
The word you standardise on is the word the business already uses out loud, not the word the source system happened to use and not the word the engineer preferred. That direction matters: you are renaming the data to match the business, never the other way round.
LiveThe synonym map, and why it is the cheapest thing you will ever fund4 min▶
A synonym map is a short list with two columns: what the business says, and which defined thing in the model answers it. Bazaar's version lives in its contract and is roughly a dozen entries long. It maps revenue, sales and topline to one metric; GMV to a different one; basket size and average basket to average order value; take rate to commission; failure rate to decline rate; lost revenue to abandoned cart value.
- It costs nothing to build. No migration, no downtime, no renaming of anything already in production. You are documenting a mapping that already exists implicitly in people's heads, badly.
- It pays out immediately in three places. New joiners stop asking. Analysts stop guessing which column a stakeholder meant. And a text-to-SQL tool stops guessing too, which is the entire subject of session a6.
- It surfaces the real disagreements. The hard part is not writing the map, it is discovering that two people wanted revenue pointed at two different metrics. That discovery is the value. It was always true; the map just makes it a decision with a date instead of a recurring meeting.
LiveWhat to do about the words already in production3 min▶
You will not be renaming a production column this quarter, and you should not pretend otherwise. The realistic sequence, in order of cost:
- Freeze the vocabulary going forward. Everything new uses the business word. This is free and stops the problem growing, which is most of the win.
- Publish the map over the mess. The old names stay; the map tells everyone which one is canonical and which are legacy. A reader can now navigate the estate without a guide.
- Rename only at the published layer. The tables consumers actually read get the business word. Deep internal tables can keep their history. You get 80% of the clarity for 10% of the migration.
- Retire a legacy name only when you already have a reason to touch that object. Renaming for its own sake buys clarity and spends trust; renaming during work you were doing anyway buys clarity for free.
The one thing not to do is run a big-bang estate-wide rename as its own project. It has a long, invisible payback, it breaks things for people who did not ask for it, and it is the classic way a data team spends a quarter and comes out with nothing a stakeholder can see.
Conventions that carry meaning, and an owner with a name 7 min live
There is a simple test for whether a naming convention deserves to exist: does it tell a reader something they did not already know? A rule that every table name starts with tbl_ passes no test. It is decoration, it tells you a table is a table, and it still costs a migration to remove. A suffix that tells you whether a column is a moment or a calendar day prevents a whole class of wrong number. Fund the second kind and refuse the first.
LiveOwnership: a name, a deputy, and a stated change policy4 min▶
"The data team owns it" is not ownership, because nobody in a team of nine feels personally accountable for a table and no consumer knows who to call. Ownership that works has three parts, and all three are decisions you can make without writing any code:
- A named human per published object. Not per schema, not per domain - per object that somebody outside the team reads. If the list of owners is shorter than the list of published objects, the gap is where incidents come from.
- A named deputy. One person is a single point of failure and a bottleneck during leave. Two names cost nothing and remove both.
- A stated policy for who may change it. The owner approves. Anyone may propose. Nobody changes a published object without the owner knowing, and the mechanism for that is the contract in Part 3, not goodwill.
Two things this buys you that are hard to get any other way. First, an escalation path that is a person rather than a queue, which is what stakeholders actually want during an incident. Second, and less obvious: it makes the size of your published surface visible. When a head of data has to write 140 names next to 140 objects, the conversation immediately becomes "why do we publish 140 things", which is usually the better conversation.
Self-studyThree conventions worth mandating, and two worth refusing3 min read▶
Worth mandating, because each one prevents a specific wrong number:
- Time suffixes that state the granularity. A column ending in a timestamp marker is a moment; one ending in a date marker is a calendar day. Mixing them is how a report ends up double-counting a day boundary, and the fix is free at naming time and expensive later.
- Layer prefixes that state trustworthiness. Raw-shape objects, modelled objects and published objects should be distinguishable from the name alone. This is the dbt layering convention, and its real value is that a reader can tell what they are allowed to depend on without asking.
- Booleans named for their meaning, not their position. A flag whose name states the condition can be counted directly and read correctly by a human, an analyst and a tool. A flag named after where it sits in a legacy file cannot.
Worth refusing, because they cost migration and carry no information:
- Type prefixes and object-kind prefixes. Marking a table as a table, or a string column as a string, tells a reader nothing the catalog does not already show them.
- Version numbers in names. The moment a published object is called v2_final, you have moved your change history into the naming layer, where it cannot be queried, cannot be deprecated cleanly, and will eventually produce a v2_final_new. Versioning belongs in the contract, which is where Part 3 puts it.
The data contract is the interface 7 min live
A schema tells you what columns exist. A contract tells you what they mean, who owns them, what is guaranteed, and what breaks if they change. That difference is the whole reason another team can build on your model without asking you first, and the reason you can change your model without breaking them by accident. It is an interface in exactly the sense a software team would mean it.
Bazaar's contract is a real file - semantic/contract.yaml - and it is short. You do not need a governance platform to have one. You need ten blocks and someone whose name is on it.
Here are the blocks to insist on. The right-hand column is the point of the table: each block exists because it prevents something specific that has already gone wrong somewhere. If a proposed contract is missing a row, ask what stops that failure instead.
| Block | What it states | What it prevents |
|---|---|---|
| owner | a named human, plus a deputy | the incident with no escalation path, and the object nobody dares change or retire |
| consumers | who depends on this, by name - dashboards, the finance close, the portal, an AI analyst | the change that broke something nobody knew was downstream, discovered by a customer |
| freshness SLO | what "current" means, in words: loaded daily by a stated hour, in a stated timezone | the executive reading yesterday's number as today's, and the argument about whether the pipeline is late or the number is wrong |
| completeness SLO | which records are guaranteed present, and within how long | a partial load being read as a business decline |
| breaking-change policy | which changes are free, which need notice and how much, and what happens during the deprecation window | silent breakage - and, more importantly, teams refusing to depend on your model at all because they cannot predict it |
| grain, per object | one sentence each: "one row is one payment attempt", "one row is one merchant per day" | the single most common analytics error in existence: counting rows of the wrong thing |
| allowed joins | the join paths that are sanctioned | the creative join that produces a number nobody can reproduce |
| forbidden joins, with the reason | the paths that look valid and are not - and why, in one sentence each | the confident wrong answer. Bazaar's sales-to-payments join runs cleanly and inflates revenue from 111,906 to 121,003 SGD, about 8% too high |
| metric definitions | for each metric: the expression, the grain it is computed at, and the caveat | three teams reporting three revenue numbers and all three being defensible |
| synonyms | the words the business says, mapped to the metric that answers them | the guess - by a new analyst, and by any tool writing a query on request |
| known limitations | the modelling compromises a reader could mistake for facts | the credibility collapse that follows someone else finding one first |
| agent access | which objects a tool may read, read-only, and when it must refuse to answer | an automated confident wrong answer at machine speed, which is session a6 |
LiveKnown limitations: the block that buys you trust4 min▶
This is the counterintuitive one, and the one most teams leave out because it feels like admitting weakness. It is the opposite. A model that documents its own compromises gets believed. A model that claims to have none does not.
Bazaar's contract lists five limitations in plain language. Two of them are worth reading out loud in a leadership meeting, because they are the shape every real model has:
- "A cart is attributed to the merchant on its highest-value line." So a mixed basket credits all of its abandonment to one merchant. That is a defensible modelling decision and also a real distortion, and a merchant-facing report that does not say so will eventually be challenged by a merchant who is right.
- "Merchant-day and method-day slices routinely have fewer than 30 observations, so rates at those slices are not decision-grade." In Bazaar's own data there is a decline rate of 18.2% that rests on 11 payment attempts. It is arithmetically correct and worthless, and the only thing standing between it and a slide is this sentence.
The economics are simple. If your model has ten compromises and you publish them, you have ten known caveats and a reputation for candour. If you publish none, you have ten landmines, and the first one somebody else steps on costs you the credibility of the other nine too - because now nobody knows what else you did not mention. Publishing limitations is not a confession. It is the cheapest trust you will ever buy, and it is the block that most distinguishes a model people build on from a model people work around.
LiveThe breaking-change policy, in leader terms4 min▶
You do not need to read the schema to govern change. You need to be able to sort a proposed change into one of three buckets, and to know that the third one exists.
- Adding is free. A new column, a new view, a new metric. Nothing downstream breaks, because nothing downstream was using it. This should require no ceremony at all - and if your process makes adding expensive, your process is why your data team is slow.
- Renaming and removing need notice. Rename a column, drop one, change its type, or change the grain of an object, and somebody's dashboard stops working or - worse - keeps working with a different meaning. Bazaar's policy is a version bump, two weeks of notice to every named consumer, and a window where old and new coexist so consumers can move on their own schedule rather than yours.
- Silently changing what a metric MEANS is the most dangerous change of all. Redefine revenue to exclude a fee, or start filtering out unsettled orders, and keep the name: nothing errors, no dashboard breaks, and every historical number in the organisation changes meaning at the same instant. Last quarter is no longer comparable to this one, and nobody knows, because the only visible symptom is a number that moved.
The rule that follows is short enough to state as policy: a change in definition requires a change in name, or an announcement with a date attached, and preferably both. Treat a redefinition with the same seriousness as a removal, because functionally it is one - you removed the old metric and put a different one in its place under the same label.
The leader's job here is not to approve schemas. It is to make sure the third category is named in the policy, has a notification path, and cannot be done quietly by someone acting in good faith on a Tuesday.
Self-studyForbidden joins: why the model should tell you what not to do3 min read▶
Most documentation says what you can do. The block that saves the most money says what you cannot, and why. Bazaar's contract forbids three join paths, and the reasoning generalises to any organisation:
- The sales table joined to the payments table. Both have an order reference, so the join runs. But one row of the first is a product line and one row of the second is a payment attempt, so an order with three lines and two attempts produces six rows and revenue inflated twofold. In Bazaar this turns 111,906 SGD of settled revenue into 121,003 - about 8% too high, and in exactly the direction a leadership team wants to believe.
- The sales table joined to the carts table. Different grains again, and worse, they measure different things: cart value is list price, order revenue is discounted. They will never reconcile to the cent, and that mismatch is real rather than a bug to be joined away.
- Two pre-aggregated summaries at different grains. One is per merchant per day, one is per hour. Joining them fans every merchant across every hour and silently multiplies everything.
Note the pattern: every one of these joins executes without error. There is no warning, no null, no failed pipeline. The output is a number, and it is wrong. That is why the prohibition has to be written down and, better, engineered away - which is the design move session a6 asks you to fund.
Sign the contract, or send it back ◆ no code - a conversation with an outcome
Nothing to install and nothing to run. This is a structured 15 minutes that produces a decision, and both halves of it are portable to your own next team meeting. Work in pairs if the room is larger than six.
Pick one published number your organisation argues about. Top-line revenue, active customers, conversion rate - whichever one has been re-explained more than once this quarter. Write it on the board.
Fill in six blocks against it, out loud. Owner (a name, not a team). Consumers (list them). Grain ("one row is one ___"). Freshness. The metric expression in one sentence. One known limitation. Someone writes as you go.
Notice which blocks the room cannot fill. That is the finding. An empty owner field and an empty grain sentence are the two that predict the next incident, and they are usually the two that are empty.
Decide one thing before you leave the room. A name against that number, and a date by which the other five blocks are written. Fifteen minutes is enough for exactly that, and it is more than most organisations have.
LiveExercise A · The six-block walkthrough8 min · run it in your next team meeting▶
The prompt, read out as written
"Take the number at the top of our weekly pack. In the next eight minutes I want six things on the board about it, and I do not want any of them to be a tool name. One: whose name is on it - a person, not a team. Two: who reads it, listed. Three: what one row of the underlying thing is, in a sentence that starts 'one row is one'. Four: how fresh it is, as a time of day. Five: how it is calculated, in one sentence, including what is excluded. Six: one thing about it that is a modelling choice rather than a fact. If we cannot fill a block, we write the word BLANK and move on."
What a good answer sounds like
Specific and slightly uncomfortable. "Priya owns it, Marcus is deputy. It goes to the board pack, the regional weekly and the finance close. One row is one settled order line. Loaded by 07:00 local. It is charged value after line discounts, excluding orders whose payment never settled and excluding refunds. And it attributes a mixed basket entirely to one merchant, which we know overstates our biggest merchant a little."
The tell of a good answer is that the last two blocks contain an exclusion and an admission. People who genuinely know a number can always tell you what it leaves out.
The failure mode to listen for
Fluent vagueness. "It comes out of the warehouse, it is the standard revenue metric, finance signed off on it last year." None of that is any of the six blocks - it is provenance offered in place of definition, and it is the sound of a number nobody currently understands. The second tell is the room answering block three with a system name instead of a sentence: if "one row is one" gets answered with "it is from the sales table", nobody in the room knows the grain, and every reconciliation meeting you have had about this number is explained.
LiveExercise B · Sort three changes into three buckets7 min▶
The prompt
"Here are three changes a team wants to make next sprint. Sort each into free, needs notice, or most dangerous - and say who you would tell. (1) Add a product-category column to the published sales view. (2) Rename a column from amt to net_revenue. (3) Change the revenue metric to exclude marketplace fees, keeping the name the same."
What a good answer sounds like
"One is free - nothing depends on a column that does not exist yet, ship it today. Two needs notice: it is cosmetically an improvement and functionally a breakage, so it needs a version bump, the named consumers told, and both names alive for two weeks. Three is the dangerous one, and it is dangerous precisely because it looks smallest. Nothing errors, every dashboard keeps rendering, and every historical figure changes meaning at once. That one needs a new name, an announcement with an effective date, and a restated history - or we do not do it."
The failure mode to listen for
The room ranking these by engineering effort rather than by consumer impact - which puts number three last, because it is a one-line change. That inversion is the whole point of the exercise. The most dangerous change in a data estate is almost always the cheapest one to make, and a governance process built around effort will wave it straight through. Listen also for "we will just tell people": a verbal heads-up in a standup is not a notification path, and it is not repeatable after the person who gave it changes team.
The redefinition nobody announced. A subscription business changed its active-customer definition from "billed in the last 31 days" to "billed in the last 30 days" during a routine cleanup. One day. No column renamed, no dashboard broken, no error anywhere. Growth appeared to slow by roughly a point and a half, three teams spent a fortnight investigating a market shift, and the answer was in a commit message. The team that made the change had done nothing careless by their own standards - it was a tidy-up, and their standard did not have a category for "changing what a word means". That category is what a breaking-change policy is for, and it is why the third bucket has to be named explicitly rather than left to judgement.
Six questions to ask your data team ◐ use them this week
These are diagnostic rather than rhetorical. Each one is answerable in under a minute by a team that has done the work, and each one is revealing in a specific way when it is not.
Q1 · Who is the named person - not the team - on our three most-read tables, and who is their deputy?
Why it works: it cannot be answered with a process. Either six names come back in ten seconds, or you have just discovered that your most important objects have no accountable human. The follow-up is better still: when did those names last change, and what happened to the objects when the previous owner left?
Q2 · How many words does our estate currently use for the same commercial concept, and which one is canonical?
Why it works: it converts a vague sense of mess into a countable number, and it sets up the cheapest artifact in this session. A team that says "four, and none of them is marked canonical" has just scoped an afternoon of work with a large payoff. A team that says "one" is either exemplary or has not looked.
Q3 · Show me the grain sentence for every published object. One line each, starting "one row is one".
Why it works: it is the fastest audit in data. A team that can produce this list has almost certainly avoided the whole family of counting errors; a team that cannot has them and does not yet know where. It also takes ten minutes to fix, which makes it a rare governance ask with immediate closure.
Q4 · Which joins are explicitly forbidden in our model, and what is the wrong number each one produces?
Why it works: it tests whether the team has thought about misuse rather than just use. The strong answer names a path and quantifies the damage. "None are forbidden" almost never means the model is safe - it means nobody has written down the paths that run cleanly and lie, so everyone is free to find them independently.
Q5 · What is in our known-limitations list, and when did we last add to it?
Why it works: the answer tells you about the culture, not just the model. A list that is growing means people are finding compromises and recording them. An empty list, or one last touched at launch, means either a perfect model or a team that does not think publishing weaknesses is safe - and the second is far more common and much more expensive.
Q6 · If someone changed the definition of our top-line metric tomorrow without renaming it, how would I find out?
Why it works: it targets the most dangerous change class directly, and the honest answer is usually "you probably would not". That is the gap worth funding: a notification path with named consumers on it, plus a policy that treats redefinition like removal. Any answer involving someone remembering to mention it in a meeting is a no.
Try it yourself - this week ◐ 30-40 min total, no tools
- Commission the synonym map. One page, two columns: what the business says, and the one metric that answers it. Cap it at fifteen rows and give it a two-week deadline - it is an afternoon of work and it is the highest-return governance spend available to you.
- Ask four people in four functions to write down the definition of your top-line number, separately and in one sentence. Compare the four answers yourself, without commentary. Whatever the spread is, that is the size of the problem this session is about.
- Write the owner list for your published objects, personally, with names and deputies. If it takes more than twenty minutes because there are too many objects, you have found a second, better conversation.
- Add the third bucket to your change policy in writing: a change of definition requires a change of name or a dated announcement, and preferably both. One sentence, but it has to exist before the change does.
- Ask for the known-limitations list on your most-used model. If it is empty, send it back and ask for three entries. You will get them, and you will trust the model more afterwards, not less.
Sources covered
This is the working core of the naming and contract literature, stated as decisions a leader makes rather than as conventions a team follows. Full source map, including what is deliberately out of scope, in materials/official-course-map.md. This page covers:
learn-dataopsThree questions before you go 🎯 ◐ 90 seconds
1 · A team asks to approve two naming rules: every table name must begin with a marker saying it is a table, and every time column must end in a marker saying whether it is a moment or a calendar day. Which do you approve?
The test is whether a convention carries information. A marker saying a table is a table is decoration that still costs a migration to change later. A suffix that distinguishes a moment from a calendar day stops a whole family of double-counting errors at day boundaries. Approve conventions that prevent wrong numbers; refuse the rest.
2 · Three changes land on your desk. Which one deserves the most scrutiny?
Dropping a column breaks things loudly, which means it gets found and fixed. Adding is free. Redefining without renaming breaks nothing visibly and changes the meaning of every historical number at the same instant, so nobody notices until a trend is misread. The cheapest change to make is the most expensive to get wrong.
3 · A team presents a new model with an empty known-limitations block. What is the right reading?
Every real model contains attribution choices, exclusions and small-sample slices that a reader could mistake for facts. A blank list means they are undiscovered, not absent. Publishing them is what makes a model believed - the first limitation somebody else finds costs you the credibility of everything you did document.