Skim modeEach chapter in one minute. A heading opens its section.
AtlanFive phases11 chapters14 cards
The FDE Playbook for Analytics AgentsFrom demo to production.
Your analytics agent gets questions wrong when it lacks your business context. It needs to know what each metric means, which tables join, and how your analysts already write the SQL. A better model leaves that gap open. We measured this on our own benchmark, with one model and one question set throughout. This playbook turns what worked into a method: build that context as a governed, measured asset, one domain at a time.
Questions answered correctly107 business questions, one model
Tables and columns only31.8%
Plus AI-generated metrics and trusted past queries83.2%
The model and questions stay fixed. Only the context changes: first the bare tables, then AI-generated metric SQL and trusted past queries, retrieved for each question. The playbook shows you how to build that layer. How we measured →
What you’ll walk away with
At the end of Phase 4, your team holds:
an agent that cleared the bar your sponsor set, on one domain;
the metrics behind it, each with an owner and a version;
a golden set of 50 real questions that tests every later change;
a decisions log;
people on your side who have run a round together, with a round alone booked within two weeks.
You are the delivery lead: a forward-deployed engineer, a partner consultant or an internal program lead. You want to know what happens in each phase and what to do when a week goes wrong.
For sponsor, agent builder, delivery leadProduces the four problems this book solves, and where each fix livesRead 8 min
WatchWhat we learned on our benchmark4:23Read the transcript
The narration says "certified metrics", and the guide says "metrics": in the benchmark, no person approved the metrics. In the method, each metric's owner signs it off.
Pilots don't stall on the demo. They stall on the tenth real question. It touches two tables and a house rule... and the answer comes back confident, and wrong. So here's what we learned on our benchmark... what gets the tenth question right?
Take one question... what's our Q3 sales pipeline? The query gets the fiscal quarter right, and it returns $18.4 million. Now add one line... and it's $11.2 million. That's the number Finance plans on. No bug here. That rule just isn't in any table, column, or description.
That rule is one of five decisions hiding in this question. Which stages count? Which rows are always out? Which quarter, and which amount, on which table? And how do the rows get put together? Guess each one right 80% of the time... and you'll get all five right about one time in three. That's just arithmetic. On bare schema, only the tables, we measured 31.8%.
So we put it to the test. Our benchmark has 107 real questions, with sealed answers, graded by code. Swap the model, and bare schema scores anywhere from 29% to 40%. Give it five trusted past queries, and all three models we ran scored above 66%. Give it certified metrics with their SQL... and our default model hit 83.2%. So which matters more? Context added 26 points or more to each model we tested both ways. Switching models moved about 10. In fact, the best model without context lost to the weakest model with it.
Now, each kind of context, measured on its own. Descriptions and documentation reached 39.3%. Usage patterns from the query log... 43.9%. Certified metrics, with their SQL, reached 83.2%.
Where does context matter most? In the joins. On bare schema, single-table questions scored 64.3%. Multi-table questions? Just 11.5%. Add certified metrics, and they climb to 92.9%... and 82.0%. And refusals on join questions dropped from 31... to just 1.
Form matters too. Take the same rules, and write them in plain English... then in SQL. On multi-table questions, English scored 65.6%... while SQL scored 82.0%. On single-table questions, they tied... at 95.2%.
Then we rebuilt five published methods on top of our certified metrics... and ran the layer alone, the same way. Four scored lower, by up to 14 points... at three to five times the cost per right answer. The fifth, intent search, gained 1.9 points. That's inside the noise... at twice the cost. Context moved the score. The method of reasoning didn't.
So what does work? A certified metric. It seals every decision into one statement... that runs. Here's our running example. The sales team asks... how much open pipeline do we have with our top 100 customers? Left to guess, the agent said $1.31 billion. With the metric... $412 million. And the business can read it, and correct it. It carries its owners, and a version.
It's cheaper and faster, too. Against the average of the 12 other setups we ran... it cost less than half as much per right answer. And it answered in about a third of the time... 29 seconds a question, against 85. Only curated past queries were cheaper and faster... and they scored 75.7%.
Then choose the lane by asking one thing. If this answer is wrong, and nobody notices... where does it land? The top-hundred pipeline lands in the board pack. So it's governed... a certified metric, or no answer. Which deals slipped? That one's exploratory. The agent writes its own SQL from a trusted past query, and shows it. 96 deals had slipped. And win rate with those customers was 31%... against 24% elsewhere.
So the tenth question never needed a bigger model. It needed the missing rule. Fix the context before you blame the model. Next up: Why evals come first. Because without a golden set, you can't tell a fix from luck.
The talk-to-data pilots we see stall between the demo and the tenth real question. The demo question was picked because it works. The tenth comes from a finance analyst on a Tuesday, touches two tables and a house rule, and gets back a confident number that is wrong. Nothing about the answer looks wrong, so nobody catches it. The business decides whether to trust the agent on misses like that one.
Five steps, and the hard one
01IntentThe question as asked: "What's our Q3 pipeline?"
→
02ContextWork out what it really means, and gather every rule that governs it.Open problem
→
03SQLA loop, not one shot: the agent probes, reads results, rewrites.Easy with context
→
04ExecuteRun it against the warehouse.Solved
→
05InsightNarrate the result. Good domain context turns numbers into insight.Comes later
↻ Context and SQL loop: several queries before the final one
The open problem is the middle: capturing and applying context. Adding context moved every model we tested far more than switching models did.
Figure 1
What happens between a question and an answer. Writing SQL is easy once the agent knows what the question means. Knowing what it means is the hard part.
Every question an analytics agent answers goes through the same five steps:
Intent. Read the question as asked.
Context. Work out what it means, and gather every rule that governs it. The open problem.
SQL. Write the query, probing and rewriting as results come back. Easy once the rules are known.
Execute. Run it against the warehouse. Solved.
Insight. Narrate the result. Comes later, and needs good context too.
When the agent lacks a rule at step two, it guesses one your company never wrote down: that fiscal Q3 starts in January, that early stages never count toward pipeline, that test accounts are out of every number. Each guess is a fair reading of the schema, the SQL runs clean, and nobody sees the miss until the number reaches the board. The rest of this chapter shows one such miss, why a better model doesn’t fix it, and the four problems that follow.
The tenth question: a correct query, a wrong answer
Take one question: “What’s our Q3 sales pipeline?” Any good analyst at this company, whose fiscal year ends 30 June, would write this:
sql
SELECTSUM(o.amount)
FROM opportunity o
JOIN account a ON a.id = o.account_id
WHERE o.close_date BETWEENDATE '2026-01-01' ANDDATE '2026-03-31' -- fiscal Q3AND o.stage NOTIN ('Closed Won', 'Closed Lost')
AND a.is_internal = FALSEAND a.is_test = FALSE; -- internal and test accounts are out
It returns $18.4M, and it is wrong. The analyst got the quarter right, because they knew the fiscal calendar, and left out internal and test accounts. They missed a rule nobody told them. At this company the earliest stages never count toward pipeline; Finance treats them as noise and leaves them out of every pipeline number. Add one line and the answer changes:
sql
AND o.stage_order >= 2 -- early stages never count toward pipeline
Now it returns $11.2M, the number Finance plans on.
The first query has no bug. The rule it misses lives in no table, no column and no description. The company made that decision once and never wrote it down anywhere an agent could reach. A syntax error announces itself. A missing rule produces clean SQL and a plausible number, and a reviewer who didn’t know the rule would have written the same query.
The demo never meets this question, because the demo asks what the schema can answer. Real users ask what the business needs, and the hard part of their questions is never in the schema.
What the question means: the intent problem
The stage rule is one of five decisions hiding in that short question.
80%Which stages countearly stages never count
×
80%Which rows countinternal and test accounts out
×
80%Which quarterfiscal or calendar
×
80%Which amountone of several look-alike columns
×
80%How rows combinededuplicated, as of the snapshot
= about 33%0.8 × 0.8 × 0.8 × 0.8 × 0.8. About one in three, close to what we measured on bare schema.
Figure 2
Five decisions hide in “What’s our Q3 sales pipeline?” At 80% per guess, an agent with a strong model gets all five right about one time in three.
The agent has to decide which stages count, and which rows are always out, such as internal and test accounts. It has to pick the quarter, fiscal or calendar. It has to find the right amount on the right table, because several look alike. And it has to assemble the rows correctly: deduplicated, joined to the account, as of the right date.
The schema states none of these. An amount column doesn’t say it is the wrong amount.
Now suppose a strong model guesses each decision right 80% of the time, which is generous for a rule that appears nowhere in the data. All five land about one time in three. That is our arithmetic, not a measurement, but it sits close to what we measured on bare schema: 31.8%.
A smarter model raises the 80% a little. It can’t reach 100%, because no model can infer a rule nobody wrote down. Meanwhile the exponent grows with the question: a second table or a comparison period adds hidden decisions. Demo questions hide few. Real questions hide more, and the score falls to match.
If the problem were the model, a better model would fix it. So we ran the same questions on bare schema across five models, and on three models with past SQL as context. Two models ran both ways.
Switching models moves bare schema about 10 points.Context moved both paired models 26 points or more.
GLM-5.2
Bare schema
31.8%
With context
70.1%
GPT-5.6
Bare schema
40.2%
With context
66.4%
Bare schema across five models: 31.8-42.1%. With context means past SQL served to the agent.
Source: internal benchmark
Figure 3
Bare schema and with context, per model, on the same questions. On bare schema, five models landed between 31.8% and 42.1%. With past SQL, every model we ran scored above 66%, and Gemini 3.1 Pro reached 73.8%.
Switching models moved the bare-schema score by about 10 points. Adding context moved both paired models by 26 points or more, and the best model on bare schema still lost to the weakest model with context. Use next year’s model when it arrives; it will guess better. It still won’t know that your Finance team drops the earliest stages from pipeline, because that rule is in no data it can read. Pick a model that finishes its tasks, then put your effort into context. Written down, owned and versioned, it carries over to the next model. A model swap carries nothing over. On our warehouse, it was not a model problem. It was a context problem.
Not every kind of context closes the gap. Descriptions and documentation barely moved the score; metrics built from the past queries your analysts ran moved it most. The method at a glance shows the ladder, and What teams try first shows what didn’t work.
Deciding the same way every time: the format problem
Once a rule is written down, the form it takes decides whether the agent follows it. Written as a sentence, “leave out the earliest stages” still has to be turned into SQL by the agent, on every question, and every translation is another guess. Written as SQL, the decision is made once and runs the same way each time. On multi-table questions, the same metric served as SQL beat the same metric written as a sentence by 16 points: SQL, not a sentence shows both forms.
Most teams build the prose forms first: descriptions, glossaries, documentation. We did too. None of it gave the agent a decision it lacked.
Knowing you are right: the confidence problem
In software, QA decides what ships. For an agent, the eval does. Without one, “it works” is an opinion held by whoever built it. An agent with no eval is a demo: it answers the question it was shown, and nobody can say whether it will answer the next one.
Without a fixed test, every claim gets answered by impression. A sponsor sees three good answers in a demo and believes the agent works. A builder changes a prompt, tries two questions, and believes it improved. Both are guessing, and the agent is usually being tested on questions picked because it already gets them right. One run doesn’t settle it either: the same setup run twice gives different scores, so a single run proves little.
Four problems, and where the book fixes them
The problem
What fixes it
Where
A clean query returns the wrong number, and nothing looks wrong
Test the agent against real questions with sealed answers, built before any context
Write the tests first, and run every domain through the same loop.
Read 12 min
Why it is hard ends with four problems. This page is the method that fixes them, in one place: what closes the gap, the loop, the rules it runs on, and the gate each phase must clear. It runs on any stack, with a warehouse, scripts and version control. Each stage below is one click from its chapter.
WatchThe whole playbook, in brief2:55Read the transcript
The narration says "certified metrics", and the guide says "metrics": in the benchmark, no person approved the metrics. In the method, each metric's owner signs it off.
Every question your agent answers... goes through five steps. Intent. Context. SQL. Execute. Insight. And only one of them is still an open problem. This is the playbook in two minutes... how to solve that one.
The open one is context, what a question really means. Ask for our Q3 pipeline... and three rules apply. Fiscal Q3 starts in January. Early stages never count. And test accounts are out. Nobody wrote them down, so the agent guesses. The SQL runs clean... but the number's wrong.
So does fixing context actually work? We tested it on 107 real questions, graded by code. Given bare schema, just the tables, the model scored 31.8%. Then we gave it certified metrics as context... and the same model reached 83.2%.
So where's the gap? The hard half is joins. On bare schema, single-table questions came back right 64.3% of the time. Multi-table ones? Just 11.5%. With certified metrics, the same model got 82.0% of them right. So it's not a model problem... it's a context problem.
And software teams already run the loop that fixes this. Write the tests. Build. Debug. Release. Operate. For an agent, the golden set is the test suite. And certified metrics? They're the context you improve on.
Phase 0 happens before the clock starts. You prove access, and put a name in every role. Phase 1 seals 20+ real questions... and runs a baseline. Phase 2 generates certified metrics, and scores them on the same set. Phase 3 hill-climbs from traces. It runs until the set grows to 50... and nothing that passed has broken. Phase 4 releases, hands over, and books a first solo pass. After that, you keep it running... and the next domain starts from what this one certified.
Along the way, there are eight rules. First, fix the context before you change the model. Then write each business rule into a metric's SQL. Build the golden set before any context. Settle conflicts before the agent ever sees them... provenance first, then the owner. Choose the lane by the use, exploratory or governed. Start with one domain, and the people who own its numbers. Read the raw trace of every miss, and feed real usage back. Last, make the agent reliable on what happened... before you ask it why.
So now context has a test... and a loop around it. Write the tests first, and run every domain through the same loop. Eight short videos take each part, one at a time. Up next... what we learned on our benchmark. That's the evidence behind these rules.
What closes the gap
We took real questions our analysts had asked, sealed the correct answer to each one, and ran the same questions again, each time adding one kind of context to the bare schema.
The same questions, bare schema plus one kind of context
Bare schema
31.8%
Descriptions and documentation
39.3%
Usage patterns
43.9%
AI-generated metrics and queries
83.2%
Source: internal benchmark
Figure 1
The same questions with bare schema alone, and with one kind of context added to it each time: descriptions and documentation, usage patterns from the query log, and AI-generated metrics with trusted past queries.
Bare schema carries none of the decisions, and scored 31.8%. Descriptions and documentation reached 39.3%, a few points for about seven times the context. They say what a table holds, and the decisions aren’t descriptions. Usage patterns mined from the query log, such as the filters and joins analysts actually use, served with the descriptions, reached 43.9% on an earlier version of the answer keys. The big jump came from metrics served together with trusted past queries, all generated by our systems from the query log: 83.2% on the configuration we ship. An analyst who ran the right query had already made the right decisions, and a metric seals them so they hold every time.
The rest of this page is how you build that last bar for your own domain: metrics generated from the SQL your analysts already run, tested against a golden set, one domain at a time.
The lifecycle
One analyst can get one agent through one set of questions with a long week of prompt edits. The next quarter, the next model or the next domain undoes most of it. Teams that ship software solved this problem years ago: write the tests first, build, debug against the tests, release behind a gate, operate. An analytics agent needs the same loop, with a golden set of real questions playing the part of the test suite.
The lifecycle. Click a stage to open its chapter. Every stage is scored against the golden set at the centre, and the loop closes when the next domain starts from what this one built.
Some teams spend a month on this loop and some do it in a week. The phases are an order, not a calendar.
Eight rules
The loop runs on eight rules. Rules 1, 2, 3 and 5 rest on our benchmark, and each links to its evidence. Rule 4 and the last three are what building and running the method taught us.
Fix the context before you change the model. Switching models moved our score far less than adding context: the model chart.
Write each business rule into a metric’s SQL. The past queries your analysts already ran carry the rules, and a sentence leaves the agent to translate them: SQL, not a sentence.
Build the golden set before any context. Without sealed answers, you can’t tell a fix from luck: Evals first.
Settle conflicts before the agent sees them: provenance first, then the owner. The definition most analysts ran recently, and that matches the warehouse, usually wins. A definition kept only in a spreadsheet leaves no query history, so its owners settle it. Never let the agent pick.
Choose the lane by the use: exploratory or governed. Exploratory answers suit questions where a person reads the SQL before acting on it. A number that goes on a board slide needs the governed lane: a metric that gives the same answer every time, or no answer: Two lanes.
Start with one domain and the people who own its numbers. One domain is small enough to finish, and its owners settle what provenance can’t.
Read the raw trace of every miss, and feed real usage back. The summary hides the step where the agent guessed, and context left alone goes stale within a quarter.
Make the agent reliable on what happened before you ask it why. “What was pipeline last quarter?” needs metrics. “Why did it drop?” needs a model of how the business works on top of them, and it is only worth building once the numbers hold.
The gates
Each phase of the lifecycle ends at a gate. Move on when the gate is met, whatever the date.
Phase 0 runs before the clock: the clock is the build, and it starts with Phase 1, once Phase 0’s gate is met. Phase 3 is the hill climb: run the golden set, read the trace of each miss, make the smallest fix and run it again. Phase 4 releases the agent and hands it over; What you’ll walk away with lists what your team holds at the end.
Phase 0
Before the clock
about two weeks at a typical company
One domain and its users. The questions that need an exact answer. Surface, harness and model chosen. Access open. People named with hours.
GateEvery access item proved, a name in every role
Phase 1
Build the golden set
eval owner and graders
Harvest real questions the business already asks. Write the expected answers, seal them, run the baseline once.
Gate20+ real questions sealed, baseline run
Phase 2
Generate metrics
context engineer and domain owner
Generate metrics from past SQL and BI, witness them against the warehouse, resolve conflicts, approve.
GateMetrics scored on the same set
Phase 3
Hill-climb from traces
context engineer and agent builder
Read the raw trace of every miss, make the smallest fix that closes it, rerun.
GateSet grown to 50, nothing that passed has broken
Phase 4
Release and hand over
the whole team
Launch on the chosen surface. Real traces feed the next version. Hand the loop to your team.
GateGo, no-go or go with conditions; first solo pass booked
Golden set
Not built yet
20+ sealed
Same set, rescored
Grows in batches
50 at launch
New questions are added in batches the context engineer never sees.
Figure 3
Five phases: Phase 0 to set up, then Phases 1 to 4 to build, test and launch, each ending at its gate. The golden set starts at 20 questions in Phase 1 and reaches 50 by launch.
Before Phase 1 you need read-only warehouse access, query history and BI reports. You also need your agent harness set up to record a trace of every run, so that your first test runs are traced. Last, you need named owners with hours: What you need before you start.
Find your task
Each stage breaks into numbered steps. Pick a stage, then a step, to see how it is done, who does it, the template to copy and the mistake to avoid. Next step walks you through the whole method in order.
Why this exists. An agent can write clean SQL and still give the wrong number, because it guesses business rules nobody wrote down. The method writes those rules down, tests them on real questions and keeps them true, one business area at a time. Open any box to see what is inside it.
At the centreThe golden setReal questions with checked answers. Every step is scored against it.Evals first →
Phase 0 · ScopeBefore the clockOwners, brief, access proved
Step 0.1Pick one domainOne business area, its users and its numbers
HowChoose an area with real questions, known users and an owner who has time. Sales pipeline is a good first one.
WhoExec sponsor and domain owner
Watch outThree areas at once give you three half-built answer keys and no owner with time for any.
Step 0.2Write the briefOne page everyone agrees on
HowUsers, the problem, the owners, and which numbers must be exact every time and which only need to point the right way.
WhoDomain owner and sponsor, at a 90-minute kickoff
The whole method, stage by stage. Every step links to its template or checklist, and every stage to its chapter.
The running example
The book follows one engagement at a large B2B company. The domain is sales, and three questions carry the story: open pipeline with the top 100 customers, how many of those deals slipped, and why pipeline dropped in EMEA. Boxes marked In practice follow it through each phase. It is a composite built to show the method, so its counts are examples, not measurements. The Q3 pipeline query in Why it is hard is a separate example, so its $11.2M does not reconcile with the story’s $412M.
Cards are one-page checklists you can print. Each phase chapter ends with the card for its job, and all of them are collected in Cards.
How to build one
Evals first
Build the golden set before you build any context. Without it, you can’t tell progress from luck.
For eval owner, graders, sponsor, agent builderProduces what a trustworthy golden set looks like, and how it is gradedRead 4 min
WatchWhy evals come first3:14Read the transcript
The narration says "certified metrics", and the guide says "metrics": in the benchmark, no person approved the metrics. In the method, each metric's owner signs it off.
In software, QA decided what shipped. For agents... the eval does. Without one, saying "it works" is just an opinion, held by whoever built it. In this video... why evals come first, and how you'd know the agent works.
An agent changes every time you edit a metric, a rule, the model, or the prompt. So the eval reruns on every change, before users ever see it. Think of it like a test suite before a release.
And here's the thing... a demo can't settle three questions. Is it working? Did that change help, or did it just move the failures? And where, exactly, does it break?
A right answer, once, isn't a capability. So run each question three to five times. Right every time? It knows. Right some of the time? It's guessing. Never right... it can't.
On our benchmark, two runs of the same setup scored 86 and 80... out of 107. Now look across 154 runs, of every setup we tried. 105 of 107 questions got answered right at least once. Yet the best single run got 90. So the knowledge is there... the consistency isn't.
So what goes in one row of the golden set? Three parts. First, the question, in the business's own words. That's the only part the agent sees. Then the SQL, which is evidence for diagnosis. And the sealed answer, $412M... that's the grade.
An eval worth trusting has four properties. First, it's representative... keep the hard half. On bare schema, just the tables, single-table questions scored 64.3%. Multi-table? 11.5%. With certified metrics, it's 92.9% and 82.0%. So an easy set hides most of the difference between setups. Second, un-dominated. No single fact gets to swing the headline. Third, live. Questions grow out of real use, and when the set has a wrong answer, it gets corrected. Fourth, sealed. If anything in the pipeline can see the answer... the agent will find it.
Grade the answer first. Why? Because two different queries can both be right. LinkedIn found that about 60% of its questions had more than one valid answer. So grading isn't one check. It's a stack of them. Check the value, within tolerance. Look at the SQL and the trace. Have a judge check the answer's shape. And run a leak check. And count refusals apart from wrong answers... though both are still misses.
So what's the eval's real output? A work queue. Never patch context for one question. Instead, read every miss as one of three things... a definition never written, written but not served, or served and ignored.
So now, whether it works isn't an opinion. It's a score anyone can rerun. Build the golden set before you build any context. Without it, you can't tell progress from luck. Next up: Semantic views, or metrics? The form your context should take.
Why it is hard makes the case for a golden set: without one, every claim about the agent is an impression.
Is it right?Every answer is checked against a verified one, not against an impression.
Is it better than before?The same sealed questions, scored the same way, before and after each change.
What do we fix next?Each wrong answer points to a missing definition, one never served, or one ignored.
Is it safe to change?Rerun the set after every edit to a metric, rule or model, and see the break before users do.
Only a fixed test answers these. Without one, the agent is a demo.
Figure 1
Four questions only a fixed test can answer. Each one comes up in every phase and after launch.
A right answer once isn’t a capability either. Run each question three to five times and read the pattern. Right every time: the agent knows the decision. Right some of the time: it is guessing at a decision nobody gave it, and the disagreement is a signal in its own right. Never right: something is missing from the context. Whole scores move between identical runs too, so judge a change by its effect on the whole sealed set, never on the question you were looking at, and treat a gap smaller than the run-to-run spread as unresolved: How much to trust a gap. Every later step in this book is measured against the golden set, so it comes first. This is what a trustworthy one looks like.
One row of the golden set
Each row has six required fields. Three of them do the core work, and each has one job:
Part
Example
Its job
The question, in the business’s words
“What’s open pipeline with our top 100 customers?”
The only part the agent sees
The SQL that produced the answer
Reference SQL a grader wrote and verified, with its filters
Graded second, after the result: does the agent’s SQL make the same decisions?
The sealed answer
$412M
Graded first, within a tolerance
What makes an eval worth trusting
Four properties. Miss one and the score stops meaning what it says.
Representative. Take real questions from the board pack, the dashboards and analyst requests, in the business’s words, and keep the hard half. On bare schema, our questions that one table answers scored 64%, and the ones that need a join scored 11.5%. With the metrics layer, they scored 93% and 82%. A set of easy questions hides most of the difference between setups.
Not dominated by one fact. No single rule should be able to swing the headline. In our set, four questions turned on the same missing exclusion rule. Know which questions share a decision, so one fix isn’t read as broad progress.
Live. Questions grow out of real use, and the ones that broke before stay in. Anthropic’s guidance for agent evals is to build tasks from real failures and read the transcripts, not just the pass rate. Answer keys have errors too: experts re-checking two public benchmarks found errors in more than half the samples they read. Have two graders check every key before it is sealed, and correct a wrong key when you find it.
Sealed. Each answer is computed by running the correct SQL and checked against the source the business trusts. Keep the answers away from whoever builds the context and from anything the agent can reach. If any part of the pipeline can see the answer, the agent will find it.
Grade the answer, in layers
Two different queries can both be right. LinkedIn found about 60% of its questions had more than one valid answer. So grade the answer, not the SQL text, and grade it as a stack of checks:
The value. Code compares the answer with the sealed key, within a tolerance.
The logic. A grader checks that the SQL makes the item’s decisions. A wrong query can land near the right number by luck. Read the trace to see why an answer was right or wrong.
The shape. A judge checks that the answer is the kind of thing asked for: a number, a list, a date.
Leaks. Check that no prompt carried any part of the answer.
Count refusals apart from wrong answers, and count both as misses. An agent that refuses often looks careful and still fails the business.
Evals are the agent’s CI/CD
An agent changes every time its context changes: a new metric, an edited rule, a renamed column, a new model. Each change can fix one answer and break another. Rerun the golden set on every change, before the change reaches users, and keep the change only if nothing that passed has broken. That is what lets a team keep improving the agent after launch without being afraid to touch it.
The eval’s real output is a work queue. Never patch the context for one question. Read each miss as one of three things: a definition never written, one written but never served, or one served and ignored. Phase 3 works through that list.
For context engineer, domain owner, agent builder, sponsorProduces what a metric is, where each kind of knowledge goes, which lane a question takesRead 9 min
A metric is every decision a number depends on, sealed into one statement that runs. A formula such as SUM(amount) is one part of it. On its own, that formula produced the wrong $18.4M in Why it is hard.
PopulationWhich rows are in new-business and upsell deals past the earliest stages, on the top N accounts by current ARR
GrainOne row per what one row per customer; each open deal counted once
Time ruleWhich period, as of when the quarter-end snapshot at the as-of date
FormulaThe arithmetic sum of ARR
ExclusionsWhat is always out early stages never; internal and test accounts out; closed deals out
WITH top_accounts AS (
SELECT account_id FROM latest_term WHERE rn = 1
GROUP BY account_id ORDER BY SUM(arr) DESC LIMIT $n
)
SELECT COUNT(DISTINCT o.account_id) AS accounts,
COUNT(*) AS deals,
SUM(o.arr) AS open_pipeline
FROM crm.opportunity_snapshot o
JOIN top_accounts ta ON ta.account_id = o.account_id
JOIN crm.account a ON a.id = o.account_id
WHERE o.as_of_date = $as_of
AND o.stage_order >= 2
AND o.type IN ('New Business', 'Upsell')
AND o.is_closed = FALSE
AND a.is_internal = FALSE
AND a.is_test = FALSE;
Figure 1
A metric. Population, grain, time rule, formula and exclusions each settle one decision, and each points at the clause in the SQL that carries it.
Leave any part out and the agent guesses it. Take the engagement’s pipeline question: “How much open pipeline do we have with our top 100 customers?” The metric that answers it settles five things no table states:
Top 100 means the highest current ARR.
Some early stages never count toward pipeline.
The amount is ARR, not total contract value.
Each open deal counts once, however many contract terms it spans.
The number is taken at the quarter-end snapshot.
Before the metric existed, the agent guessed each of these and returned $1.31B. With the metric, it returned $412M: 340 deals on 91 of the top 100 customers.
A metric has one more advantage: the business already understands it. A sales leader can read “open pipeline with the top 100 customers, by current ARR” and say “that’s wrong, we rank by bookings.” Nobody can say that about a table description or a prompt. When the unit of context is a metric, the people who own the number can correct and approve it directly, so the feedback loop stays short. Their time is the real cost of this method, which is one reason to work one domain at a time.
Metrics also change. Stage names move and fiscal rules get redefined. So every metric carries an owner and a version, and every agent reads the same copy.
SQL, not a sentence
The same rule can reach the agent in two forms. As a sentence:
Open pipeline is the value of new and upsell deals that are still open, leaving out the earliest stages and internal or test accounts, taken at the end of the quarter.
And as SQL, where each line settles one part of that sentence:
sql
-- taken at the end of the quarterWHERE o.as_of_date = :quarter_end
-- leaving out the earliest stagesAND o.stage_order >= 2
-- new and upsell deals that are still openAND o.type IN ('New Business', 'Upsell')
AND o.is_closed = FALSE-- no internal or test accountsAND a.is_internal = FALSEAND a.is_test = FALSE
Figure 2
The same metric served as SQL and as prose, on the same multi-table questions. Only the form changed. In a single run of each, the SQL scored 16 points higher.
On single-table questions the two forms tied. The more decisions a question carries, the more a sentence leaves the agent to translate, and every translation is another guess.
Where does each kind of knowledge go?
Find the knowledge you are holding in the first column. Put it where the second column says.
Knowledge
Where it goes
Example
A number the business runs on
Metric: SQL, owner, provenance
Open pipeline with the top 100 customers, with “some early stages never count” written inside
How analysts actually answered a long-tail question
Trusted past query, with provenance: who ran it, how often, when
“Deals pushed past quarter end”
A house rule that applies across many metrics
Rule: one short line the agent must follow, also written into each metric it touches
“Quarter means fiscal quarter”; “top 100 customers means highest current ARR”
Internal names and jargon
Business term
Project names such as “Project Alpha”, internal product names, team codenames
What a table is and what one row means
The DDL itself
CREATE TABLE plus a comment on the grain
Why a number moved
Ontology plus a dated record of business changes
A territory realignment, a pricing change
Two rules settle most ties. If a fact could go in two places, use the one that can run: SQL beats a sentence. A rule that touches one metric goes inside that metric; a rule that touches many is served as a rule and also written into the SQL of every metric it touches.
Provenance is what makes a past query trustworthy. In the engagement, the slipped-deals question had no metric. It was answered by a RevOps analyst’s “deals pushed past quarter end”, which many analysts had run many times, recently. That record is why the agent could trust it. A business term then linked the user’s word “slipped” to the query, though the two share no words.
Why a metric, and not a view
Most teams arrive with a semantic layer of some kind: Snowflake semantic views, Databricks metric views or a Genie Agent, LookML, or a homegrown metric store. Every layer holds the same four parts: what each table and column means, how tables join, metrics, and the dimensions a metric is grouped by. The question is how to organize them so an agent can use them. An agent puts three demands on that storage: a script with no model in the loop can compile a definition to the same SQL every time; the right item can be found by exact lookup when a metric covers the question and by search when it doesn’t; and a fix changes the definition itself instead of piling up beside it as notes.
The four parts get organized one of three ways, and each repeats something.
Organized by
How it works
What gets repeated
Where a question starts
Per table
Each table carries its own description, keys, and any joins or metrics that touch it. A catalog works this way
Joins and metrics that span tables
A table name, which the business does not speak
Per logical table
Tables are grouped into one business-facing view, such as “Orders”, with its own joins, metrics and dimensions. Snowflake semantic views and Genie Agents work this way
Table meanings, joins and metrics, across views
An entity; the agent answers only inside the view it was given
Per metric
The metric is the unit. Its formula, filters, joins, dimensions and verified SQL are stored together, and tables are referenced from it
Joins and dimensions, never the metric
The metric, which is where the question starts
Per logical table is the default today, because it is what the major platforms ship. Its costs show up once agents are asking: a metric that two views need is often defined in each, a question that spans two views has nowhere to go, and a wrong answer gets patched with a note beside the view that the agent reinterprets on every question. On our benchmark, semantic views as the only way in scored 38.3%. On multi-table questions they scored 16%, against about 61% on the same questions for past queries with complete SQL. A view states a join; a past query shows it worked.
Business questions start with a metric. People ask how many orders came in last week or what churn did last quarter; they rarely start from a table or a view. A per-metric layer stores context in the shape the questions arrive in: the business can read a metric and correct it, the same definition serves every agent and BI tool, and it compiles to the same SQL every time. Its costs are real too. Questions no metric covers fall back to exploration, so coverage builds over time, and without owners and review, metrics sprawl into near-duplicates such as revenue, net revenue and recognized revenue. That is why every metric carries an owner and a version.
Figure 3
Logical-table first asks the agent to pick a view, and the same metric lives in several. Metric-first starts at the one definition the question names, with its formula, verified SQL, named joins, dimensions and drills.
If you have semantic views, keep them. They keep working for the analysts who use them, and in Phase 2 they are a source: their measures and filters become candidate metrics alongside past SQL, witnessed and approved like any other. Five questions show quickly whether a layer will hold up once agents are asking:
When a metric definition changes, how many places have to change with it?
Can an agent answer a question that spans two of your views?
For a question your metrics cover, does the layer compile the SQL, or does the agent write it fresh?
Does the same request compile to the same SQL, with no model in the loop?
When someone corrects a wrong answer, does the fix change the model, or get added beside it as text?
The placement table says where knowledge goes. The lanes say how the agent may use it. For each kind of question, ask one thing: if this answer is wrong and nobody notices, where does it land?
Ask one question firstWhere does a wrong answer land if nobody notices?
On a board slide, in finance, in a published KPIGoverned laneExact, every time
Served from
A metric: name, version, complete SQL, owner
The rule
No metric, no answer
The agent
Runs the metric's SQL; no exploring outside it
The pipeline question · pipeline metric, v3$412M340 deals on 91 of the top 100 customersIn front of someone who reads the SQLExploratory laneDirectionally right
Served from
Trusted past queries and business terms
The rule
Show the SQL and the sources with every answer
The agent
Writes its own SQL within the domain's tables, and flags doubt
The slipped-deals question · "slipped deal" + a trusted query96 slipped · 31% win rateof the 340 deals; 24% win rate everywhere else
One context call before any SQL returns the matches and the lane. When two teams publish different numbers for the same question, write the metric and move it to the governed lane.
Figure 4
The two lanes. Numbers the business runs on take the governed lane: a metric or no answer. The long tail and diagnostics take the exploratory lane: the agent writes SQL grounded in trusted past queries and shows its sources.
In the governed lane, the agent serves a metric or gives no answer. The bar is exact, every time. The pipeline question took this lane and returned $412M, the number in the board pack.
In the exploratory lane, the agent writes its own SQL from trusted past queries and business terms. It shows the SQL and what it assumed. The bar is directionally right. The slipped-deals question took this lane: 96 deals had slipped, and the win rate with these customers was 31% against 24% elsewhere.
Good context alone doesn’t make a board number safe. Even the best run still got some answers wrong, and it stated them as plainly as right ones. In the exploratory lane, a reader can see the SQL and catch a miss before acting. A board number has no such reader, so it needs the governed lane. A kind of question can move lanes later: when two people publish different numbers for an exploratory question, write the metric and move it to the governed lane.
Ask it of each kind of question in the brief, not of every question one by one.
The sponsor and the domain owner walk this at the kickoff, in about 30 minutes. Why-questions wait until the numbers under them are right.
If this answer is wrong and nobody notices, where does it land?
In a board pack, a finance close or a published KPI. The question is governed.
The bar is exact, on every run.
The answer comes from a metric, whose SQL runs as served.
If no metric covers it, the agent says so. No metric, no answer.
In a decision about where to look next. The question is exploratory.
The bar is one pass rate for the whole lane, set by the sponsor now, before any result exists.
The agent writes the SQL, grounded in trusted past queries.
Every answer shows its SQL and its sources.
Later, in production: do two people publish different numbers for an exploratory question?
Yes. It has become governed. Resolve the conflict, write the metric, move it.
No. Leave it where it is.
In the running example, open pipeline with the top 100 customers is governed: it lands in the board pack. Slipped deals are exploratory: they tell a sales leader where to look.
How to build one
Serve per question
One context call per question, before any SQL: exact lookup first, search second, served live over MCP.
For agent builder, context engineerProduces the retrieval architecture, the ranking rules, the three trace checksRead 5 min
Building the context layer is half the job. The other half is getting the one metric or query that settles a question in front of the agent at the moment it needs it. The obvious first build pastes everything into the agent’s instructions. It is simple and it fails. Loaded in full into every prompt, the layer scored 52.3%, and 72.0% with past queries added. Retrieved per question, the same kind of layer scored 83.2% and cost less than half as much per right answer. A long prompt buries the decisive item among near-variants, and the agent picks the closest-looking one. Retrieval per question also keeps the layer live: an agent that searches on every question reads the version approved this morning.
The retrieval architecture
1The user asksIn Slack, a BI chat or an IDEHow many deals slipped last quarter?
2The agent asks firstOne context call, before any SQLget_context("deals slipped last quarter")
3The MCP server searches liveOver the one store, never a copy
Exact lookup a metric by name or alternate label
Search trusted past queries by field names and business terms
Attach the rules and terms the matches depend on
4What comes backA handful of items, ranked and labelled, each with complete SQL
Metric none covers this question, so the governed lane says so
Trusted past query "Deals pushed past quarter end" · run by many analysts, recently
Business term "slipped" means pushed past quarter end; links to the query
Rule "quarter means fiscal quarter" · set by the RevOps lead
5The agent writes and runs SQLRead-only, against the warehouse
6It answers with its sourcesThe SQL, the items it used, the lane
Trace every call, what it returned, every statement and the answer
Figure 1
One question, end to end. The agent makes one context call before any SQL. The MCP server searches the context layer live and returns a handful of labelled items, each with complete SQL. The tool name is an example.
Three parts do the work:
One store. Metrics, trusted past queries, rules and business terms live in one place, each with an owner and a version. This is the layer you build in Phase 2.
One MCP server in front of it. It exposes a small set of tools, such as a context lookup and a metric fetch, to any agent that speaks MCP. Lyft reaches its metrics through an MCP server in the same way. DoorDash’s data agent goes further: it blocks unmodeled or unverified sources at the harness level, and keeps new joins and documents inactive until they meet an eval threshold.
One rule in the agent’s instructions. Call for context before writing SQL. If a metric matches, run its SQL as served. If none matches, say so. For a governed question, stop there; otherwise explore and show the SQL.
Why MCP
How context reaches the agent
What happens
Our view
Pasted into the prompt
The whole layer rides along with every question
Don’t. It scored lower and cost more per right answer
Pushed into the platform
Semantic views, metric views or instructions inside the warehouse’s own agent
Works for that one agent. It stays inside the platform’s governance and permissions, with no extra service to run. You push again on every release
Live search over MCP
The agent calls one server on each question; the server searches the context layer
Our design preference, not measured against pushing into the platform. One store serves every agent, each call shows up in the traces, and a change reaches every agent at once
Your own API
Your harness calls a context endpoint before it writes SQL
Same design as MCP, for a harness you own. Expose the same tools
The case for MCP isn’t the protocol. It is that every agent, whether it’s a warehouse agent, an IDE assistant or a Slack bot, reads the same copy through one door you can trace. When the next harness arrives, connecting it is only wiring.
What the search should match
Exact lookup first. When a metric covers the question, return it at the top, labelled as a metric, so the agent runs it instead of rewriting it.
Match on field names and business terms. Ranking past queries by the tables, columns and terms they share with the question beat ranking by embedding similarity, 68.2% to 55.1%. Words in a question rarely match the words in a query’s title. Business terms bridge that gap.
Return a handful, whole. Return the top five or so, with complete SQL. Cap by the number of items, never by characters. Past queries served whole instead of cut short added 9.4 points.
Don’t stack retrievers. A second, sharper retriever on top of the metrics added nothing, because near-variants compete with the item that settles the question.
Judge retrieval by answers, not recall. Better table search lifted recall from 59.8% to 86.4% and accuracy didn’t move. Finding more candidates is not the same as serving the decisive one.
Check it in the traces
Retrieval fails quietly. The agent still answers, so read the traces for three things:
The call happens. Every question shows a context call before the first SQL statement. An agent wired to MCP but not told to call it often skips it.
The decisive item comes back. For every miss in the golden set, check whether the metric or query that would have settled it was returned. If it wasn’t, the miss is “written, not served”: fix the term, the alternate labels or the ranking, not the metric. Phase 3 sorts every miss this way.
The agent uses what came back. If the right item was returned and the agent wrote its own SQL anyway, tighten the instruction to run a metric’s SQL as served.
Start with one domain and the people who own its numbers.
For sponsor, domain owner, platform owner, security lead, delivery leadProduces the domain brief, the access list proved, named owners with hours, the agent architecture, a working trace exportRead 9 min
WatchPhase 0: before the clock2:15Read the transcript
The sales team's CRO asked for one thing... a pipeline number for the top accounts, one that matches Finance every time. In a 90-minute kickoff, the team picked sales, named two owners, and wrote a one-page brief. Then getting access... took the next two weeks. This is Phase 0: what has to be ready before the first question gets graded.
Phase 0 starts with one domain. Pick one where the questions are bounded, you know the users and the tables, and the owner has time. Try three domains at once... and you get three half-built golden sets.
The brief fits on one page. And it puts every kind of question into a lane. Some questions are governed, like the CRO's top-100 pipeline. Those have to be exact, on every run. Others are exploratory, like which deals slipped. Those clear one pass rate... and the sponsor writes it down before any result.
Next comes access. Every item gets proved by running its test. And the one that's left until last? Trace export... and Phase 3 depends on it. A nightly summary doesn't count. You need a record of every call.
Then put a person's name on every role. Why? RevOps can't settle a conflict... but the RevOps lead can. The co-owner's hour a week? That's the line teams forget. The builder's 20 hours a week? That's the one they underestimate.
Every analytics agent comes down to four parts... the surface, the harness, the model, and the context. Platform-native or custom, it's the same picture. The context layer plugs into the same place in both.
Then build the minimum harness... and stop. That's one context call per question, and one read-only SQL tool. Give it a step budget of 10... and trace every call. Building in-house? Then Phase 0 can take days, and three of its parts are optional.
So, two weeks in... one question could be followed from start to finish. Start with one domain, and the people who own its numbers. Next up, Phase 1: build the golden set that every later change gets scored against.
An answer is only right against a definition someone owns and a bar someone set. Phase 0 names those people, writes the bar down and opens the access every later fix depends on. The work is small and the waiting is long. Plan for about two weeks.
Pick one domain: a bounded set of questions, asked by known users, over known tables. Sales pipeline, finance close and support analytics are good first domains. Choose the one with an owner who has time, real questions the business already asks, and past SQL or dashboards on its tables. Three domains at once give you three half-built golden sets and no owner with time for any of them.
The brief
The brief is one page. It fixes the domain, the users, the problem, the owners and which questions need an exact answer. Phase 1 harvests questions only from inside it. The domain owner and the sponsor write it together at the kickoff.
CH03.BRIEF.PREVIEW Domain brief, short form
The sales team’s brief, as agreed at the kickoff.
domain-brief.yamlyaml
domain: Sales pipeline
fiscal_year: ends 30 June
as_of: the last quarter-end snapshot # every answer in the golden set uses itusers: CRO staff, sales leaders, RevOps analysts, FP&A partners
asks_in: the chat tool sales leadership already uses
problem: >
Leaders get pipeline numbers that disagree with FP&A.
Each disagreement costs an analyst a day to reconcile.
owners:
- RevOps lead: deals, stages, amounts; 2-3 h/week
- FP&A partner: who the top accounts are; about 1 h/week in Phases 2 and 3
eval_owner: one named person, with a RevOps analyst and an FP&A analyst as graders; 6-8 h in Phase 1, then about 2 h/week
model: the one expected in production, named with its version
governed: open pipeline, win rate, closed-won ARR # exact, every runexploratory: slippage, pipeline creation, stage aging # SQL shown; 4 in 5 passdeferred: why-questions, until the numbers are right
out_of_scope: bookings forecast, commissions, marketing attribution
The brief puts each kind of question in a lane. Governed questions must be exact on every run. Exploratory ones must clear one pass rate, which the sponsor writes down now, before any result exists. Name two owners if another team owns part of a definition. When the two meanings of “top 100 customers” collided in Phase 3, both people who could settle it were already named.
This is the checklist for Phase 0: the system access and the named people. Most delays in Phase 0 come from access, so request every item on the first day. Each item is done when its test passes. A statement that access “should work” is not a signature.
Card
System access you need before phase 1
Read-only warehouse accessscoped to the domain's tables · test: a query runs under it
Required
Query historywho ran each query, when and how often · test: the export has rows and a date range
Required
BI reports and semantic modelsdashboards, LookML, dbt or Power BI models · test: the export opens
Required if you have them
Trace export from your harnessevery call: context served, SQL run, answer · test: one trace read end to end
Required
Where users will askSlack, Teams, a BI tool or an app · named in the brief
Named
People, named with hours
Exec sponsornameh/wk
Domain ownernameh/wk
Eval owner and gradersnameh/wk
Agent buildernameh/wk
Platform ownernameh/wk
Security lead if data leaves your environmentnameh/wk
Figure 1
What you need before Phase 1: five access items, each with its test, and a name and weekly hours for every role.
Trace export is the item most often left until last, and the one the hill climb depends on. In Phase 3 the trace is where you see which decision the agent guessed. A nightly summary does not count, because it reports what the agent said it did. You need a record of every call, with what was served and what SQL ran.
Each role owns one part of the work. Adjust the hours to your domain, but never to zero.
Role
Owns and decides
Phases 1-4
After launch
Exec sponsor
The bar and every gate
The kickoff, a 30-minute readout in each phase, the gates
Each release
Domain owner
Approves metrics, past queries and rules; decides the conflicts provenance can’t settle
2-3 h/week, most of it in one working session
1-2 h/week
Co-owner from another team
Co-signs definitions that span both teams
About 1 h/week in Phases 2 and 3
As conflicts need
Eval owner and graders
Seal the golden set and grade every run
6-8 h in Phase 1, then about 2 h/week
About 1 h/week
Agent builder
The harness and the model
About 20 h/week until the baseline, then 4-6
Runs the loop
Platform owner
Access, trace export, the tables
Phase 0, then on call
On call for schema changes
Security lead (if data leaves your environment)
What leaves the building
Phase 0
Reviews changes to data handling
Context engineer (in-house: an analytics engineer)
Generates and tests candidates; never sees an expected answer
Dedicated
Hands over in Phase 4, or stays on
Delivery lead (in-house: your program lead)
Runs every session and gate
Every session
Runs the handover
Put a person’s name in every row. “RevOps” cannot settle a conflict. The RevOps lead can. The co-owner’s hour is the line teams forget, and the agent builder’s 20 hours is the line they underestimate.
Role
Phase 0
Phase 1
Phase 2
Phase 3
Phase 4
After launch
Your side
Exec sponsorkickoff, readouts, gates
Kickoff, agrees brief
Readout, gate
Readout, gate
Readout, gate
Readout, go / no-go
Reviews releases
Domain owner2-3 h/week; settles what provenance can't
Seed questions
2-3 h, disputes
2-3 h, conflicts
2-3 h
2-3 h, approves release
1-2 h, approves changes
Co-owner from another teamco-signs definitions that span both teams
~1 h
~1 h
As conflicts need
Eval owner and graderssealing-heavy in phase 1
Grading method
6-8 h, seal 20+
~2 h, new questions
~2 h, 50 sealed
~2 h, launch gate
~1 h, audits
Agent builder~20 h/week until the baseline, then 4-6
Surface, harness, model
~20 h if new; baseline
4-6 h
4-6 h, reruns
4-6 h, launch
Runs the loop
Platform ownerPhase 0, then on call
Access, trace export
On call
On call
On call
On call
Production traces
Security leadPhase 0
Approves access
Reviews changes
Delivery side
Context engineerdedicated for phases 1-4
Kickoff
Dedicated
Dedicated
Dedicated
Handover
Delivery leadruns every ceremony
Plans, runs kickoff
Ceremonies
Ceremonies
Ceremonies
Handover
2-3 h hours per weekReadout eventOn call standing◆ gate at the end of each phase
Exec sponsor The kickoff, a 30-minute readout in each phase, the gates. After launch: at each release.
KickReadReadReadGo?Rev
Domain owner 2-3 h/week, most of it in one working session; conflicts land in phase 2. After launch: about 1-2 h/week.
Seed2-3h2-3h2-3h2-3h1-2h
Co-owner from another team About 1 h/week in phases 2 and 3, co-signing definitions that span both teams. After launch: as conflicts need.
1h1hAsk
Eval owner and graders About 6-8 h in phase 1 to harvest and seal the golden set, then about 2 h/week growing it to 50. After launch: about 1 h/week.
Rubric6-8h2h2h2h1h
Agent builder About 20 h/week until the baseline, then 4-6 h/week. After launch: runs the loop.
Pick20h4-6h4-6h4-6hLoop
Platform owner Opens access and trace export in Phase 0, then on call. After launch: production traces.
AccessCallCallCallCallTraces
Security lead · if data leaves your environment Approves what leaves the building in Phase 0. After launch: reviews changes to data handling.
OKRev
Context engineer · in-house: an analytics engineer Dedicated from phase 1, handing over in phase 4.
KickDedDedDedHand
Delivery lead · in-house: your program lead Runs the kickoff, the working sessions and the gates, then the handover in phase 4.
PlanCerCerCerHand
Columns: Phase 0 · 1 · 2 · 3 · 4 · after launch. A gate closes each phase.
Figure 2
Who does what, phase by phase. A gate closes each one.
The agent architecture
Every analytics agent has four parts: the surface where people ask, the harness that runs the loop, the model, and the context it reads before it writes SQL. That context lives in a context layer: the store of metrics, trusted past queries, rules and terms that the agent calls once per question. It can be files in a repository behind a small search function, or a product. You choose between two shapes for the rest.
Platform-native. The warehouse vendor supplies the harness and the surface. Databricks Genie and Snowflake CoWork (formerly Snowflake Intelligence) are the common ones. You configure; you do not build.
Custom. You build the harness on a framework such as Google ADK or LangGraph, or write your own. You get full control of the loop, the tools and the traces.
UIwhere users ask
Harnessthe loop, tools, prompts, traces
Modelthe LLM it calls
↕ MCP or API: context served, traces back
Context layermetrics, trusted past queries, rules and terms
Golden setsealed, never served: the eval owner keeps it apart and scores the agent against it
Platform-native
Databricks Genie, Snowflake CoWork. The platform supplies the chat and the model; you configure its agent: instructions, data scope, tools.
Custom
Google ADK, LangGraph or your own code. You build the harness, pick the model and put it in Slack, Teams, a BI tool or your app.
Both reach the same context layer over MCP or API. It serves the context and takes the traces back; the harness runs the agent and the SQL.
Figure 3
The four parts of an analytics agent, in both shapes. The surface, harness and model differ. The context layer plugs into the same place in each.
In either shape, the harness runs in your environment and your team owns it after launch. Pick the model you expect to use in production. You can change it later, as long as you rerun the golden set on the new model before you compare scores.
The minimum harness
Build this and stop.
One context call per question, before any SQL. At baseline it returns the schema only.
One read-only SQL tool. Exploratory queries run as the asking user; governed answers run under a fixed service identity, so a board number is the same for every asker.
A step budget: a fixed cap on tool calls per question. Ten is a sound default. Leave it there; Phase 3 explains why.
A per-call trace: everything served, every tool call and SQL statement, the answer or refusal, tokens and time.
Fix the shape of the context call on the first day. In Phase 2 the metrics and trusted past queries arrive behind the same call, and nothing else in the harness changes. That is what keeps the baseline and the later scores comparable.
What leaves the building
This section matters when a vendor or outside team handles your data or runs part of the stack. Security will ask what data moves, and where. Walk them through this diagram at the kickoff.
1 · Result rowsFrom your warehouse to your harness, its model and your trace store; never through the context layer. Read under a named identity: the asking user, or a service account.
2 · Past SQL and BI definitions. Query text, BI reports and DDL, read by a read-only identity, go to the model the metrics agent uses. Query text only, never table rows. Security approves it in Phase 0; name the provider in the brief.
3 · Served contextThe context layer serves metrics, trusted past queries, rules and terms over MCP or API to the model your harness calls, per question: definitions, not data. Traces go back to your trace store and context layer.
Three flows, agreed with security in Phase 0. Every context call is traced.
Figure 4
What moves and where it goes: result rows go from your warehouse to your harness and model, past SQL is read for context, and definitions and past queries are served to the agent. The metrics agent is any model-driven script that drafts candidate metrics from past SQL in Phase 2.
Result rows never pass through the context layer. Every context call is logged, so security can audit what was served.
Gate 0
The delivery lead shows the sponsor the brief, the access tests and the named owners. The decision is to start the clock.
Phase 1 can’t start until you make five decisions:
The domain: one business area, its problem and its users.
The bar: exact on every run for the numbers the business runs on, and one pass rate for everything else, written down now.
The agent architecture: where people ask, which harness runs the loop, and which model.
The people: a name and weekly hours next to every role.
The start date. Phase 0 ends when the brief is agreed and every access item is proved.
At the end of Phase 4 you decide go, no-go or go with conditions.
Your people’s weekly hours are set in Phase 0. The domain owner’s two to three hours a week matter most: engagements stall where the owner can spare only minutes.
Go when the governed questions are right on every run, the rest clear your pass rate, and nothing that passed before has broken. Give each condition an owner and a date.
Exec sponsor
Signature
Date
Phase 1
Build the golden set
Seal the questions where the builders can’t see them, and grade them by code.
For eval owner, graders, agent builder, domain ownerProduces at least 20 sealed questions, the grading rules, the baseline score, Gate 1Read 6 min
WatchPhase 1: build the golden set2:41Read the transcript
The narration says "certified metrics", and the guide says "metrics": in the benchmark, no person approved the metrics. In the method, each metric's owner signs it off.
Two graders checked the same question against two trusted sources... and got two different hundred customers. The question? Open pipeline with our top 100 customers. The sources? The dashboard tile, and the board pack. So who was right? The RevOps lead chose the board pack... the one the sales team's CRO had promised. This is Phase 1: building the golden set... the test every later change is scored against.
Start with at least 20 real questions... the ones the business already asks. Where do they come from? The board pack, and leaders' dashboards. Analyst tickets from the last two quarters. Saved analyst queries, too. And the sponsor's own questions. Then ask the owner one thing... what was the last wrong number that reached a meeting?
Every item goes in one format, with six required fields. An ID and the question. Its lane, and its source. The expected answer, plus the SQL. Two more fields are optional, and they pay off in Phase 3. The decisions the question hides... and the decoy, the answer you get if you guess them.
Write the grading rules before any result exists. Rules written after... bend toward the results. Grade the data first... then the SQL. A wrong query can land near the right number by luck. Allow valid alternatives, like a total, or a breakdown that sums to it. And a governed answer only counts if it's right on every run.
Then seal the set away from the builders... and guard against three leaks. First, golden SQL in the context. Purge it, and record each removal by hash. Second, the agent reading its own work. Exclude its service account. Third, sealed values in served text. Scan every prompt... a hit invalidates the run.
Now run the bare agent, with only the tables, once per question. It got 7 of 20. Take the pipeline question. It came back at $1.31 billion... but the sealed answer is $412 million. So what went wrong? Four reasonable guesses. It ranked by deal count, counted every stage, summed contract value... and joined each deal to every subscription term. Each guess is a line of the decoy. And the SQL still ran clean. That's Gate 1. The sponsor sees where the agent starts.
Remember that disagreement? It's now a sealed item, with the owner's decision in its history. Seal the questions where the builders can't see them... and grade them by code. Next, Phase 2: turning the SQL your analysts already wrote into certified metrics.
Evals first makes the case for the golden set; this phase builds it.
Harvest at least 20 real questions
Take the questions from what the business already asks and has already answered. An invented question tests work nobody needs done, and it tends to be one the agent can pass. Collect two or three times as many candidates as you will seal. Then pick at least 20 that cover the domain and both lanes.
Pull the candidates from four places:
the board pack and the dashboards leaders read
analyst tickets and requests from the last two quarters
saved analyst queries on the domain’s tables
the sponsor’s own questions
Rewrite each one the way a user would ask it, with no table or column names. Record where its verified answer lives. Then ask the domain owner one question, because it often surfaces the item that matters most: what was the last wrong number that reached a meeting, and how was it caught?
Write every item in one format
Every question goes into the golden set in one format, so any grader can check any item and you can version the set like code. Six fields are required. The rest are optional.
CH04.ITEM.PREVIEW Golden-set item, short form
The pipeline question, as sealed.
sales-01.yamlyaml
# requiredid: sales-01
question: How much open pipeline do we have with our top 100 customers?
lane: governed
source: FP&A board pack, top-accounts pipeline page
expected: {accounts: 91, deals: 340, open_pipeline: 412000000}
expected_sql: |
-- the query that returns expected, run read-only on the as-of snapshot
# optionalvalid_alternatives: ["by region, summing to the total"]
tolerance: {counts: exact, amounts: within 0.5%}
decisions: [top 100 by current ARR, some early stages never count, amount is ARR, each deal once]
decoy: "top 100 by deal count, every stage, contract value, each term -> $1.31B"
history: ["graders disputed the source; FP&A partner chose the board pack"]
Two optional fields pay off in Phase 3. decisions lists the choices the question hides. decoy is the wrong answer you get when those choices are guessed the obvious way. When the agent misses, a grader compares its SQL against the decisions and names the one it guessed.
Write the grading rules in this phase, before any result exists. Rules written after the results bend toward them.
1 · Does the returned data match? code grades it
Against the expected result or a valid alternative, within tolerance: counts exact, amounts within 0.5%. A total or a breakdown summing to it both pass.
noWrong on this run. Declined to answer is its own verdict, never right, reported apart from wrong.
2 · Does the SQL make the item's decisions? domain grader; a judge only once calibrated
noWrong on this run. A wrong query can land near the right number by luck; a near-match of data alone never passes.
3 · Right on all k runs of the same configuration? code compares values and SQL
noFails pass^k. Right on at least one run is pass@k; never quote it as accuracy.
yesPass^k · the item counts. Report pass^k for the governed lane: a board number right on two runs of three is wrong. An item right on every run joins the regression set, and leaves it if it fails. The same setup, run twice, can disagree on a few questions.
Figure 1
One item, graded in order: the returned data within tolerance, then the SQL against its decisions, then the same answer on every run. Each item runs k times. Pass^k means right on all k runs; pass@k means right on at least one. Items right on every run form the regression set. The rest are items the agent can’t yet answer reliably.
Grade the data first, then the SQL. The data check is fast and needs no judgment. Then check that the SQL makes the item’s decisions. A wrong query can land near the right number by luck, so a near-match on data alone never passes.
Allow several valid answers. A total and a breakdown that sums to it are both right. Record these in valid_alternatives when you seal. An alternative that makes a different decision is a conflict. The definition’s owner settles it before the item is sealed, and the eval owner sends it to the conflict list too, with no sealed value.
Check consistency across runs. Right every time means the agent knows it. Right some of the time means it is guessing, and on one run you cannot tell the difference. A governed answer counts only if it is right on every run.
Use an LLM as a judge for answer shape. A model is good at checking what code cannot: did the answer state its period, filter and unit? It should never grade the number itself when code can.
Calibrate the judge before its verdicts count:
Two graders grade the same sample blind, with one written rubric.
The judge grades the same sample.
Look at every disagreement. Most trace to a rule nobody wrote down, so fix the rubric.
The judge counts once it agrees with the graders about as often as they agree with each other. Recheck it whenever its model or rubric changes.
Keep the golden set away from the agent
The golden set and the agent’s context draw on the same past SQL. The query behind a dashboard tile can come back as a trusted past query, and then the agent copies the answer instead of working it out. Build guards against three leaks into the pipeline, so nobody has to remember to check:
Golden SQL in the context. Before any context is served, remove every past query that matches an item’s expected SQL or returns a sealed answer. Record each removal by hash, so it can be audited without exposing the set.
The agent reading its own work. Exclude the agent’s service account from the query history.
Answers in served text. Scan every prompt for sealed values. A hit invalidates the run.
The context engineer never sees an expected answer. The agent sees only the question as a user would ask it.
Harvest 2-3× the questions you will seal eval owner · from what the business asks
Draft expected SQL and answers graders · six fields required, the rest optional
Rubric: how each answer is graded eval owner · before any result
Verify every draft against its source graders; disputes to the domain owner
crosses the wallA definition dispute also goes to the review queue as a conflict, with no sealed value.
Seal at least 20 eval owner · hashed, stored where no agent reads
crosses as hashesPast SQL is purged by hash; each exclusion can be audited without exposing the golden set.
Baseline on bare schema, once per question agent builder runs, eval owner grades
gatePhase 1 gate · 20+ sealed and the baseline run. The exec sponsor sees where the agent starts.
never crossesExpected answers and SQL, decisions and their history, the questions sealed later. The context engineer never sees the golden set; the agent sees only the question as a user asks it.
Figure 2
How the golden set is built and sealed. Only two things cross the wall to the context side: a conflict between definitions, with no sealed value, and the hashes used to purge past SQL.
Seal, then audit. An item is sealed when its expected SQL has run read-only on the snapshot, the result matches the trusted source, no dispute is open, and the eval owner has signed it. Commit the set to version control and never edit a question to make the agent pass.
The set will still have errors. When an item fails on every run whatever you change, suspect the item first: re-run its SQL, re-check the source, and correct it if it is wrong. Audit a few passing items too. A wrong item the agent happens to match looks like a pass, and nobody checks a pass.
Run the bare agent once for a baseline
Run the agent on the bare schema before you build any context. It shows how far the schema alone gets you, and every later score is read against it. Run each sealed question once, trace every call, and grade the result. For every miss, record which decision the agent guessed.
In the sales baseline, the pipeline question went wrong four ways. The agent ranked the top 100 by deal count, counted every stage, summed contract value, and joined each deal to every subscription term. Each choice was a reasonable reading of the schema, and the SQL ran clean. Each was also one line of the item’s decoy. The right answer is $412M.
Gate 1
The delivery lead shows the sponsor the golden set and the baseline. The decision is whether to start building context.
You own the golden set. The context engineer never drafts, sees or edits an expected answer.
The tasks, in order:
Name the graders and fix the as-of date every answer is computed at.
Harvest two or three candidates for every question you will seal. Pull them from the board pack, dashboards, tickets, saved analyst queries and the sponsor’s own questions.
Rewrite each candidate the way a user would ask it, with no table or column names.
Graders draft the expected SQL and answer for each one.
Write the grading rules before any result exists: returned data first, then the SQL, with a tolerance per answer type.
Graders verify every draft against its source. A question with two defensible answers goes to the domain owner before it is sealed.
Pick at least 20 that cover both governed and exploratory questions. Seal them.
Purge every past query that computes a sealed answer, by hash. Commit the set.
The agent builder runs the baseline once per question. You grade it and record the decision the agent guessed on every miss.
Every item carries six required fields: id, the question as asked, lane, source, expected result and expected SQL. Optional: valid alternatives, tolerance, the decisions the question hides, the wrong answer a guess would produce, and a history of every correction.
An item is sealed when its expected SQL has run read-only on the as-of snapshot, the result matches the trusted source, no dispute is open, and you have signed it. Store the set where neither the agent nor the context side can read it. Never edit a question to make the agent pass.
A definition dispute raised while sealing also goes to the conflict list, with no sealed value attached. Otherwise the context side never sees it.
Phase 2
Generate metrics
Write each business rule into a metric’s SQL. The agent follows a query and skims a paragraph.
For context engineer, domain owner, agent builder, eval ownerProduces metrics, trusted past queries, resolved conflicts, the Gate 2 scoreRead 7 min
WatchPhase 2: generate metrics2:40Read the transcript
The narration says "certified metrics", and the guide says "metrics": in the benchmark, no person approved the metrics. In the method, each metric's owner signs it off.
By the first afternoon, the metrics agent had drafted candidate metrics... from the analysts' past SQL and their sales dashboards. Most of the conflicts settled on provenance. But one wouldn't. This is Phase 2, generating certified metrics. Phase 1 left the agent at 7 of 20.
Here's the question. On multi-year deals, did the amount mean first-year ARR... or total contract value? It went to the sales team's CRO, who answered, ARR... the figure the board pack uses.
So how do you get there? Five steps take you from past SQL to certified metrics. First, gather past SQL and BI reports... always together. Generate candidates. Witness each one. Resolve the conflicts. Then certify what survives.
Generating them needs no product. A script groups the statements by shape, and a model names each group. It writes no new SQL... and it never sees the golden set.
Nothing's certified until it's run. Every candidate gets five checks. Did it run, and how many rows came back? Does each row count once? Does the prose match the SQL? And is there a literal nobody can explain? If a candidate's uncertain, keep it out entirely. An agent can't weigh a warning.
So how do conflicts settle? On provenance... who ran it, how often, how recently, and whether it matches the warehouse. Win rate, for example, settled on recency. The dashboard version predated the Disqualified stage.
Then certify. Each metric becomes a file, governed like code... with an owner, a version, its provenance, and its SQL. Every house rule goes inside the SQL, where the harness runs it.
Serve it per question... in the form that runs. Does the form matter? In one test, we stripped parts out of each metric. The full metric scored 83.2%. Its name and SQL alone scored 84.1%... the same, within the noise. But its prose alone? That fell 8 points, to 74.8%.
Back to the sales team. Those first-afternoon drafts are now certified metrics. And the agent scores 14 of 20, up from 7. That's Gate 2.
So here's the rule. Write each business rule into a metric's SQL. The agent follows a query... but it skims a paragraph. Next, Phase 3, hill-climb from traces. That's where the definitions nobody raised show up.
Most of what your company knows about its numbers is already written down. It sits in the SQL your analysts ran and in the reports and semantic models your BI tool serves. You rarely write a metric from scratch. You generate candidates from those sources, prove each one runs, settle the conflicts and have the owner approve what survives. Then you score the result on the same sealed questions.
Five steps from past SQL to metrics
Sources, read-only
Past SQL (query history) · what analysts ran, who, how often, when
BI reports and semantic models · the numbers leaders already see
Governed lane
1Generate metrics · a metrics generator: your script or a product
2Witness against the warehouse · runs clean, one row per key, matches its report
3Resolve conflicts · provenance first (who ran it, how often, how recently, does it match), then the domain owner
4Metrics · SQL, owner, version, provenance
Exploratory lane
Keep what analysts trust: machine traffic out, duplicates merged, ranked by who ran it.
Trusted-query library · complete past SQL; the agent writes its own SQL from it.
→Both lanes served to your agent from one context layer.
Figure 1
From what your company already has to metrics: gather the sources, generate candidates, witness each one against the warehouse, resolve conflicts, approve.
Gather the sources
Use two kinds of source, always together. Past SQL shows how analysts actually answered questions, including the filters nobody wrote down. BI reports and semantic models show what the business agreed to put on a dashboard. Either one alone misses things. Query history has no record of a ranking kept in a spreadsheet. A dashboard has no record of the one-off question an analyst answered last month.
Pull the executed statements on the domain’s tables, read-only, far enough back to cover a full business cycle, with who ran each one, when and how often. Leave out the agent’s own queries and machine traffic such as scheduled loads. Keep dashboard queries, because a person chose their filters. Export the domain’s BI reports, measures and semantic models alongside.
Generate candidates
Hand both sources to a metrics agent. It groups statements that share one shape, keeps one complete statement per shape with its literals intact, and names the metrics inside it. Each candidate comes out with a population, exclusions, a grain, a time rule, joins and dimensions, plus the real SQL it came from. Whatever does not become a metric stays as a trusted past query, with its provenance, for the exploratory lane.
You don’t need a product for this step. A script can normalise each statement, stripping literals and ordering clauses, and group statements by shape; a language model then names and describes each group without touching its SQL. Two rules keep the output honest. The generator never sees the golden set. And every candidate’s SQL is cut from a real statement: the generator names and describes, but writes no new SQL.
The metrics agent drafts
What you already havePast SQL with who ran it, when and how often; BI reports, semantic models, saved queries.
Generate candidatesGroup statements by shape, keep one complete statement, name the metric inside it. It writes no new SQL.
↓ the rest stay as trusted past queries for the exploratory lane
Your people decide
Witness, review, approve, serveEvery candidate runs read-only; conflicts settle on provenance, then the owner; the owner approves; each metric is served per question.
Phase 2 gate: metrics scored on the same set. In practice: 14 of 20, up from 7.
Figure 2
What the metrics agent does, and where your people take over: it drafts candidates from what you already have; your people witness, settle conflicts, approve and serve.
Witness every candidate
Nothing is approved until it has run. Run each candidate under a read-only identity and record five things:
did it run, and how long did it take
how many rows came back
does each row count once (COUNT(*) = COUNT(DISTINCT key))
does the prose agree with the SQL
is there any literal nobody can attribute to a rule
Hold back any candidate that fails its run or carries a predicate you cannot explain. A hard-coded list of account IDs is the common case. Trace the list to its source before you move on. This is where a fork can hide. A definition kept in a spreadsheet or a board pack never shows up in query history, so at most it surfaces as an unexplained list.
Keep uncertain candidates out of the served context entirely. An agent cannot weigh a warning. A metric marked “unverified” is still a complete, confident statement, and the agent will use it.
Resolve conflicts
A conflict is two witnessed candidates that claim the same number with different rules. Two versions of win rate is the classic case. The sales dashboard counted disqualified deals in the denominator. The analysts’ queries did not.
In our engagements, most conflicts settled on provenance, without a meeting. Line up the evidence for each version.
Signal
What it tells you
Who ran it
Analysts in the owning team outrank a one-off from another function
How often
The version run most is the working definition
How recently
A version nobody has run since a process change is probably stale
Does it match the warehouse
The version whose filters fit the current schema and data is usually right
Win rate settled on recency. The dashboard version predated the “Disqualified” stage, and every recent analyst query excluded it. The RevOps lead confirmed it in a minute.
When the evidence splits, the domain owner decides. Prepare each conflict the day before: both versions as SQL, both results on the same snapshot, the literals that differ, and who uses each. When a definition spans two functions, both owners sign. If they cannot agree, the conflict goes to the sponsor, and the agent serves neither version until then. Take on only the conflicts the owner can decide in the time booked, most-used numbers first. The rest wait, unserved.
Approve
Send every witnessed metric with no open conflict for approval. Each one gets an owner, a version, its provenance and its SQL. The domain owner approves them, usually in one batch, and only approved metrics are served on the governed lane.
Before you approve, check that every house rule that applies is written into the SQL. A rule that lives only in a description, or in a separate instruction, never reaches the statement the harness runs.
What one metric holds
A metric is a file, governed like code. Here is win rate after its conflict was resolved, cut to the fields a reviewer reads.
CH05.METRIC.PREVIEW Metric spec, short form
The exclusion of disqualified deals is in the SQL, where the harness will run it, and in the prose, where a reviewer will read it. The witness run checks that the two agree.
win_rate.yamlyaml
name: win_rate
version: 4 # v3 was the dashboard version; retired, kept on recordowners:
- {role: RevOps lead, owns: the definition}
status: approved
description: Deals won as a share of deals won or lost in the period. Disqualified deals are out.
population: Deals closed won or closed lost in the period
exclusions: [disqualified deals, internal and test accounts]
grain: One row per deal (key opportunity id)
time_rule: Close date, fiscal quarters; the fiscal year ends 30 June
dimensions: [region, segment, rep]
joins:
- {to: crm.account, condition: a.id = o.account_id, cardinality: many_to_one}
sql: |
SELECT 100.0 * COUNT(CASE WHEN o.stage = 'Closed Won' THEN 1 END) / COUNT(*) AS win_rate
FROM crm.opportunity o JOIN crm.account a ON a.id = o.account_id
WHERE o.close_date BETWEEN $start AND $end
AND o.stage IN ('Closed Won', 'Closed Lost')
AND NOT a.is_internal AND NOT a.is_test
verified_examples:
- question: What was our win rate last quarter?
result: 24.3 # executed against the warehouseprovenance:
source: query history and the sales dashboard
distinct_analysts: 6
runs: 140
witnessed: Phase 2 · 1 row · grain check passed
conflict: dashboard version counted disqualified deals; settled on recency, confirmed by the RevOps lead
approved_by: [RevOps lead]
How you serve decides whether the agent uses what you built. Serve per question has the architecture and the ranking rules: one context call per question, a handful of complete statements, metrics first and labelled. Two more rules matter here:
Keep the literals.'Closed Won' and stage_order >= 2 are the definition. Mask the names of people and customers, and keep the business values.
Serve rules as instructions. A house rule that holds for every question, such as “quarter means fiscal quarter”, goes to the agent as a short instruction with the name of whoever set it. If a metric depends on the rule, write it into the metric’s SQL as well.
Bring in what you already have
Most teams already hold some context: a semantic layer (semantic views, metric views, LookML or dbt metrics), saved queries, instructions written for an earlier agent. Treat all of it as a source, put it through the same witness and conflict steps, and sort it by what it can do.
What you bring in
Treat it as
Why
Saved or verified queries
Candidate trusted past queries
Complete, human-approved SQL transfers well
Metric views and measures with filters
Candidate metrics
The filter is a decision, and it runs the same every time
Instructions such as “exclude test tenants”
Candidate rules
A rule the agent must follow
Column descriptions and synonyms
The floor, for finding tables
A dictionary says what exists. It says nothing about how to count
Give every imported object an owner and a version before it is served.
Gate 2
The sponsor sees the score on the same sealed questions, the change since the baseline, the conflicts resolved and anything escalated. The decision is to start the hill climb. Hold the gate if anything served is unowned, unversioned or unwitnessed.
A gate can only check what somebody raised. A metric can pass every check here and still carry a definition nobody questioned, because the other definition never appeared in any source. Phase 3 finds those in the traces.
A conflict is two definitions of the same thing, both in use. Most settle on evidence; the domain owner decides the rest in a short session.
First, let provenance decide. For each variant, the context engineer shows:
who runs it, and how many different people
how often, and how recently
whether it runs clean and matches the warehouse
which dashboards and reports it feeds
When one variant is run by most analysts, recently, runs clean and matches the trusted report, keep it and record why. No meeting needed.
When the evidence splits, it goes to the owner. The day before, the context engineer prepares each variant’s definition as SQL, where it is used, and both results on the snapshot.
The owner resolves it one of five ways:
Choose a variant.
Name an authoritative source table.
Add a population rule, such as “internal and test accounts are out of every number”.
Retire an object.
Dismiss it, with a note.
If another team owns part of the definition, its owner co-approves.
Example: the top-100 conflict. One variant ranked customers by number of deals. It fed the sales ops dashboard and had plenty of query history, so Phase 2 approved it. The other ranked by current ARR and fed the finance board pack, but its list lived in a spreadsheet and never appeared in query history. Provenance could see only one side. In Phase 3 the raw trace of the pipeline question surfaced the gap. The RevOps lead and the FP&A partner chose ARR in 20 minutes and also wrote “some early stages never count” into the metric. Sales ops kept its tile, renamed “most active accounts”.
What happens next:
The context engineer records the decision and what would reopen it. The losing variant is retired and kept on record.
The metric is re-rendered and checked against the warehouse again.
The agent builder reruns the questions that depend on it.
A definition kept in a spreadsheet leaves no trace in query history, so provenance can’t rank it. Before approval, trace any pasted list of IDs back to its source.
Phase 3
Hill-climb from traces
Read the raw trace of every miss. The summary hides the step where the agent guessed.
For context engineer, agent builder, domain owner, eval ownerProduces trace reviews, approved context changes, the iteration ledger, a score ready for the launch gateRead 8 min
WatchPhase 3: hill-climb from traces2:59Read the transcript
The narration says "certified metrics", and the guide says "metrics": in the benchmark, no person approved the metrics. In the method, each metric's owner signs it off.
Here's the question: how much open pipeline do we have with our top 100 customers? The summary said the agent used the certified metric... and it had. But the raw trace showed something else. It ranked them by number of deals. Finance ranks them by current ARR. This is Phase 3, hill-climbing from traces. Phase 2 got it to 14 of 20. So why do the rest still miss?
It's one loop, run in short rounds. Freeze the context... and predict what'll change. Run it, grade it, then read every miss. Make the smallest fix. Then rerun everything, and record it.
Teams skip two steps. The first: predict before you run. Which questions should each change fix? The second: rerun the whole set. Here's why. A rule meant to drop internal accounts also dropped a partner account... and only the full rerun caught it.
So what's in a trace worth reading? Each served item, by name and version... each tool call, every SQL statement, the answer, and what it cost in tokens, steps and time. Why not just ask again? Because a metric that's wrong the same way every time... never disagrees with itself.
Before you fix a miss, check two things. Is the sealed answer itself wrong? Or did the agent just run out of steps? If not, it's one of three kinds. It was never written. It was written, but not served. Or it was served... and ignored. Our top-100 ranking was never written. Slipped deals was written... but never served.
So how often does this happen? On our benchmark, the configuration we ship, certified metrics with their SQL, missed 18 of 107. 11 of those were about which rows belong. And 4 landed within 1% of the sealed answer.
Then make the smallest fix. Slipped deals took 2 edits to 1 business term... the synonyms "pushed" and "rolled", plus a link to the analyst's query. The top 100 took a 20-minute decision from its 2 owners: rank by ARR. And record the fixes you reverted, too.
Write the stop rule down first. Stop when two rounds in a row move the score less than the run-to-run variation. And don't raise the step budget to cut refusals. Why not? On our ontology setup, a bigger budget cut refusals from 46 to 31. But wrong answers jumped from 27 to 40. A refusal is telling you a decision's missing.
Back to the pipeline question. Ranked by ARR, it now returns $412 million. And Phase 3 closed at 18 of 20. So read the raw trace of every miss. The summary hides the step where the agent guessed. Next, Phase 4: release and hand over, on fresh questions nobody's climbed against.
Phase 3 starts from the metrics and the Phase 2 score. The misses left are decisions nobody raised, and the trace is where they show. The phase ends when the score stops moving or clears the bar set in the brief. The work is one loop, run in short rounds. Each round changes the context a little, reruns the golden set and reads what happened. Meanwhile the graders grow the golden set to 50 questions for the launch gate. The context engineer never sees the new questions.
The loop
1Freeze: tag the layer version context engineer
2Predict which items flip, and which way written before the run
3Run, every call traced agent builder · one run early, 3-5 past about 60%
4Grade the data, then the SQL eval owner
5Read the raw trace of every miss and classify it context engineer; the domain owner checks
6Change and approve the smallest fix its owner approves
7Rerun the whole set and record the change-log row failed predictions too
↺Next round, back to step 1. A round scores the items right on every run.
stop ruleTwo rounds in a row within run-to-run variation and no predicted flip lands. Then stop, report where it levelled off, and take the gap to the sponsor.
Figure 1
One round: freeze the context, predict what will change, run, grade, read every miss, make the smallest fix, rerun everything and record it. The stop rule is the only way out.
Teams skip two steps most often.
Predict before you run. Write down which questions each change should fix. A round that moves the total without landing its predictions did something other than you meant.
Rerun the whole set. A change aimed at one question can break another. The sales team’s did: a rule meant to drop internal accounts also dropped a partner account the golden set counts. Only the full rerun caught it.
Two habits keep the scores honest. First, before the first round, run the unchanged context two or three times. The score moves a little between identical runs. Call that spread the run-to-run variation. A round that moves the total by less than that proves nothing on its own. Second, once the score is past about 60%, ask each question three to five times per round. Count a question as right only when it is right on every run.
Record every round in the iteration ledger: what changed, what you predicted, what moved, and what you kept or reverted.
Read the raw trace
A summary tells you what the agent says it did. The trace shows what it actually did, step by step. Read the trace of every miss before you change anything. Here is the pipeline question, cut to the lines that matter:
text
trace · the pipeline question · run 1 of 3
context call returned: the metric "open pipeline, top customers", version 2, owner RevOps lead
ran metric the metric's SQL, as served
WITH top_accounts AS (... ORDER BY COUNT(*) DESC LIMIT 100) <- ranked by number of deals
... WHERE NOT o.is_closed AND o.type IN ('New Business', 'Upsell') <- every stage counts
answer "Open pipeline with the top 100 customers: [a total well above the golden answer]" wrong on 3 of 3 runs
The agent made no mistake of its own. It ran the statement it was given, the same way on every run. Both wrong decisions were inside the metric. Asking the question several times would never have exposed this, because a metric that is wrong the same way every time never disagrees with itself. Only the statement in the trace shows it.
A trace is worth reading when it carries, for every run:
the prompt, with every served item by name and version
each tool call, with its arguments and result
every SQL statement, failed ones included
the answer or the refusal
tokens, steps and time
If your export lacks any of these, fix it before the next round.
The three kinds of miss
Is the key wrong?
yesEval owner corrects and reseals the key. Never edit the question to fit the agent.
Did the step budget run out?
yesRead what the steps were spent on and supply the missing decision. Never raise the budget: it trades abstentions for wrong answers.
Does the decision exist anywhere in the layer?
noNever written · the most common miss. Write the definition into a metric; the domain owner settles it.
Was it served for this question?
noWritten, not served. Fix retrieval so the right item arrives: term links, ranking.
Was it used?
noServed, ignored. Make it a rule the agent must follow, or make the SQL a metric so the wrong path is impossible.
yesIn the data, still wrong on every run. The state the answer needs does not exist, or the grain is wrong. The platform owner fixes it.
Figure 2
Walk every miss through the tree before you fix anything. Each kind has one fix and one owner.
Check two things first, because adding context makes both worse. Is the golden answer wrong? Then the eval owner re-verifies and reseals it, and nobody edits the question to fit the agent. Did the agent run out of steps? Then read what the steps were spent on.
Then place the miss in one of three kinds:
Kind
What the trace shows
Smallest fix
Who
Never written
The decision exists nowhere in the context
Write the definition; the owner decides it
Context engineer drafts, domain owner decides
Written, not served
The definition exists and never reached the agent
Fix retrieval: a term link, alternate labels, a rank
Context engineer
Served, ignored
The definition was in front of the agent and it took a simpler path
Make it a rule the agent must follow, or make the SQL a metric
Context engineer and agent builder
Phase 3 found the first two kinds in the running example. The top-100 ranking was never written: finance’s definition lived nowhere the pipeline could see it. The slipped-deals question was written and not served. A trusted past query already answered it, but the question said “slipped”, and neither the query nor its title used that word, so the agent invented its own definition.
A miss that persists with its definition served and used is not a context problem. The warehouse has no table in the shape the question needs. Take it to the platform owner.
When a miss won’t sort cleanly, ask the question several times with everything else fixed and compare the SQL. Where the runs split, two definitions compete. Resolve it as a conflict. This check needs no golden set, so it keeps working after launch.
The smallest fix that closes a miss
The climb stalls when a team writes new definitions for misses whose definitions already exist. Search the context before you write anything. Then make the smallest change that closes the miss: a versioned edit to one metric, rule, business term or trusted query’s rank.
Target the rule, never the answer. The change states the business rule. It should make sense to someone who has never seen the golden set.
Keep sealed values out. No change may contain a golden answer or a literal copied from the set.
Use the form that runs. Definitions go in as SQL, rules as instructions, vocabulary as term links.
Give it an owner and a version. Each round gets a new context version, so rolling back is one step.
The slipped-deals fix shows the size to aim for. It was two edits to one business term. “Slipped deal” gained the alternate labels “pushed” and “rolled”, and it was linked to the analyst’s query. Nobody wrote a new definition, because none was missing.
The top-100 fix needed a decision. The context engineer prepared both rankings as witnessed SQL, with who uses each. The two owners chose ARR in 20 minutes and agreed to co-own the metric. The RevOps lead also moved “some early stages never count” out of a separate instruction and into the metric’s SQL. A harness runs a metric as written, so a rule has to be in the statement to count.
Without context
How much open pipeline do we have with our top 100 customers?
$1.31B
Turns
6
SQL queries
3
Time
49 s
Cost
9¢
Guessed: top customers by deal count, early stages included, contract value, one row per deal per contract term.
With the metric
Open pipeline, top accounts · v3
$412M
Turns
5
SQL queries
2
Time
29 s
Cost
3¢
340 deals on 91 of the top 100 customers. NA $198M · EMEA $161M · APAC $53M.
Five decisions the metric carries: top 100 by current ARR on the latest active term; new-business and upsell past the earliest stages; amount is ARR; each deal once; as of the quarter-end snapshot. Owners: RevOps lead (deals), FP&A partner (who the top accounts are).
Figure 3
The pipeline question before and after the fix. Without context: $1.31B, from four reasonable guesses. With the metric: $412M, 340 deals on 91 of the top 100 customers.
Record the changes that do nothing as carefully as the ones that work. The sales team added a description to the stage column, hoping the agent would apply the early-stage rule in its own SQL. Nothing moved across three runs, because the rule already lived in the metric, so they reverted it. The next domain reads that line in the iteration ledger before it spends a round on descriptions.
When to stop
Write the stop rule down before the first round, so nobody bends it later. Ours: stop when two rounds in a row move the score by no more than the run-to-run variation, and none of the fixes you predicted works. Count predicted fixes as well as the total, because a round can land its one fix while something else flickers. Cap the phase at five rounds. If the bar is still not cleared, report the ceiling honestly and take the gap to the sponsor.
Don’t raise the step budget to cut refusals
When the agent gives up too often, a bigger step budget looks like the easy answer. It turns refusals into confident wrong answers. A refusal tells you a decision is missing. Read the trace, find the decision and supply it. Keep the step budget where it was at the baseline.
Gate 3
The sponsor sees the score after each round, what broke and what was fixed, and the golden set grown to 50. The decision is to move to the launch gate.
Classify every miss before you fix it. Each kind has one fix and one owner.
Read the raw trace first and find the first step where the agent decided without context. Then walk the tree.
Is the key wrong? The agent’s answer is defensible and the key is not.
Yes. The eval owner re-runs the expected SQL, re-checks the source and reseals. Never edit the question.
No. Go to 2.
Did the step budget run out partway through?
Yes. Read what the steps were spent on and supply the missing decision. Raising the budget is not the fix.
No. Go to 3.
Is the right decision written down anywhere, as a metric, rule, business term or trusted query?
No. Never written. The context engineer drafts it, and provenance or the domain owner settles it.
Yes. Go to 4.
Was it served for this question? Look for it by name in the context call.
No. Written, not served. The context engineer fixes retrieval: a term link, alternate labels, ranking.
Yes. Go to 5.
Was it used?
No. Served, ignored. The context engineer and agent builder make it a rule the agent must follow, or make the SQL a metric.
Yes, and still wrong on every run. The gap is in the data: the state the answer needs does not exist, or the grain is wrong. The platform owner fixes it.
A miss on some runs and not others means the agent is guessing. Ask the question several times and compare the SQL. Where the runs split, a decision is missing.
Make one change per miss, record it, and rerun the whole set to see what else moved.
Work in rounds: a small batch of changes, then a full rerun. When two rounds in a row move the score no more than identical runs do, and no predicted fix lands, stop and take the gap to the sponsor.
Phase 4
Release and hand over
Launch on questions nobody climbed against, and hand over only what your team has run alone.
For sponsor, domain owner, eval owner, agent builder, platform ownerProduces launch decision, release note, handoverRead 6 min
WatchPhase 4: release and hand over2:19Read the transcript
The narration says "certified metrics", and the guide says "metrics": in the benchmark, no person approved the metrics. In the method, each metric's owner signs it off.
Here's the trap... a score earned on the questions you tuned against? It flatters the agent. This is Phase 4... release and hand over. Phase 3 closed at 18 of 20. So by now, the golden set had grown to 50. The graders drafted the new ones... and the context engineer never saw them.
The launch gate runs all 50, sealed ones included. Each one runs 3 to 5 times, and governed questions must be right on every run. Then 5 passing questions, picked at random, get re-graded by hand.
And everything that passed at the last gate? It still has to pass. On our benchmark, bare schema, just the tables, got 34 of 107 right. Add certified metrics, and the agent kept every one... 34 of 34.
So what if something falls short? You've got three moves. Ship without it and name it... move it to the exploratory lane... or climb one more round. The CRO signed the launch, and held one question type back, by name. How much pipeline did we create this quarter? It's wrong on every run, because no table records it.
Next, wire the agent to wherever your users ask. There are three paths. A platform agent with context pushed in... the same agent, calling it over MCP... or a custom harness. Whichever you pick, all three reach the same context layer.
On launch day, four checks have to hold. And the one that slips? Traces, reaching a store the team can read. Without traces, the launch waits.
Then you hand over. Everything left behind gets an owner on your side. The decisions log... who settled each conflict, and when... outlasts the rest. Even a model swap. Run one pass together, with the context engineer only watching. Then one alone, within two weeks. The engineer's on call... and nobody calls.
So the CRO signed on a score that was earned... not flattered. The rule? Launch on questions nobody climbed against, and hand over only what your team has run alone. Then keep it running. Domain two starts from what this one certified.
Phase 4 has two jobs. It proves the agent holds up on questions nobody climbed against. It also leaves a team that keeps the context true after the delivery team goes, so the score still holds next quarter.
Gate 4: is it ready to launch?
A score earned on the questions you tuned against flatters the agent. That is why the graders grew the golden set to 50 during Phase 3, with questions from outside the climb: new dashboard tiles, recent tickets, the sponsor’s own asks. Now run all 50 three to five times each. Tick this checklist at the gate review.
Definition of done
If something falls short, you have three moves: ship without it and name it, move it to the exploratory lane with the sponsor’s agreement, or run one more round of the hill climb. The engagement’s launch readout fit in five lines:
markdown
# Launch readout: Sales · end of Phase 4 · CRO, RevOps lead, FP&A partner, eval owner, delivery lead
Governed: right on every run, and "no metric" on every out-of-scope probe · CLEARED
Exploratory: above the Phase 0 bar on every run, after one golden answer was corrected · CLEARED
Pipeline created this quarter: wrong on every run; the warehouse holds no "created and still open" record · HELD BACK
Decision: GO WITH CONDITIONS · the held-back type returns once the platform owner builds the record · traces must flow on launch day, or the launch waits
Launch readout: Sales · end of Phase 4 · CRO, RevOps lead, FP&A partner, eval owner, delivery lead
Governed: right on every run, and “no metric” on every out-of-scope probe · CLEARED Exploratory: above the Phase 0 bar on every run, after one golden answer was corrected · CLEARED Pipeline created this quarter: wrong on every run; the warehouse holds no “created and still open” record · HELD BACK Decision: GO WITH CONDITIONS · the held-back type returns once the platform owner builds the record · traces must flow on launch day, or the launch waits
You chose the architecture and the surface in Phase 0. Phase 4 wires the release path to the context layer and checks it on launch day. Each path reaches the same context layer; they differ in how the context gets to the agent.
UIwhere users ask
Harnessthe loop, tools, prompts, traces
Modelthe LLM it calls
↕ MCP or API: context served, traces back
Context layermetrics, trusted past queries, rules and terms
Golden setsealed, never served: the eval owner keeps it apart and scores the agent against it
Platform-native
Databricks Genie, Snowflake CoWork. The platform supplies the chat and the model; you configure its agent: instructions, data scope, tools.
Custom
Google ADK, LangGraph or your own code. You build the harness, pick the model and put it in Slack, Teams, a BI tool or your app.
Both reach the same context layer over MCP or API. It serves the context and takes the traces back; the harness runs the agent and the SQL.
Figure 1
The same context layer behind every release path. A platform-native agent reads context pushed into the platform or calls the context layer over MCP or API. A custom harness makes the context call itself.
Release path
How context reaches the agent
What to watch
Platform-native agent
Pushed into the platform as semantic views, metric views or instructions
Stays inside the platform’s governance and permissions, with no extra service to run. Push again on every release.
Platform agent plus MCP
Called over MCP on each question
Name the connection in the agent’s instructions, and check the traces to confirm the call happens.
Custom harness
Your harness calls for context first, then runs read-only SQL
You own the tools, the step budget and the traces.
Keep every definition in one store any harness can read, so the next harness change is only a wiring job. Four things must hold on launch day:
The agent asks for context before it writes any SQL. Confirm it in the traces.
Governed questions run the metric’s SQL as served. When no metric matches, the agent says so.
Governed answers run under a fixed service identity, so a board number is the same for every asker. Exploratory queries run under the user’s own identity.
Traces reach a store the review team can read: every context call, what it returned, every SQL statement and the answer.
The fourth slips most often. Without traces there is no loop, so the launch waits.
Hand over: one pass together, one alone
An agent that clears its bar is half the job. The other half is a team that can produce the next score alone. Each thing left behind needs an owner on your side and a version.
What stays
Owner after handover
Reused as
Metrics
The owning team for each
The one definition every later agent and domain calls
Golden set of 50
Eval owner
The full rerun on every context change. The questions it gets right on every run form the regression set, rerun on every schema change
Decisions log
Domain owner
Precedent: the next conflict on the same concept starts here
Rules and business terms
Domain owner
Shared by every domain that uses the same words
Trusted past queries
Their authors, approved by the domain owner
The exploratory lane’s library
Trained owners
Exec sponsor
The people who run domain two
The decisions log outlasts the rest. It records every place two defensible definitions were in use, who decided, and when. It survives a model swap or a harness rewrite.
The handover takes three steps:
Walk the assets. Each owner uses their own asset while the context engineer watches.
Run one pass together. The team runs a full improvement round end to end: it decides the open conflicts, reruns the golden set and records the result. The context engineer only watches.
Run one pass alone within two weeks. The context engineer is on call and nobody calls. Your team writes the record.
One round together · phase 4
The team runs it; the context engineer watches
Trigger
planned: the open conflicts that touch a released metric
Decides
domain owner
Runs
agent builder
Grades
eval owner
Context engineer
in the room, watching only
Result
a new layer version; regression set (the 45 questions right on every run): 45 of 45
One round alone · after launch
Forced by a schema change, a week early
Trigger
the platform owner's schema alert
Fixes
an analyst re-issues two trusted queries
Approves
domain owner
Runs
the regression set on staging: 43 of 45, then 45 of 45
Records
eval owner logs the result
Context engineer
on call; nobody called
Result
done in three days, a week before it was due
The handover test: could your team run the next round with the delivery team gone? The second round says yes, and the team chose none of it.
Figure 2
The two handover passes side by side: who triggered, decided, ran, graded and recorded each one, and where the context engineer was.
In the running example, a schema change after launch forced the solo pass early, a harder test than a planned one (Keep it running tells the story). Test the handover with one question: could your team run the next round with the delivery team gone? If the answer depends on a script, a notebook or a person the delivery team brought, move it into your repository, give it an owner, or throw it away.
The launch gate, as a checklist. The sponsor signs when every line holds.
The golden set:
At least 50 sealed questions, including new ones the context engineer never saw.
Every question run several times. A governed answer counts only if it is right on every run.
The random pass audit done: five passing items re-graded by hand against their source.
The results:
Governed questions right on every run.
Exploratory questions at or above the pass rate the sponsor set in Phase 0.
Everything that passed at the last gate still passes.
Out-of-scope governed questions refused, with no number. No question bound to the wrong metric.
Any kind of question that can’t pass is named and held back, with an owner and a date.
The context:
Every served metric, rule and business term has an owner, a version and a record of why it was approved.
No open conflict is served. Each waits in the backlog with a date.
Running it:
Production traces reach your log store, per call.
A rerun of the golden set fires on every context change and every schema change, and someone owns it.
The previous version can be restored in one step, and someone is named to decide.
The first run your team does alone is on the calendar, within two weeks.
Decision: go, no-go, or go with conditions. Each condition has an owner and a date. Never lower the bar to fit the score.
Exec sponsor
Decision
Date
After launch
Keep it running
Feed real usage back into the context, or it goes stale within a quarter.
For domain owner, eval owner, agent builder, platform owner, exec sponsor, delivery leadProduces the production loop, drift triggers, the domain-two plan, the ceremonies and the gatesRead 11 min
Launch is where the agent meets questions nobody wrote down. From here the job changes: keep the context true as the business moves, use what domain one built to start the next one faster, and run the whole thing on gates rather than dates. Your team runs all of it, with no outside help.
Run the production loop
Your users will ask hundreds of questions the golden set never held. Each one comes with a trace, and the ones that recur are golden-set candidates. Two events in the first weeks after launch show the two halves of the loop.
A regional VP asked for open pipeline with the top customers in EMEA, then replied, “Wrong. My tracker is well above that.” The trace showed the metric’s SQL, matching the board pack. The VP’s tracker counted renewals and early stages the metric leaves out. The correction became a proposed change for the owners, never applied on its own. In ten minutes they kept the board number, added a note under every answer (“excludes renewals and early stages”), and put a renewal-pipeline metric in the backlog.
Then a schema alert fired: billing would retire a deal-amount column. The regression set ran on a staging copy first, and two questions failed. Both leaned on past queries that read the dying column. The agent had rewritten them from the schema and lost the rule about early stages. No user would have seen an error, only a plausible wrong number. The queries’ author re-issued them, the RevOps lead approved, and the rerun came back clean.
Every week after launch: the trace hour
signalsTraces of every answer, steps logged as "context not enough", user corrections, runs that disagree on real questions.
filedA correction becomes a proposed edit and a split between runs a conflict; neither applies itself.
decidedRead the raw traces, classify with the tree; the domain owner settles each queue item.
releasedApproved changes batched into a release candidate; the gate runs; the eval run ships with it. Served to users, whose questions are the next signals.
A regional VP called a pipeline number wrong; their tracker counted renewals and early stages. The owner kept the metric, added a note to it, and put a renewal-pipeline metric on the backlog.
On a trigger: a schema change, cleared in three days
day 1Platform owner's alert: a source column will be retired next week.
day 1Regression set on staging, the 45 golden-set questions right on every run, 3 runs each: 43 of 45.
witness38 trusted queries rerun: 36 OK, 2 fail and are quarantined; metrics 6 of 6 OK.
day 2Their author moves both to the new column; the domain owner approves a new version of each.
day 3Rerun: 45 of 45. Change cleared and logged by the eval owner, with no call to the delivery team.
Figure 1
After launch, two loops keep the context current. Real use turns into proposed changes that the domain owner decides each week. A schema change triggers a regression run before it reaches production.
Run the loop every week, in one trace hour:
Read the raw traces of every flagged answer and a sample of the rest. Owner: agent builder, with the domain owner.
Pull every step where the agent logged that its context was not enough, and classify each miss.
Ask the most common real questions several times. A split between runs means a decision nobody made. File it as a conflict.
Decide the queue: corrections, conflicts and gap fixes. Owner: domain owner.
Batch the approved changes into the next release and run the gate. Owner: eval owner.
Corrections are the richest signal and the easiest to mishandle. Each arrives sounding like a bug, and often the user simply holds a different definition.
Rerun the set on every drift trigger
The business moves under the context, and nothing announces the move. A realignment, a pricing change or a retired column changes no line of the context. So handle drift with triggers, each with an owner. A context version with no eval run behind it is still a draft.
Trigger
What reruns
Owner
A schema change on any table the context touches
The regression set: the golden-set questions already right on every run. Run it on staging first if you can
Platform owner
Any context change: a metric, rule, term or trusted query
The full golden set
Eval owner
Any harness change, including its model or instructions
The full golden set
Agent builder
A business event: a reorg, a pricing change, a new fiscal rule
The questions on what it changed; the change is recorded with its date
Domain owner
A new kind of question in the traces
Nothing yet; it becomes a golden-set candidate
Eval owner
Keep the previous release deployable, so rollback takes one decision.
Domain two
Domain two inherits what domain one built: house rules, shared entities, business terms, the grading method and the release process. Plan it while the knowledge is still in the room.
Domain one · SalesBuilt in five phases, owned by the RevOps lead: 6 metrics, 5 rules, 12 terms. The FP&A partner has co-owned "Top accounts" since phase 3.
Inherited as is: term "Top accounts" · rule quarter-means-fiscal · rules "early stages never count" and "internal and test accounts out" · entities Account and Opportunity · grading rubric v1 · the release process and its rerun triggers
Domain two · FinanceBuilds its own: its own brief and access list, with security approving the billing and ledger schemas · a golden set of 20+ · metrics for bookings, net new ARR and churn ARR · its own conflicts to resolve. The same five phases
"Quarter" · settledFiscal, in both domains.
"ARR" · contested. Sales reads the latest term's value; Finance reads recognised ARR at period end.
"Customer" · contested. Sales reads an active term; Finance a paid invoice.
Missing: a cross-domain arbiter. Each owner decides for their own domain, neither over the other, so when they disagree nobody decides. The sponsors name one before Finance's brief is agreed; until then neither domain redefines "ARR" or "customer" alone.
Figure 2
What finance inherits from sales with no new decision, what it builds itself, and the shared words that still need an arbiter.
Pick the next domain from those that share tables, entities and words with the first. Owner: exec sponsor, with the delivery lead.
List what it inherits with no new decision, and what it must build. Owner: context engineer.
List the words both domains use, and mark each as settled or contested.
Name the domain owner and their hours. Owner: exec sponsor.
In the engagement, finance came next. It inherited “top 100 customers”, the fiscal quarter and the rule on early stages. It still built its own golden set, metrics and queue. Two words were contested. Sales reads “ARR” as the latest term’s value, and finance reads it as recognised ARR at period end. Sales counts a customer by an active term, and finance by a paid invoice. Each owner could decide for their own domain, and neither could overrule the other. Name an arbiter before the new domain starts: one executive with authority over both functions. Until then, freeze the contested words, so neither domain changes them alone.
Answer why
“Why did pipeline drop in EMEA?” is what an executive asks as soon as the number lands, often at the first readout. An agent with only metrics restates the drop. To explain it, the agent has to know how your business works and what changed in it this quarter. That is a second kind of context, and it is built only after the numbers hold: a why-answer explains a movement in a number, and if the number is wrong, the explanation is a confident story about a figure nobody should trust. Write the why-question down with its date and finish the what-questions first.
A map of the business, and a record of what changed
The first piece is an ontology: your business drawn as a graph and tied to your data. Its entities are the things the business talks about, such as rep, deal, customer, territory and stage history. The links between them carry rules the agent can reason with: a territory is owned by a rep, and when it changes hands the new rep re-qualifies its deals; a deal re-signed on new terms goes back to an early stage. Each entity points to the tables that hold it and to the metric that measures it, so the agent knows where to compute instead of guessing.
The second piece is a dated record of what changed in the business: a territory realignment, a pricing change, a reorg, a new comp plan, each tied to the entity it touched and the team that owns it. Without this, the agent can list every way pipeline might fall and still cannot say which one happened this quarter. A stronger model does not fix that. It can reason about causes, but it cannot test a change nobody wrote down.
Opportunitycrm.opportunity · metrics: open pipeline, top accounts; win rate
Accountcrm.account · term "Top accounts"
Territorycrm.territory
Repcrm.rep
Stage historycrm.stage_history
Rep works Opportunity · Opportunity belongs to Account · Account sits in Territory
Territory owned by Rep. Rule: on an owner change, the new rep re-qualifies the deals.
Opportunity moves through Stage history. Process: re-signing a deal on new terms returns it to the first stage.
Mid-quarter · Finance. Enterprise pricing change; open deals re-signed on the new terms.
First cause: $31M41 deals changed owner in the realignment and have not moved since.
Second cause: $19M9 Enterprise deals re-signed on the new terms went back to the first stage.
EMEA fell $53M ($214M → $161M). NA and APAC held; deal creation flat; season ruled out.
Figure 3
The slice of the business behind the EMEA answer: five entities tied to their tables, two business rules, two dated changes, and the two causes the agent measured in SQL.
The EMEA question, worked through
Without this context, the agent summed open amounts by country and returned a percentage. With it, the agent worked in three steps:
Find the possible causes. The metric showed EMEA down while North America and APAC held. The graph listed what this pipeline moves with: new deals, owner changes, deals re-signed on new terms, and the season.
Rule some out. New deals were flat, and last year’s numbers ruled out the season. The two causes left each matched a dated change: the territory realignment and the pricing change.
Measure the rest in SQL. Using a trusted past query on days since a deal last changed stage, the agent counted the deals behind each cause.
text
EMEA pipeline with the top 100 customers fell $53M. North America and APAC held.
New deals were flat, and last year rules out the season.
$31M sits in deals that changed owner in the territory realignment and have not moved since.
$19M sits in Enterprise deals re-signed on new terms after the pricing change, which sent them back to an early stage.
The remaining $3M has no single cause.
The one why-answer that fell short in the running example traced to a comp-plan change nobody had written down. Ask the owning teams to record each change when it happens, Sales Ops for territories and Finance for pricing, as part of their weekly work.
Build it only where systems or history need linking
Metrics carry most of a why-answer. The ontology adds the most where one entity has to be linked across two systems, or where the answer turns on a deal’s history. It is the wrong tool for what-questions, and it is one more thing for owners to keep current.
If you do build it, keep it small: seal five to ten real why-questions, each with its list of expected findings; import what exists first (the glossary, BI semantic models, any existing ontology) and cut it down to what those questions touch; have the domain owner approve every link an answer depends on; tie each entity to its tables and metric and check each tie runs; serve it for why-questions only, and rerun the what-question regression set on every release.
No benchmark covers why-questions yet. Treat this tree as judgment.
Are the numbers released and stable, the same answer twice on the full golden set?
No. Not yet. Go back to the hill climb. A number that changes between runs has nothing to explain.
Yes. Go to 2.
Does the domain live in one system, with one schema and one set of keys?
Yes. Rules carry the why. Write the business processes as rules, such as “a deal re-signed on new terms goes back to the first stage”, and stop.
No. Go to 3.
Is there an entity to link across systems, or a history of changes to reason over?
No. Not worth it yet. Metrics carry most of a why-answer; the ontology helps where it links systems or reasons over history.
Yes. Go to 4.
Will a team record what changes in the business, with dates?
No. Start that record first. Without dated changes the agent has no cause to test.
Yes. Build it.
To build it:
Seal the why-questions first, each with a written list of the findings you expect.
Import what exists: the glossary for entities and vocabulary, the BI semantic model for bindings.
Cut it to what those questions touch. The running example needed five entities. Its answer turned on two of their relationships.
Bind each entity to its tables and metrics.
Have the domain owner approve the relationships the answers turn on.
Name an owner for each kind of dated change, such as territories or pricing.
The record of what changed is the part that decays. In the running example, the one why-answer that fell short traced to a comp-plan change nobody had written down.
Run the ceremonies
The delivery lead, whether a forward-deployed engineer, a partner consultant or an internal program lead, owns the calendar and the ceremonies and holds the gates. The delivery lead never decides a definition and never grades an answer. Those belong to the domain owner and the eval owner. If the delivery lead makes those calls, the numbers stop belonging to the business, and nobody owns their accuracy after they leave.
Each phase ends at a gate, and each gate is one decision: pass, hold or stop. What the sponsor sees at each gate lists what passes each one. A stop is a legitimate result. Four ceremonies carry the engagement. Book all of them through Phase 4 before the kickoff ends. Each one produces something written.
Kickoff · 90 min Phase 0
The whole room; the brief walked item by item.
Working session · 60 min each phase
Where decisions happen. Weekly if a phase runs longer.
Readout · 30 min each phase
Sponsor, domain owner and you: one page, one decision. It runs straight into the gate review.
Gate review · 45 min pass, hold or stop
Phase 0Brief agreed, access open
Phase 120+ questions sealed, baseline run
Phase 2Metrics scored
Phase 3Misses closed, set grown to 50
Phase 4Launch gate
Figure 4
The four ceremonies on one calendar, from the kickoff in Phase 0 to the launch gate at the end of Phase 4.
Ceremony
When
Who
What it produces
Kickoff, 90 minutes
Phase 0
Sponsor, domain owner, eval owner, agent builder, platform owner, security, the delivery lead
A signature on each checklist item, or an owner and a date
Working session, 60 minutes
Each phase, weekly if a phase runs longer
Domain owner, agent builder, eval owner, context engineer, the delivery lead
Decisions on conflicts and changes, and the latest score
Readout, 30 minutes
Each phase
Sponsor, domain owner, the delivery lead
One page and one decision
Gate review, 45 minutes
End of each phase
Sponsor, domain owner, eval owner, the delivery lead
Pass, hold or stop, written and signed
At the kickoff, teach before you ask. Open with one real question from their business and let the room find the rules hidden in it, using the exercise in Why it is hard. Then walk the checklist; the full agenda is the kickoff agenda template. The working session is where decisions happen, and its agenda is fixed: the score since the last session, the misses read from traces, changes waiting for approval, and conflicts waiting for a decision. The sponsor will ask for things the plan deferred. Log each one in the backlog with a date, and say when it comes back. “Go with conditions” is a pass with debts: check each condition on its date, because one that slips past unchecked has quietly lowered the bar.
What to do when things stall
A stall usually shows up first as a date that slips. Treat the slip as the signal, whatever caused it, and make the same four moves: log it the day you see it, with an owner and a date; keep working on everything that does not depend on it; take it to the sponsor at the next readout, or the same day if it is both likely and serious; and hold the gate it affects, without absorbing the stall by deciding yourself or starting the next phase early.
Stall
First sign
Your move
Who decides
The domain owner disappears
Conflicts wait a week undecided
Ask for the hours back, or a named deputy with a vote
Sponsor
Access is blocked
A request sits with no owner
Log it; in Phase 0 the clock waits
Platform owner, then sponsor
The sponsor moves the bar
A new target in a readout
Record the new bar and its date; score the last run against both
Sponsor
Someone asks the delivery team to host the agent
“Just for the pilot”
Decline; the agent builder stands it up in the company’s environment
Sponsor
Scope creeps into a second domain
New questions from another team
Log them for domain two; keep them out of the golden set
Sponsor
Security review stretches Phase 0
Weeks pass on one approval
Start the review early; keep the gates, stretch the calendar
Security lead, with the sponsor
In our engagements, the stall that cost the most time was an owner who could spare only minutes a week. Decisions queued, and the gates slipped behind them. Ask for the hours back as soon as the queue starts to grow.
Three more things the delivery lead owes the company, each on one page: the boundaries that hold when a partner firm delivers, Deliver as a partner; the anonymised note on what moved the score, so the next engagement costs less, Pattern write-up; and a blameless postmortem at the end of each engagement and whenever a gate slips or a wrong governed number reaches a user, Field postmortem.
The domain owner disappears. Conflicts wait unresolved past a weekly session. Let provenance settle what it can, then raise the rest with the sponsor at the next readout. Ask for the hours back, or a named deputy who can decide. The context engineer never decides a definition. Decides: exec sponsor.
Access is blocked. A test fails or a request stalls. Log it that day with an owner and a date. In Phase 0 the clock does not start. Mid-phase, work what needs no access and take the blocker to the next readout. Decides: platform owner, then the sponsor.
The sponsor changes the bar. Record the new bar and its date. Score the last run against both bars. Leave the golden set alone. Agree in writing what the launch gate now tests. Decides: exec sponsor.
You are asked to host the agent for the company. Decline. The harness stays with the company that runs it. The delivery team helps the agent builder stand up the minimum harness in the company’s environment. Decides: exec sponsor.
Scope creeps into a second domain. Log the new questions in the domain-two plan. They stay out of the golden set until launch. Decides: exec sponsor.
Security review stretches Phase 0. Where vendor review applies, Phase 0 can take months. Hand out the access list on day one, walk security through what leaves the building, and keep the gates. Phase 1 starts when the checklist is met. Decides: security lead, with the sponsor.
Whatever the stall, the clock does not start early and the bar does not move quietly.
Toolkit
Reading paths
Read 3 min
Pick the row that matches your job. Each one has a podcast, a recommended reading list and the cards that go with it. You can also listen to all three episodes.
I’m sponsoring it
You are the exec sponsor, or the data leader who will answer for the agent. The risk you are buying down is a wrong answer that looks right.
You are the delivery lead: a forward-deployed engineer, a partner consultant or an internal program lead. You want to know what happens in each phase and what to do when a week goes wrong.
Watch. The method page, the opening chapter and each of the five phases open with a short narrated video, two to five minutes long. Videos plays them all back to back.
Ten minutes. Turn on Skim in the top bar, or press S. Each chapter shrinks to its rule, an “In one minute” box, its key figure and its section headings. Click any heading to open the full section.
The whole thing. About an hour and a half for the chapters, and about another hour and a half for the toolkit, the research and the reference. Pick a reading path above for your role and the contents will mark your chapters.
Press ? anywhere for keyboard shortcuts.
About this book
Published by Atlan. The book is licensed under CC BY 4.0: copy and adapt it with credit. The code that builds it is under the MIT License. Product names are their owners’ trademarks. Maintained by the playbook maintainers. A change to any number must include its source evidence, and every change goes through review by the maintainers.
Toolkit
Where are you starting?
Read 2 min
This page takes about fifteen minutes to answer honestly. Ten questions score your readiness, and every 0 points you to the chapter that closes it. Questions 3, 9 and 10 are gates: a 0 on any of them means you are not ready to start Phase 1, whatever your total. Phase 0 is where you close them. You can copy the result into your success document.
Questions 1 to 10 · Readiness. Score each answer 0, 1 or 2.
#
Question
0
1
2
If you scored 0, read
1
Have you picked one domain, with its problem statement and its users?
Run Phase 0 as a project of its own. Read Phase 0 first and take the gaps to your exec sponsor.
8-14
Ready for Phase 0
Read Phase 0 and close every 0 there, gates first. The chapters listed under your zeros are your reading list.
15-20
Ready to start Phase 1, unless a gate is at 0
Run the Phase 0 checklist in Phase 0, then start Phase 1. A 0 on question 3, 9 or 10 means not ready, whatever the total.
Toolkit
Cards
Read 18 min
Cards are one-page checklists you can print. Most close a chapter, and each stands on its own, so you can pin the one you need by your desk and leave the book closed.
Card
The whole method
Scope one domain, build the golden set, generate and approve metrics, hill-climb from traces, release and hand over. Real traces feed the next version, and domain two starts from what domain one built.
Five phases: Phase 0 to set up, then Phases 1 to 4 to build, test and launch. Each phase ends at a gate, and you move on only when it is met.
Phase 0, before the clock. Pick one domain and decide which questions need an exact answer. Settle access and the agent architecture. Name the owners and their hours. Gate: the brief agreed, every access item proved.
Phase 1, the golden set. Harvest real questions, seal at least 20 with verified answers, and run the baseline once. Gate: 20 or more sealed, baseline scored.
Phase 2, generate metrics. Draft them from past SQL and BI, check them against the warehouse, resolve conflicts, approve. Gate: the metrics scored on the same set.
Phase 3, the hill climb. Read the raw trace of every miss and make the smallest fix that closes it. Gate: the misses closed that can be, and the set grown to 50.
Phase 4, release and hand over. Pass the launch gate, launch, and hand the loop to your team. Gate: launch approved, first solo run booked.
The rules:
Fix the context before you change the model. A better model can’t guess a rule nobody wrote down.
Write each business rule into a metric’s SQL. The agent follows a query and skims a paragraph.
Build the golden set before any context. Without it, you can’t tell progress from luck.
Settle conflicts before the agent sees them: provenance first, then the owner. Never let the agent pick.
Board numbers need a metric, or no answer.
Start with one domain and the people who own its numbers.
Read the raw trace of every miss, and feed real usage back.
Make the agent reliable on what happened before you ask it why.
The five phases leave you metrics your business owns, a golden set that tests each change, and a team that runs the loop without help.
Card
The sponsor's ask
Phase 1 can’t start until you make five decisions:
The domain: one business area, its problem and its users.
The bar: exact on every run for the numbers the business runs on, and one pass rate for everything else, written down now.
The agent architecture: where people ask, which harness runs the loop, and which model.
The people: a name and weekly hours next to every role.
The start date. Phase 0 ends when the brief is agreed and every access item is proved.
At the end of Phase 4 you decide go, no-go or go with conditions.
Your people’s weekly hours are set in Phase 0. The domain owner’s two to three hours a week matter most: engagements stall where the owner can spare only minutes.
Go when the governed questions are right on every run, the rest clear your pass rate, and nothing that passed before has broken. Give each condition an owner and a date.
Exec sponsor
Signature
Date
Card
The eval owner's week
You own the golden set. The context engineer never drafts, sees or edits an expected answer.
The tasks, in order:
Name the graders and fix the as-of date every answer is computed at.
Harvest two or three candidates for every question you will seal. Pull them from the board pack, dashboards, tickets, saved analyst queries and the sponsor’s own questions.
Rewrite each candidate the way a user would ask it, with no table or column names.
Graders draft the expected SQL and answer for each one.
Write the grading rules before any result exists: returned data first, then the SQL, with a tolerance per answer type.
Graders verify every draft against its source. A question with two defensible answers goes to the domain owner before it is sealed.
Pick at least 20 that cover both governed and exploratory questions. Seal them.
Purge every past query that computes a sealed answer, by hash. Commit the set.
The agent builder runs the baseline once per question. You grade it and record the decision the agent guessed on every miss.
Every item carries six required fields: id, the question as asked, lane, source, expected result and expected SQL. Optional: valid alternatives, tolerance, the decisions the question hides, the wrong answer a guess would produce, and a history of every correction.
An item is sealed when its expected SQL has run read-only on the as-of snapshot, the result matches the trusted source, no dispute is open, and you have signed it. Store the set where neither the agent nor the context side can read it. Never edit a question to make the agent pass.
A definition dispute raised while sealing also goes to the conflict list, with no sealed value attached. Otherwise the context side never sees it.
Card
The builder's minimum harness
The harness runs in your environment and your team owns it. Two shapes work: platform-native, such as Databricks Genie or Snowflake CoWork, or custom, on Google ADK, LangGraph or your own loop.
Build this and stop:
One context call per question, before any SQL. At baseline it returns the schema only.
One read-only SQL tool. Exploratory queries run as the user. Governed answers run under a fixed service identity, so a board number is the same for every asker.
A step budget: a fixed cap on tool calls per question. Don’t raise it to cut refusals. A bigger budget turns refusals into wrong answers.
On a governed question, run the metric’s SQL with only its declared parameters filled in. No metric, no answer.
A per-call trace: every served item by name and version, each tool call with its arguments and result, every SQL statement including failed ones, the answer or refusal, tokens, steps and time.
The context call goes in with three things:
the question text, unedited
the domain whose context to search
the user’s identity, passed through
It comes back with five:
metrics: name, version, SQL, owner, provenance
trusted past queries: the top matches, each as complete SQL
the rules that apply, as instructions
the business terms the question matched
the lane: governed when a metric covers the question, otherwise exploratory
Fix the shape of the call on day one. In Phase 2 the metrics arrive behind the same call and nothing else changes, so later scores compare with the baseline.
You can change the model later. When you do, rerun the golden set on the new model before comparing scores.
Card
How to resolve a conflict
A conflict is two definitions of the same thing, both in use. Most settle on evidence; the domain owner decides the rest in a short session.
First, let provenance decide. For each variant, the context engineer shows:
who runs it, and how many different people
how often, and how recently
whether it runs clean and matches the warehouse
which dashboards and reports it feeds
When one variant is run by most analysts, recently, runs clean and matches the trusted report, keep it and record why. No meeting needed.
When the evidence splits, it goes to the owner. The day before, the context engineer prepares each variant’s definition as SQL, where it is used, and both results on the snapshot.
The owner resolves it one of five ways:
Choose a variant.
Name an authoritative source table.
Add a population rule, such as “internal and test accounts are out of every number”.
Retire an object.
Dismiss it, with a note.
If another team owns part of the definition, its owner co-approves.
Example: the top-100 conflict. One variant ranked customers by number of deals. It fed the sales ops dashboard and had plenty of query history, so Phase 2 approved it. The other ranked by current ARR and fed the finance board pack, but its list lived in a spreadsheet and never appeared in query history. Provenance could see only one side. In Phase 3 the raw trace of the pipeline question surfaced the gap. The RevOps lead and the FP&A partner chose ARR in 20 minutes and also wrote “some early stages never count” into the metric. Sales ops kept its tile, renamed “most active accounts”.
What happens next:
The context engineer records the decision and what would reopen it. The losing variant is retired and kept on record.
The metric is re-rendered and checked against the warehouse again.
The agent builder reruns the questions that depend on it.
A definition kept in a spreadsheet leaves no trace in query history, so provenance can’t rank it. Before approval, trace any pasted list of IDs back to its source.
Card
Why did this miss?
Is the key wrong?
yesEval owner corrects and reseals the key. Never edit the question to fit the agent.
Did the step budget run out?
yesRead what the steps were spent on and supply the missing decision. Never raise the budget: it trades abstentions for wrong answers.
Does the decision exist anywhere in the layer?
noNever written · the most common miss. Write the definition into a metric; the domain owner settles it.
Was it served for this question?
noWritten, not served. Fix retrieval so the right item arrives: term links, ranking.
Was it used?
noServed, ignored. Make it a rule the agent must follow, or make the SQL a metric so the wrong path is impossible.
yesIn the data, still wrong on every run. The state the answer needs does not exist, or the grain is wrong. The platform owner fixes it.
Figure
Classify every miss before you fix it. Each kind has one fix and one owner.
Read the raw trace first and find the first step where the agent decided without context. Then walk the tree.
Is the key wrong? The agent’s answer is defensible and the key is not.
Yes. The eval owner re-runs the expected SQL, re-checks the source and reseals. Never edit the question.
No. Go to 2.
Did the step budget run out partway through?
Yes. Read what the steps were spent on and supply the missing decision. Raising the budget is not the fix.
No. Go to 3.
Is the right decision written down anywhere, as a metric, rule, business term or trusted query?
No. Never written. The context engineer drafts it, and provenance or the domain owner settles it.
Yes. Go to 4.
Was it served for this question? Look for it by name in the context call.
No. Written, not served. The context engineer fixes retrieval: a term link, alternate labels, ranking.
Yes. Go to 5.
Was it used?
No. Served, ignored. The context engineer and agent builder make it a rule the agent must follow, or make the SQL a metric.
Yes, and still wrong on every run. The gap is in the data: the state the answer needs does not exist, or the grain is wrong. The platform owner fixes it.
A miss on some runs and not others means the agent is guessing. Ask the question several times and compare the SQL. Where the runs split, a decision is missing.
Make one change per miss, record it, and rerun the whole set to see what else moved.
Work in rounds: a small batch of changes, then a full rerun. When two rounds in a row move the score no more than identical runs do, and no predicted fix lands, stop and take the gap to the sponsor.
Card
Which lane?
Is it a why-question?
yesDeferred until the what is released; then the ontology and dated changes.
If the answer is wrong and nobody notices, where does it land?
board pack, finance close, published KPIGoverned lane. Exact, every time; metric or no answer. The pipeline question: $412M.
a decision about where to look nextExploratory lane. Directionally right; SQL and sources shown. The slipped-deals question: 96 slipped, 31% win rate.
Later: do two people publish different numbers for it?
yesIt has become governed. Write its metric, resolve the conflict, move it.
Figure
Ask it of each kind of question in the brief, not of every question one by one.
The sponsor and the domain owner walk this at the kickoff, in about 30 minutes. Why-questions wait until the numbers under them are right.
If this answer is wrong and nobody notices, where does it land?
In a board pack, a finance close or a published KPI. The question is governed.
The bar is exact, on every run.
The answer comes from a metric, whose SQL runs as served.
If no metric covers it, the agent says so. No metric, no answer.
In a decision about where to look next. The question is exploratory.
The bar is one pass rate for the whole lane, set by the sponsor now, before any result exists.
The agent writes the SQL, grounded in trusted past queries.
Every answer shows its SQL and its sources.
Later, in production: do two people publish different numbers for an exploratory question?
Yes. It has become governed. Resolve the conflict, write the metric, move it.
No. Leave it where it is.
In the running example, open pipeline with the top 100 customers is governed: it lands in the board pack. Slipped deals are exploratory: they tell a sales leader where to look.
Card
Is an ontology worth it?
Are the what-questions released and stable?
noNot yet. Go back to the hill climb. Explaining a number you cannot state consistently explains nothing.
Does the domain live in a single system?
yesRules carry the why. Write the processes as rules ("a re-signed deal returns to the first stage") and stop.
Is there cross-system identity to resolve, or lifecycle history to reason over?
noNot worth it yet. Metrics carry most of the answer.
Will a team date each change?
noStart that record first. Without it the agent describes the business, not what moved it.
yesBuild it. Import what exists, cut to the why-set's subgraph, bind entities to tables and metrics, record dated changes. Metrics carry most of the answer; the dated changes explain the move.
Figure
Three stop conditions, then one precondition.
No benchmark covers why-questions yet. Treat this tree as judgment.
Are the numbers released and stable, the same answer twice on the full golden set?
No. Not yet. Go back to the hill climb. A number that changes between runs has nothing to explain.
Yes. Go to 2.
Does the domain live in one system, with one schema and one set of keys?
Yes. Rules carry the why. Write the business processes as rules, such as “a deal re-signed on new terms goes back to the first stage”, and stop.
No. Go to 3.
Is there an entity to link across systems, or a history of changes to reason over?
No. Not worth it yet. Metrics carry most of a why-answer; the ontology helps where it links systems or reasons over history.
Yes. Go to 4.
Will a team record what changes in the business, with dates?
No. Start that record first. Without dated changes the agent has no cause to test.
Yes. Build it.
To build it:
Seal the why-questions first, each with a written list of the findings you expect.
Import what exists: the glossary for entities and vocabulary, the BI semantic model for bindings.
Cut it to what those questions touch. The running example needed five entities. Its answer turned on two of their relationships.
Bind each entity to its tables and metrics.
Have the domain owner approve the relationships the answers turn on.
Name an owner for each kind of dated change, such as territories or pricing.
The record of what changed is the part that decays. In the running example, the one why-answer that fell short traced to a comp-plan change nobody had written down.
Card
What to do when
Six stalls, what you do, and who decides.
The domain owner disappears. Conflicts wait unresolved past a weekly session. Let provenance settle what it can, then raise the rest with the sponsor at the next readout. Ask for the hours back, or a named deputy who can decide. The context engineer never decides a definition. Decides: exec sponsor.
Access is blocked. A test fails or a request stalls. Log it that day with an owner and a date. In Phase 0 the clock does not start. Mid-phase, work what needs no access and take the blocker to the next readout. Decides: platform owner, then the sponsor.
The sponsor changes the bar. Record the new bar and its date. Score the last run against both bars. Leave the golden set alone. Agree in writing what the launch gate now tests. Decides: exec sponsor.
You are asked to host the agent for the company. Decline. The harness stays with the company that runs it. The delivery team helps the agent builder stand up the minimum harness in the company’s environment. Decides: exec sponsor.
Scope creeps into a second domain. Log the new questions in the domain-two plan. They stay out of the golden set until launch. Decides: exec sponsor.
Security review stretches Phase 0. Where vendor review applies, Phase 0 can take months. Hand out the access list on day one, walk security through what leaves the building, and keep the gates. Phase 1 starts when the checklist is met. Decides: security lead, with the sponsor.
Whatever the stall, the clock does not start early and the bar does not move quietly.
Card
What the sponsor sees at each gate
One decision per gate. Hold means the next phase waits.
Gate
You see
You decide
Go when
Hold when
End of Phase 0
the brief, the access tests, the named owners
start the clock
every access item proved; a name in every role
any item untested or unowned
End of Phase 1
20 or more sealed questions; the baseline score; the decision guessed on each miss
start the metrics work
every item verified against its source
a dispute open or an item unverified
End of Phase 2
the metrics scored on the same set; the change over baseline; conflicts resolved and open
start the hill climb
every served metric checked, owned and versioned
a disputed or unowned metric is served
End of Phase 3
the score after each round of fixes; what broke and what was fixed; the set grown to 50
move to the launch gate
the new questions sealed; nothing that passed has broken
the set short of 50, or a break unfixed
Launch gate, Phase 4
the 50, each run several times; governed and exploratory against their bars; the random pass audit; refusals
go, no-go, or go with conditions
governed right on every run; exploratory at its bar
a lane short: hold that kind of question back, or run one more round
At every gate, the eval owner re-grades five passing items by hand, and the score is reported after any correction.
At the launch gate, also check how the governed lane fails. It should refuse questions it has no metric for, and it should never bind a question to the wrong metric.
Expect a low baseline. It prices the decisions your schema leaves out.
A no-go names each gap and who owns its fix. Go with conditions names each condition, its owner and its date.
Card
What you need before you start
Two lists: the access, and the people. Request everything on day one. An access item is done when its test passes.
Access:
Read-only warehouse access for the domain’s tables (required). Test: a query runs under it.
Query history for the domain (required). Test: the export has rows and a date range.
BI reports and semantic models: required if you have them. Test: the export opens.
Trace export from your harness (required): the context served, every SQL statement, the answer. Test: one trace read end to end. Start this first; it is the item that arrives last.
Where users will ask, named: the chat surface or tool your users will ask in.
People, on your side:
An exec sponsor who sets the bar and decides at each gate.
A domain owner with 2-3 hours a week, and a co-owner if another team owns part of a definition.
An eval owner and two graders who know the domain.
An agent builder.
A platform owner and a security lead, mostly in Phase 0.
People who run the engagement, from a partner or your own team:
A context engineer (in-house: an analytics engineer), dedicated from Phase 1 to Phase 4.
A delivery lead (in-house: your program lead), who runs every session and gate.
Put a name next to every line. “RevOps” cannot resolve a conflict. The RevOps lead can.
Card
Is it ready to launch?
The launch gate, as a checklist. The sponsor signs when every line holds.
The golden set:
At least 50 sealed questions, including new ones the context engineer never saw.
Every question run several times. A governed answer counts only if it is right on every run.
The random pass audit done: five passing items re-graded by hand against their source.
The results:
Governed questions right on every run.
Exploratory questions at or above the pass rate the sponsor set in Phase 0.
Everything that passed at the last gate still passes.
Out-of-scope governed questions refused, with no number. No question bound to the wrong metric.
Any kind of question that can’t pass is named and held back, with an owner and a date.
The context:
Every served metric, rule and business term has an owner, a version and a record of why it was approved.
No open conflict is served. Each waits in the backlog with a date.
Running it:
Production traces reach your log store, per call.
A rerun of the golden set fires on every context change and every schema change, and someone owns it.
The previous version can be restored in one step, and someone is named to decide.
The first run your team does alone is on the calendar, within two weeks.
Decision: go, no-go, or go with conditions. Each condition has an owner and a date. Never lower the bar to fit the score.
Exec sponsor
Decision
Date
Card
Replies for the skeptic
What a data-platform skeptic asks in the room, and a reply that holds up.
Question
Straight answer
“We already have a semantic layer.”
Good. Bring it in as a source. Its measures and filters become candidate metrics alongside past SQL. Serve the SQL each measure produces, because worked SQL beat declarative definitions in our tests.
“A better model will fix this.”
Choose the model after the context. On our questions, context moved both models we ran both ways by 26 points or more, and switching models moved the bare-schema score about 10.
“Is this just your benchmark?”
It is one warehouse, so your numbers will differ. The direction matches published work: worked SQL examples beat schema alone. Your Phase 1 baseline tells you where you start.
“Isn’t this few-shot retrieval?”
Largely, yes. Past SQL is the biggest single step, and that is the field’s standard result. We add two things on top: a record of what didn’t help, such as a join graph, and metrics, which did.
“Can’t we just write better descriptions?”
Write them, but don’t expect much. The same metric served as SQL beat the same metric served as prose. If a fact can be written as something that runs, write it that way.
“Curation won’t scale to 10,000 tables.”
You never curate 10,000 tables; you work one domain at a time. The metrics agent drafts candidates, provenance settles most conflicts, and the domain owner decides the rest.
“What if our analysts’ SQL is wrong?”
Then a generated metric inherits the error. That is why every candidate is checked against the warehouse and approved by an owner before it serves. Where analysts disagree, you have found a decision your business never wrote down.
“How long does this take?”
Phase 0 first, which runs longer where vendor and privacy reviews apply. Then four build phases, often a week each. The gates hold even when the calendar stretches.
“Who keeps it current?”
Named owners, with a rerun of the golden set on every context change and every schema change.
“Who pays for the owners’ time?”
You do, and it is the largest cost. When an owner can spare only minutes a week, the engagement stalls.
“Our warehouse has row-level security.”
Governed answers run under a fixed service identity, so a board number is the same for every asker. Exploratory queries run as the asker.
“We’d be locked in.”
What stays behind is plain files: metric specs, the golden set, the decisions log. Any store that can hold and serve them will do.
“Will you run the agent for us?”
No. The harness is yours: your builder, your model, your surface, your logs. Context is served to it.
Card
Deliver as a partner
A partner firm runs the same method and the same gates. These boundaries hold whatever platform the company runs.
Request access through the company’s platform owner. Work under a read-only identity the company issues. Hold no credentials of your own.
The company builds and runs the harness. Help their builder stand it up. Never host it.
If a platform vendor is involved, the company names your contact there at the kickoff.
The success document carries scope and success criteria. Commercials stay in your contract.
Anything you pass to a vendor goes through the company’s platform owner, anonymised.
Build on the company’s shared context store. Nobody can take over a script or notebook that only you can run.
Within a week of launch, send the platform owner a short, anonymised pattern write-up: what moved the score, and which fixes the next engagement will need, sorted into keep or throw away.
You never decide a definition and never grade an answer. Those belong to the domain owner and the eval owner.
Toolkit
Templates
Copy the template, fill it from your domain, and keep it in version control next to the context it governs.
Read 27 min
Every artifact the method produces is here as a file card. Each card opens on a filled example from the running engagement: the sales domain at a large B2B company whose fiscal year ends 30 June, with every eval answer computed at the fiscal year-end snapshot. The second tab is the blank template. Copy either one.
The order follows the engagement, from Phase 0 to the handover. Chapters show short previews and link here.
Conventions:
All SQL is DuckDB-compatible, so every example runs on a laptop first.
Placeholders are written <like this>.
A cell that reads “your run” is one only your own run can fill.
Every count in an example comes from the engagement’s golden set. None is a benchmark result. The engagement is a composite, built to show the method.
What will be delivered, how both sides judge it together, and who signs. It ends in the Phase 4 go or no-go.
success-document.mdmarkdown
# Engagement success document: Sales (pipeline and win rate)## 1. Purpose
One pipeline number for the top 100 customers, the same every time it is asked, that matches finance.
Diagnostic answers on slippage, stage aging and win rate, in the chat tool sales leadership already uses.
## 2. Shared understanding
No agent exists yet. Sales ops, RevOps and finance each publish pipeline numbers, and two of them
reached the board on adjacent slides last quarter. Each disagreement costs an analyst a day to reconcile.
## 3. Scope
- Domain: sales pipeline. Data: CRM and billing, query history, the board pack and dashboards
- Golden set: at least 20 sealed in Phase 1, 50 by the launch gate; drafted and sealed by the eval owner and two graders
- Agent architecture: the chat tool as surface; a custom harness built by the agent builder; the model chosen in Phase 0
- Out of scope: bookings forecast, commissions, marketing attribution; why-questions until the numbers are released
## 4. Success criteria
| Gate | Deliverable | How we judge it together | Sign-off | Outcome |
|---|---|---|---|---|
| Phase 1 | 20 sealed; baseline | the grading rubric; one run per question | RevOps lead | pass: baseline 7 of 20 |
| Phase 2 | metrics, scored | every metric witnessed; conflicts resolved | RevOps lead | pass: 14 of 20 |
| Phase 3 | fixes from traces; set grown to 50 | nothing that passed has broken | RevOps lead | pass: 18 of 20 |
| Phase 4 | launch gate on the 50 | governed right on every run; exploratory 4 in 5 on every run | CRO | go with conditions |
## 5. Who does what; open questions
The ownership table and the hours table, with a name in every cell on the company's side.
## 6. Go / no-go (Phase 4)
Decision: GO WITH CONDITIONS
Conditions: platform owner builds the "created and still open" state, due two weeks after launch ·
RevOps lead resolves the open conflicts on released questions, due at the first release ·
CRO names domain two, due at handover
Signed: CRO, delivery lead
Engagement success document: Sales (pipeline and win rate)
1. Purpose
One pipeline number for the top 100 customers, the same every time it is asked, that matches finance. Diagnostic answers on slippage, stage aging and win rate, in the chat tool sales leadership already uses.
2. Shared understanding
No agent exists yet. Sales ops, RevOps and finance each publish pipeline numbers, and two of them reached the board on adjacent slides last quarter. Each disagreement costs an analyst a day to reconcile.
3. Scope
Domain: sales pipeline. Data: CRM and billing, query history, the board pack and dashboards
Golden set: at least 20 sealed in Phase 1, 50 by the launch gate; drafted and sealed by the eval owner and two graders
Agent architecture: the chat tool as surface; a custom harness built by the agent builder; the model chosen in Phase 0
Out of scope: bookings forecast, commissions, marketing attribution; why-questions until the numbers are released
4. Success criteria
Gate
Deliverable
How we judge it together
Sign-off
Outcome
Phase 1
20 sealed; baseline
the grading rubric; one run per question
RevOps lead
pass: baseline 7 of 20
Phase 2
metrics, scored
every metric witnessed; conflicts resolved
RevOps lead
pass: 14 of 20
Phase 3
fixes from traces; set grown to 50
nothing that passed has broken
RevOps lead
pass: 18 of 20
Phase 4
launch gate on the 50
governed right on every run; exploratory 4 in 5 on every run
CRO
go with conditions
5. Who does what; open questions
The ownership table and the hours table, with a name in every cell on the company’s side.
6. Go / no-go (Phase 4)
Decision: GO WITH CONDITIONS Conditions: platform owner builds the “created and still open” state, due two weeks after launch · RevOps lead resolves the open conflicts on released questions, due at the first release · CRO names domain two, due at handover Signed: CRO, delivery lead
# Engagement success document: <domain> · signed <date>## 1. Purpose<one paragraph: the business problem and why this domain first>## 2. Shared understanding<what both sides agree is true today: data, current agent if any, known gaps>## 3. Scope
- Domain; data in scope; out of scope: <...>
- Golden set: at least 20 sealed in Phase 1, 50 by the launch gate; drafted and sealed by <eval owner>
- Agent architecture: <surface>, <harness>, <model>; owner of each: <role>## 4. Success criteria
| Gate | Deliverable | How we judge it together | Sign-off | Outcome |
|---|---|---|---|---|
| Phase 1 | golden set sealed; baseline | <rubric; one run per question> | <domain owner> | <your run> |
| Phase 2 | metrics, scored | <metrics witnessed; conflicts resolved> | <domain owner> | <your run> |
| Phase 3 | fixes from traces; set grown to 50 | <nothing that passed has broken> | <domain owner> | <your run> |
| Phase 4 | launch gate | <bar per lane, on the 50> | <exec sponsor> | <your run> |## 5. Who does what; open questions
<the ownership and hours tables, the company holding every accountable cell; open questions with owner and due date>
## 6. Go / no-go (Phase 4)
Decision: GO | NO-GO | GO WITH CONDITIONS
Conditions: <owner, action, due>
Signed: <exec sponsor>, <delivery lead>
Engagement success document: <domain> · signed <date>
1. Purpose
<one paragraph: the business problem and why this domain first>
2. Shared understanding
<what both sides agree is true today: data, current agent if any, known gaps>
3. Scope
Domain; data in scope; out of scope: <…>
Golden set: at least 20 sealed in Phase 1, 50 by the launch gate; drafted and sealed by <eval owner>
Agent architecture: <surface>, <harness>, <model>; owner of each: <role>
4. Success criteria
Gate
Deliverable
How we judge it together
Sign-off
Outcome
Phase 1
golden set sealed; baseline
<rubric; one run per question>
<domain owner>
<your run>
Phase 2
metrics, scored
<metrics witnessed; conflicts resolved>
<domain owner>
<your run>
Phase 3
fixes from traces; set grown to 50
<nothing that passed has broken>
<domain owner>
<your run>
Phase 4
launch gate
<bar per lane, on the 50>
<exec sponsor>
<your run>
5. Who does what; open questions
<the ownership and hours tables, the company holding every accountable cell; open questions with owner and due date>
6. Go / no-go (Phase 4)
Decision: GO | NO-GO | GO WITH CONDITIONS Conditions: <owner, action, due> Signed: <exec sponsor>, <delivery lead>
R2.11 Kickoff agenda
The 90 minutes the delivery lead runs to reach a signed checklist. Teach before you ask: show what goes wrong on the company’s own data, then walk the checklist.
kickoff-agenda.mdmarkdown
# Kickoff: Sales · 90 min · run by the delivery lead
Room: CRO, RevOps lead, FP&A partner, eval owner, agent builder, platform owner, security lead, delivery lead, context engineer
| Time | Item | Output |
|---|---|---|
| 0:00 | Why pilots stall between the demo and the tenth question | a shared diagnosis |
| 0:10 | The decisions hidden in "What's our Q3 pipeline?", on the company's data | two unwritten rules: some early stages never count; internal and test accounts are out |
| 0:25 | Which domain first | sales pipeline, over finance close and marketing attribution |
| 0:35 | The two lanes | board numbers governed; slippage, creation and aging exploratory at 4 in 5; why deferred |
| 0:50 | Owners | RevOps lead: deals, stages, amounts · FP&A partner: who the top 100 customers are |
| 1:00 | Walk the before-you-start checklist | people named; architecture chosen |
| 1:15 | Access and what leaves the building | security walks the data-flow diagram; trace export owned by the agent builder |
| 1:25 | Next steps | brief agreed; the clock starts when every access test passes |
Kickoff: Sales · 90 min · run by the delivery lead
Why pilots stall between the demo and the tenth question
a shared diagnosis
0:10
The decisions hidden in “What’s our Q3 pipeline?”, on the company’s data
two unwritten rules: some early stages never count; internal and test accounts are out
0:25
Which domain first
sales pipeline, over finance close and marketing attribution
0:35
The two lanes
board numbers governed; slippage, creation and aging exploratory at 4 in 5; why deferred
0:50
Owners
RevOps lead: deals, stages, amounts · FP&A partner: who the top 100 customers are
1:00
Walk the before-you-start checklist
people named; architecture chosen
1:15
Access and what leaves the building
security walks the data-flow diagram; trace export owned by the agent builder
1:25
Next steps
brief agreed; the clock starts when every access test passes
# Kickoff: <domain> · 90 min · run by <delivery lead>
Room: <exec sponsor>, <domain owner(s)>, <eval owner>, <agent builder>, <platform owner>, <security lead>, <context engineer>
Pre-read: the one-page method
| Time | Item | Output |
|---|---|---|
| 0:00 | Why pilots stall between the demo and the tenth question | shared diagnosis |
| 0:10 | One question, the decisions it hides, on your own data | two of your own unwritten rules |
| 0:25 | Which domain first | the domain, and why |
| 0:35 | The two lanes | which questions are governed; one pass rate for the rest |
| 0:50 | Who owns which definitions | named domain owner(s) |
| 1:00 | Walk the before-you-start checklist | status per item; owners for gaps |
| 1:15 | Access and what leaves the building | security's next step and date |
| 1:25 | Next steps | checklist met, or the date it will be |
Kickoff: <domain> · 90 min · run by <delivery lead>
Why pilots stall between the demo and the tenth question
shared diagnosis
0:10
One question, the decisions it hides, on your own data
two of your own unwritten rules
0:25
Which domain first
the domain, and why
0:35
The two lanes
which questions are governed; one pass rate for the rest
0:50
Who owns which definitions
named domain owner(s)
1:00
Walk the before-you-start checklist
status per item; owners for gaps
1:15
Access and what leaves the building
security’s next step and date
1:25
Next steps
checklist met, or the date it will be
R2.1 Before-you-start checklist
The access and the people that must be in place before Phase 1. Each access item is done when its test passes. The clock starts when every line is met.
before-you-start.mdmarkdown
# Before you start: Sales (pipeline and win rate) · met at the end of Phase 0 · signed by the CRO and the delivery lead## Access
| Item | Test | Owner | Status |
|---|---|---|---|
| Read-only warehouse access for CRM and billing (required) | a query runs under it | platform owner | done, first week of Phase 0 |
| Query history for sales (required) | the export has rows and a date range | platform owner | done, first week |
| BI reports and semantic models: board pack, RevOps dashboards, semantic model (required if you have them) | the export opens | platform owner | done, second week |
| Trace export from the harness (required): context served, every SQL statement, the answer | one trace read end to end | agent builder | done, last day of Phase 0: the chat tool exported a nightly summary only, so a per-call export was built |
| Where users will ask, named | recorded in the brief | exec sponsor | the chat tool sales leadership already uses |
## People
| Role | Name | Hours |
|---|---|---|
| Exec sponsor | the CRO | kickoff, a 30-minute readout in each phase, gates |
| Domain owner | the RevOps lead | 2-3 h/week |
| Co-owner | the FP&A partner | about 1 h/week in Phases 2-3 |
| Eval owner and graders | eval owner; a RevOps analyst and an FP&A analyst | 6-8 h in Phase 1, then about 2 h/week |
| Agent builder | the agent builder | about 20 h/week to the baseline, then 4-6 |
| Platform owner, security lead | named | Phase 0, then on call |
| Context engineer, delivery lead | from the partner; in-house, an analytics engineer and your program lead | dedicated; every session |
Before you start: Sales (pipeline and win rate) · met at the end of Phase 0 · signed by the CRO and the delivery lead
Access
Item
Test
Owner
Status
Read-only warehouse access for CRM and billing (required)
a query runs under it
platform owner
done, first week of Phase 0
Query history for sales (required)
the export has rows and a date range
platform owner
done, first week
BI reports and semantic models: board pack, RevOps dashboards, semantic model (required if you have them)
the export opens
platform owner
done, second week
Trace export from the harness (required): context served, every SQL statement, the answer
one trace read end to end
agent builder
done, last day of Phase 0: the chat tool exported a nightly summary only, so a per-call export was built
Where users will ask, named
recorded in the brief
exec sponsor
the chat tool sales leadership already uses
People
Role
Name
Hours
Exec sponsor
the CRO
kickoff, a 30-minute readout in each phase, gates
Domain owner
the RevOps lead
2-3 h/week
Co-owner
the FP&A partner
about 1 h/week in Phases 2-3
Eval owner and graders
eval owner; a RevOps analyst and an FP&A analyst
6-8 h in Phase 1, then about 2 h/week
Agent builder
the agent builder
about 20 h/week to the baseline, then 4-6
Platform owner, security lead
named
Phase 0, then on call
Context engineer, delivery lead
from the partner; in-house, an analytics engineer and your program lead
dedicated; every session
# Before you start: <domain> · met <date> · signed by <exec sponsor>, <delivery lead>## Access
| Item | Test | Owner | Status |
|---|---|---|---|
| Read-only warehouse access for the domain's tables (required) | a query runs under it | <platform owner> | <date> |
| Query history for the domain (required) | the export has rows and a date range | <platform owner> | <date> |
| BI reports and semantic models (required if you have them) | the export opens | <platform owner> | <date> |
| Trace export from your harness (required): context served, every SQL statement, the answer | one trace read end to end | <agent builder> | <date> |
| Where users will ask, named | recorded in the brief | <exec sponsor> | <surface> |## People
| Role | Name | Hours |
|---|---|---|
| Exec sponsor | <name> | <...> |
| Domain owner, co-owner | <names> | <h/week> |
| Eval owner and graders | <names> | <h/week> |
| Agent builder | <name> | <h/week> |
| Platform owner, security lead | <names> | <...> |
| Context engineer, delivery lead | <names> | <...> |
Before you start: <domain> · met <date> · signed by <exec sponsor>, <delivery lead>
Access
Item
Test
Owner
Status
Read-only warehouse access for the domain’s tables (required)
a query runs under it
<platform owner>
<date>
Query history for the domain (required)
the export has rows and a date range
<platform owner>
<date>
BI reports and semantic models (required if you have them)
the export opens
<platform owner>
<date>
Trace export from your harness (required): context served, every SQL statement, the answer
one trace read end to end
<agent builder>
<date>
Where users will ask, named
recorded in the brief
<exec sponsor>
<surface>
People
Role
Name
Hours
Exec sponsor
<name>
<…>
Domain owner, co-owner
<names>
<h/week>
Eval owner and graders
<names>
<h/week>
Agent builder
<name>
<h/week>
Platform owner, security lead
<names>
<…>
Context engineer, delivery lead
<names>
<…>
R2.2 Domain brief
One page that fixes the domain, its users, its questions and which lane each kind of question runs in.
domain-brief.yamlyaml
# Domain brief: Sales · v1 · agreed at the kickoffdomain: sales pipeline
fiscal_year: ends 30 June; every eval answer at the fiscal year-end snapshot
users: CRO staff, sales leaders, RevOps analysts, FP&A partners, asking in the chat tool they already use
problem: pipeline numbers disagree with finance; each disagreement costs an analyst a day to reconcile
owners: RevOps lead (deals, stages, amounts), 2-3 h/week · FP&A partner (who the top 100 customers are), about 1 h/week in Phases 2 and 3
eval_owner: one named person, with a RevOps analyst and an FP&A analyst as graders; 6-8 h in Phase 1, then about 2 h/week
governed: # exact, on every run; a metric or no answer
- open pipeline, any cut
- win rate, any cut
- closed-won ARR, any cut
exploratory: # SQL and sources shown; the bar is 4 in 5, right on every run
- slippage
- pipeline creation
- stage aging
- rep and territory cuts
deferred: why-questions, until the numbers are released
out_of_scope: bookings forecast, commissions, marketing attribution
data: CRM opportunities, snapshots, accounts, stage and close-date history, reps, territories; billing terms
sources: query history, human authors; the board pack; the RevOps dashboards and semantic model
import: the RevOps semantic model; no earlier agent, so no instructions
architecture: surface the chat tool · harness custom, built by the agent builder · model the production model, named with its version
# Domain brief: <domain> · v<n> · agreed <date>domain: <domain>fiscal_year: <when it ends>; every eval answer at <snapshot>users: <roles who will ask, and where they ask today>problem: <what goes wrong today, for whom, at what cost>owners: <domain owner (what they decide)>, <h/week> · <co-owner, if a definition crosses teams>, <h/week>eval_owner: <name>, with <graders>; <h in Phase 1>, then <h/week>governed: # exact, on every run; a metric or no answer
- <kind of question>exploratory: # SQL and sources shown; the bar is <one pass rate, written now>
- <kind of question>deferred: <kinds of question, and why>out_of_scope: <questions, data, surfaces>data: <schemas and tables>sources: <query-history window, human authors>; <BI reports and semantic models>
import: <semantic layer, saved queries or instructions you already have, or none>architecture: surface <...> · harness <platform-native or custom> · model <the production model, with its version>
Phase 1: the golden set
R2.15 Question-harvest sheet
The candidate list the golden set is drawn from, each question traced to where the business already asks it. Collect two or three candidates for every question you will seal.
question-harvest.mdmarkdown
# Question harvest: Sales, Phase 1 · run by the eval owner · graders: a RevOps analyst, an FP&A analyst · 62 candidates
Sources: 23 from the board pack, 19 from RevOps dashboards, 14 from tickets, 6 from the CRO. Five rows shown.
| # | Question, as a user asks it | Source | Asked by, how often | Lane | Verified answer at | Keep? |
|---|---|---|---|---|---|---|
| 3 | How much open pipeline do we have with our top 100 customers? | board pack, top-accounts page; RevOps "Top accounts" tile | CRO, weekly | governed | board pack. DISPUTED: the tile ranks a different 100 | yes; the FP&A partner picks the source before sealing |
| 7 | How many of the open deals with our top 100 customers slipped from last quarter? | a RevOps analyst's saved query, "deals pushed past quarter end, by rep" | sales leaders, each quarter end | exploratory | the analyst's query on the snapshot | yes |
| 8 | What is our win rate with the top 100 customers, against everyone else? | RevOps win-rate dashboard | CRO staff, monthly | governed | dashboard; denominator to confirm | yes |
| 19 | Which reps have the most pipeline stuck at one stage for over 60 days? | ticket from a regional sales VP | sales managers, ad hoc | exploratory | graders compute it from stage history | yes |
| 41 | Why did pipeline with these customers drop in EMEA this quarter? | CRO, year-end review | CRO, once | why | none | no: deferred until the numbers are released |
Question harvest: Sales, Phase 1 · run by the eval owner · graders: a RevOps analyst, an FP&A analyst · 62 candidates
Sources: 23 from the board pack, 19 from RevOps dashboards, 14 from tickets, 6 from the CRO. Five rows shown.
#
Question, as a user asks it
Source
Asked by, how often
Lane
Verified answer at
Keep?
3
How much open pipeline do we have with our top 100 customers?
board pack. DISPUTED: the tile ranks a different 100
yes; the FP&A partner picks the source before sealing
7
How many of the open deals with our top 100 customers slipped from last quarter?
a RevOps analyst’s saved query, “deals pushed past quarter end, by rep”
sales leaders, each quarter end
exploratory
the analyst’s query on the snapshot
yes
8
What is our win rate with the top 100 customers, against everyone else?
RevOps win-rate dashboard
CRO staff, monthly
governed
dashboard; denominator to confirm
yes
19
Which reps have the most pipeline stuck at one stage for over 60 days?
ticket from a regional sales VP
sales managers, ad hoc
exploratory
graders compute it from stage history
yes
41
Why did pipeline with these customers drop in EMEA this quarter?
CRO, year-end review
CRO, once
why
none
no: deferred until the numbers are released
# Question harvest: <domain>, Phase 1 · run by <eval owner> · graders: <names> · <n> candidates
Sources: <n> from <source>, <n> from <source>, ...
| # | Question, as a user asks it | Source | Asked by, how often | Lane | Verified answer at | Keep? |
|---|---|---|---|---|---|---|
| 1 | <question> | <tile, report, ticket, saved query> | <role>, <how often> | <governed / exploratory / why> | <where, or none> | <yes / no: why> |
Candidates drafted by a tool are marked "drafted"; graders rewrite them in the user's words.
A disputed source goes to the definition's owner before sealing, and to the conflict list with no value attached.
Question harvest: <domain>, Phase 1 · run by <eval owner> · graders: <names> · <n> candidates
Sources: <n> from <source>, <n> from <source>, …
#
Question, as a user asks it
Source
Asked by, how often
Lane
Verified answer at
Keep?
1
<question>
<tile, report, ticket, saved query>
<role>, <how often>
<governed / exploratory / why>
<where, or none>
<yes / no: why>
Candidates drafted by a tool are marked “drafted”; graders rewrite them in the user’s words. A disputed source goes to the definition’s owner before sealing, and to the conflict list with no value attached.
R2.16 Coverage estimate
Optional. A first signal of your ceiling: how many harvested questions a trusted past query or an existing metric already answers. The eval owner runs it, so no answer passes to the context engineer. The engagement did not record its counts, so the example shows the shape with “your run” in the cells.
coverage-estimate.mdmarkdown
# Coverage estimate: Sales, Phase 1 · run by the eval owner
Inputs: 62 harvested questions; query history (a query counts with 2 or more distinct analysts and 5 or more runs)
| Lane | Candidates | With a trusted past query | With an existing metric | Neither | Covered |
|---|---|---|---|---|---|
| governed | your run | your run | your run | your run | your run |
| exploratory | your run | your run | your run | your run | your run |
Reading: <go | hold | re-scope>. Uncovered topics go to the context engineer as topic names only.
Coverage estimate: Sales, Phase 1 · run by the eval owner
Inputs: 62 harvested questions; query history (a query counts with 2 or more distinct analysts and 5 or more runs)
Lane
Candidates
With a trusted past query
With an existing metric
Neither
Covered
governed
your run
your run
your run
your run
your run
exploratory
your run
your run
your run
your run
your run
Reading: <go | hold | re-scope>. Uncovered topics go to the context engineer as topic names only.
# Coverage estimate: <domain>, Phase 1 · <date> · run by <eval owner>
Inputs: harvested questions; <query-history window; a query counts with at least <n> analysts and <n> runs>
| Lane | Candidates | With a trusted past query | With an existing metric | Neither | Covered |
|---|---|---|---|---|---|| <lane> | <n> | <n> | <n> | <n> | <%> |
Reading: <go | hold: mostly uncovered | re-scope>
Any query later used as expected SQL is purged from the context by hash.
Coverage estimate: <domain>, Phase 1 · <date> · run by <eval owner>
Inputs: harvested questions; <query-history window; a query counts with at least <n> analysts and <n> runs>
Lane
Candidates
With a trusted past query
With an existing metric
Neither
Covered
<lane>
<n>
<n>
<n>
<n>
<%>
Reading: <go | hold: mostly uncovered | re-scope> Any query later used as expected SQL is purged from the context by hash.
R2.4 Grading rubric
How every answer is judged, agreed before the first run so no score is argued after it.
grading-rubric.mdmarkdown
# Grading rubric: Sales, v1 · agreed in Phase 1 by the eval owner and the RevOps lead## 1. Returned data first
- Counts exact. Amounts within 0.5%. A fraction equals its percentage.
- The pipeline question expects 91 accounts, 340 deals, $412M. A split by region that sums to the total
(NA $198M, EMEA $161M, APAC $53M) is a valid alternative.
## 2. Then the SQL
- A value inside tolerance reached by the wrong logic is wrong.
- Governed: the answer comes from the metric. No metric, no answer.
- Exploratory: SQL and sources shown; directionally right passes if the RevOps lead agrees.
## 3. Verdicts
- The pipeline question at $1.31B (top 100 by deal count, every stage, contract value, each term): wrong.
- "Two definitions of top 100 are in use; which one?" before the conflict is resolved: a correct refusal.
- A run that failed is an error, reported apart, never counted as wrong.
## 4. Runs and judges
- Baseline and Phase 2 score: one run per question. From the first round in Phase 3: three runs. Launch gate: five.
- Score = questions right on every run.
- An LLM judge checks answer shape only (period, filter and unit stated), after calibration on 20 items.
## 5. Not measured
Why-questions, follow-up turns, entity lookups.
Grading rubric: Sales, v1 · agreed in Phase 1 by the eval owner and the RevOps lead
1. Returned data first
Counts exact. Amounts within 0.5%. A fraction equals its percentage.
The pipeline question expects 91 accounts, 340 deals, $412M. A split by region that sums to the total (NA $198M, EMEA $161M, APAC $53M) is a valid alternative.
2. Then the SQL
A value inside tolerance reached by the wrong logic is wrong.
Governed: the answer comes from the metric. No metric, no answer.
Exploratory: SQL and sources shown; directionally right passes if the RevOps lead agrees.
3. Verdicts
The pipeline question at $1.31B (top 100 by deal count, every stage, contract value, each term): wrong.
“Two definitions of top 100 are in use; which one?” before the conflict is resolved: a correct refusal.
A run that failed is an error, reported apart, never counted as wrong.
4. Runs and judges
Baseline and Phase 2 score: one run per question. From the first round in Phase 3: three runs. Launch gate: five.
Score = questions right on every run.
An LLM judge checks answer shape only (period, filter and unit stated), after calibration on 20 items.
5. Not measured
Why-questions, follow-up turns, entity lookups.
# Grading rubric: <domain>, v<n> · agreed <date> by <eval owner>, <domain owner>## 1. Returned data first
- Compare returned values with `expected`; accept any `valid_alternatives` entry.
- Counts: <exact>. Amounts: <tolerance>. A fraction equals its percentage.
## 2. Then the SQL
- Check the SQL against the decisions the question hides.
- A value inside tolerance reached by the wrong logic is wrong.
- Governed: the answer must come from the metric. No metric, no answer.
- Exploratory: SQL and sources shown; directionally right passes if the domain owner agrees.
## 3. Verdicts
- correct: data within tolerance and the logic holds
- wrong: data outside tolerance, or right data by wrong logic
- refusal: declined, or flagged a conflict. Correct when: <policy>
- error: the run failed; reported separately, never counted as wrong
## 4. Runs and judges
- One run per question until the score passes about 60%; then <3-5> runs; score = right on every run.
- Code checks values first; an LLM judge checks answer shape only, once calibrated on <n> items.
## 5. Not measured<e.g. why-questions, follow-up turns, entity lookups>
One question with its expected answer, the SQL that produced it, and how it is graded. The eval owner and graders draft and seal it. The agent and the context engineer never see it. The first six fields are required; the rest are optional.
sales-01.yamlyaml
# requiredid: sales-01
question: How much open pipeline do we have with our top 100 customers?
lane: governed
source: finance board pack, top-accounts pipeline page (year-end close)
expected: {accounts: 91, deals: 340, open_pipeline: 412000000}
expected_sql: | # a full copy, never a link, so the sealed answer never moves when a metric does
WITH latest_term AS (
SELECT account_id, arr, ROW_NUMBER() OVER (PARTITION BY subscription_id ORDER BY start_date DESC) AS rn
FROM billing.subscription_term WHERE status = 'active' AND start_date <= DATE '2026-06-30'),
top_accounts AS (
SELECT account_id FROM latest_term WHERE rn = 1 GROUP BY account_id ORDER BY SUM(arr) DESC LIMIT 100)
SELECT COUNT(DISTINCT o.account_id) AS accounts, COUNT(*) AS deals, SUM(o.arr) AS open_pipeline
FROM crm.opportunity_snapshot o
JOIN top_accounts t ON t.account_id = o.account_id JOIN crm.account a ON a.id = o.account_id
WHERE o.as_of_date = DATE '2026-06-30' AND o.stage_order >= 2 AND o.type IN ('New Business', 'Upsell')
AND NOT o.is_closed AND NOT a.is_internal AND NOT a.is_test;
# optionalas_of: 2026-06-30 # the fiscal year-end snapshotvalid_alternatives: ["by region, summing to the total: NA 198M, EMEA 161M, APAC 53M"]
tolerance: {counts: exact, amounts: within 0.5%}
decisions: [top 100 by current ARR, some early stages never count, amount is ARR, each deal once]
decoy: "top 100 by deal count, every stage, contract value, each term -> $1.31B"
sealed_by: eval owner, with the RevOps and FP&A graders, Phase 1
history: ["Phase 1: graders disputed the source (dashboard tile vs board pack); the FP&A partner chose the board pack"]
# requiredid: <domain>-<nn>question: <exactly as a user would ask it>lane: <governed | exploratory>source: <dashboard, report or analyst work the answer was verified against>expected: {<column>: <value>, ...}
expected_sql: |
<DuckDB SQL that returns expected; a full copy, never a link>
# optionalas_of: <YYYY-MM-DD>
valid_alternatives: [] # each with a reasontolerance: {counts: exact, amounts: <your setting>}
decisions: [<the choices the question hides>]
decoy: <the wrong answer you get when the hidden choices are guessed the obvious way>sealed_by: <eval owner, with the graders, when>history: [] # every key correction and source dispute: when, who, why
R2.22 Context call and trace record
What the harness sends on its one context call, what comes back, and the per-call trace record it exports. Fix this shape before the baseline and keep it, so the baseline and the later scores compare. At baseline the response carries the schema only. The example is the pipeline question after the top-100 conflict was resolved.
context-call-and-trace.jsonjson
{
"request": {
"question": "How much open pipeline do we have with our top 100 customers?",
"domain": "sales",
"identity": {"user": "a member of the CRO staff", "passthrough": true}
},
"response": {
"call_id": "cc-phase3-sales-01-r1",
"context_version": "v1.3",
"lane": "governed",
"metrics": [
{
"name": "open_pipeline_top_accounts",
"version": 3,
"owners": ["RevOps lead", "FP&A partner"],
"provenance": "approved; witnessed in Phase 3; top-100 conflict resolved by both owners",
"parameters": {"as_of": {"type": "date", "required": true}, "n": {"type": "integer", "default": 100}},
"dimensions": ["region", "segment", "rep", "stage"],
"sql": "-- the metric's sql field, complete, as in the metric spec"
}
],
"trusted_queries": [],
"rules": [
{"name": "quarter-means-fiscal", "version": 1, "instruction": "Quarters are fiscal; the fiscal year ends 30 June."}
],
"business_terms": [{"term": "Top accounts", "version": 2, "points_to": "open_pipeline_top_accounts v3"}]
},
"trace_record": {
"trace_id": "sales-01 · Phase 3, round 4 · run 1 of 3",
"question_id": "sales-01",
"model": "the chosen model and version",
"served": [
{"id": "open_pipeline_top_accounts", "version": 3},
{"id": "quarter-means-fiscal", "version": 1},
{"id": "Top accounts", "version": 2}
],
"tool_calls": [
{"turn": 2, "tool": "context_call", "args": {"domain": "sales"}, "result": "cc-phase3-sales-01-r1", "ok": true},
{"turn": 3, "tool": "execute_metric", "args": {"metric": "open_pipeline_top_accounts", "version": 3, "as_of": "2026-06-30", "n": 100},
"identity": "the fixed service identity", "sql": "-- the bound statement, exactly as run", "rows": 1, "ok": true}
],
"outcome": {"kind": "answer", "text": "Open pipeline with our top 100 customers: $412M, 340 deals on 91 accounts."},
"steps": 4,
"sql_statements": 1,
"seconds": "your run",
"tokens": "your run"
}
}
{
"request": {
"question": "<the user's words, unedited>",
"domain": "<domain>",
"identity": {"user": "<the asking user's id>", "passthrough": true}
},
"response": {
"call_id": "<unique per call>",
"context_version": "<v x.y>",
"lane": "<governed | exploratory>",
"metrics": [
{"name": "<metric>", "version": "<int>", "owners": ["<role>"], "provenance": "<status, owners, how it was settled>",
"parameters": {"<name>": {"type": "<type>", "required": "<true | false>", "default": "<value, or omit>"}},
"dimensions": ["<name>"], "sql": "<the complete sql field>"}
],
"trusted_queries": [
{"id": "<query id>", "version": "<int>", "provenance": "<run by N analysts, M runs, last run <when>; witness OK>", "sql": "<complete statement, literals kept>"}
],
"rules": [{"name": "<rule>", "version": "<int>", "instruction": "<one rule, as an instruction>"}],
"business_terms": [{"term": "<term>", "version": "<int>", "points_to": "<metric or query, with version>"}]
},
"trace_record": {
"trace_id": "<question id · week, round · run n of k>",
"question_id": "<id, or unsealed in production>",
"model": "<model and version>",
"served": [{"id": "<item>", "version": "<version>"}],
"tool_calls": [
{"turn": "<n>", "tool": "<context_call | run_sql | execute_metric>", "args": {}, "identity": "<user | service identity>",
"sql": "<every statement, failed ones included>", "rows": "<n>", "ok": "<true | false>", "error": "<message, if any>"}
],
"outcome": {"kind": "<answer | refusal: no metric | conflict flagged>", "text": "<what the user saw>"},
"steps": "<n>",
"sql_statements": "<n>",
"seconds": "<n>",
"tokens": "<in, out>"
}
}
Phase 2: metrics
R2.14 Trusted past query
A complete analyst query, kept as a worked example for the exploratory lane. The record carries the provenance that earns it a place and the business terms that let a question find it.
q-pushed-by-rep.yamlyaml
id: q-pushed-by-rep
title: Deals pushed past quarter end, by rep
owner: a RevOps analyst
domain: sales
version: 1
provenance:
distinct_analysts: 9
runs: 120
last_run: the final week of the fiscal year
witness: OK # re-run read-only in Phase 2business_terms: # linked in Phase 3; before that "slipped" found nothing
- {term: Slipped deal, alternate_labels: [pushed, rolled, slid]}
rules: [quarter-means-fiscal]
dialect: duckdb
sql: |
WITH slipped AS ( -- each deal once, however often it was pushed
SELECT DISTINCT h.opportunity_id
FROM crm.close_date_history h
WHERE h.old_close_date >= DATE '2026-01-01' AND h.old_close_date < DATE '2026-04-01'
AND h.new_close_date >= DATE '2026-04-01'
AND h.changed_at >= DATE '2026-01-01' AND h.changed_at < DATE '2026-04-01')
SELECT r.name AS rep, COUNT(*) AS slipped, SUM(o.arr) AS arr
FROM slipped s
JOIN crm.opportunity o ON o.id = s.opportunity_id
JOIN crm.rep r ON r.id = o.owner_id
GROUP BY r.name
ORDER BY slipped DESC;
notes: Fiscal Q3 runs January to March; the fiscal year ends 30 June.
id: <query id>title: <what the query answers, in the analyst's words>
owner: <analyst or team who wrote it>domain: <domain>version: <int># bumps when the author re-issues itprovenance:
distinct_analysts: <N>
runs: <M>
last_run: <when> witness: <OK | FAIL> # re-run read-only against the warehousebusiness_terms: # the terms linked to this query, with their alternate labels
- {term: <term>, alternate_labels: [<label>, ...]}
rules: [<rules that apply when it is used>]
dialect: duckdb
sql: |
<complete statement, literals kept>notes: <what the analyst's comments say, if any>
R2.5 Metric spec
The metric’s executable definition: one metric per file, governed like code. It stays a candidate until an owner approves it.
Rules the file obeys:
sql is what the harness runs. It fills only declared parameters and adds only declared dimensions. It never retypes the statement.
formula, filters and joins restate sql for reviewers. The witness run checks that they agree.
Verified examples are executed from sql, never hand-written.
provenance records where the metric came from and how its conflicts were settled. The approval label served with the metric is rendered from status, owners and provenance.
open_pipeline_top_accounts.yamlyaml
name: open_pipeline_top_accounts
version: 3 # v2 ranked customers by deal count; retired when the top-100 conflict was resolvedowners:
- {role: RevOps lead, owns: deals and amount}
- {role: FP&A partner, owns: who the top 100 customers are}
status: approved
description: >
Open new-business and upsell pipeline in ARR, on the 100 customers with the highest current ARR.
Some early stages never count. Finance ranks the customers; Sales owns the deals.
population: Open new-business and upsell deals past the first stage, on the top N customers by current ARR
grain: One row per customer; each open deal counted once (key opportunity id)
time_rule: The quarter-end snapshot at the as-of date. Quarters are fiscal; the fiscal year ends 30 June.
formula: SUM(o.arr)
exclusions: [first-stage deals, renewals, internal and test accounts, closed deals]
filters:
- o.stage_order >= 2
- o.type IN ('New Business', 'Upsell')
- NOT o.is_closed
- NOT a.is_internal
- NOT a.is_test
dimensions:
- {name: region, sql: a.region}
- {name: segment, sql: a.segment}
- {name: rep, sql: o.owner_id}
- {name: stage, sql: o.stage}
joins:
- {to: top_accounts (ranked from billing.subscription_term), condition: t.account_id = o.account_id, cardinality: many_to_one}
- {to: crm.account, condition: a.id = o.account_id, cardinality: many_to_one}
sql: |
-- dialect: duckdb; parameters: $as_of (date, required), $n (integer, default 100)
WITH latest_term AS (
SELECT account_id, arr, ROW_NUMBER() OVER (PARTITION BY subscription_id ORDER BY start_date DESC) AS rn
FROM billing.subscription_term WHERE status = 'active' AND start_date <= $as_of),
top_accounts AS (
SELECT account_id FROM latest_term WHERE rn = 1 GROUP BY account_id ORDER BY SUM(arr) DESC LIMIT $n)
SELECT COUNT(DISTINCT o.account_id) AS accounts, COUNT(*) AS deals, SUM(o.arr) AS open_pipeline
FROM crm.opportunity_snapshot o
JOIN top_accounts t ON t.account_id = o.account_id JOIN crm.account a ON a.id = o.account_id
WHERE o.as_of_date = $as_of AND o.stage_order >= 2 AND o.type IN ('New Business', 'Upsell')
AND NOT o.is_closed AND NOT a.is_internal AND NOT a.is_test;
verified_examples:
- question: How much open pipeline do we have with our top 100 customers?
parameters: {n: 100, as_of: 2026-06-30}
result: {accounts: 91, deals: 340, open_pipeline: 412000000}
provenance:
source: the finance board pack; the ranking lived in a spreadsheet, never in query history
observed_queries: 0 # 31 queries pasted the list's output as fixed IDs; none computed the ranking distinct_analysts: 0
witnessed: Phase 3 · 1 row · grain check 340 = 340 · by region NA 198M, EMEA 161M, APAC 53M
conflict: >
Top 100 by deal count (the sales ops dashboard, the only ranking in query history) against top 100 by
current ARR (the board pack, ranked in a spreadsheet). Provenance could not weigh a variant it never saw, so both owners decided: ARR.
approved_by: [RevOps lead, FP&A partner]
replaces: "v2: top 100 by deal count"
name: <snake_case># unique; equals the filename stemversion: <int># bumps when sql, formula, filters or joins changeowners:
- {role: <team>, owns: <what part of the definition>}
status: candidate # candidate | approved | deprecateddescription: <what a business owner approves, in plain words>population: <which rows the number counts>grain: <one row per ...; the key each row is counted once by>time_rule: <which date, which calendar, snapshot or live>formula: <aggregate expression>exclusions: [<what is deliberately left out, in plain words>]
filters: [<SQL predicates, always ANDed in>]
dimensions:
- {name: <name>, sql: <expression>}
joins:
- {to: <schema.table>, condition: <condition>, cardinality: <many_to_one>}
sql: |
-- dialect: duckdb; parameters: $<name> (<type>, <required | default>)
<the complete executable statement>verified_examples:
- question: <text> parameters: {<name>: <value>}
result: {<column>: <value>}
provenance:
source: <query history | BI | imported | hand-written> observed_queries: <n> distinct_analysts: <n> witnessed: <when · rows · grain check> conflict: <what disagreed, and whether provenance or the owner settled it> approved_by: []
replaces: null # previous version and why it was retired
R2.6 Conflict record
The record of a conflict between two definitions, and what changed because of it. Most conflicts close on provenance and need only the first two sections. Write the full record when the owner decides, or when the decision changes something already approved.
top-100-conflict.mdmarkdown
# Conflict: who the top 100 customers are
Status: resolved · Raised by: trace review, Phase 3 · Settled by: the owners, a 20-minute session the next day
Room: RevOps lead (decides: deals) · FP&A partner (decides: top 100) · context engineer (presents, no vote) · eval owner (present, silent on the key)
Prepared the day before: both variants as SQL, witnessed; the pasted list of 100 account IDs traced to the FP&A partner's spreadsheet
## The conflict
When someone asks about "our top 100 customers", which 100 are they?
| Variant | Definition | Where it is used | Provenance |
|---|---|---|---|
| A | most opportunities, any stage | sales ops "Top accounts" dashboard; approved v2 | the only ranking in query history, run often by sales ops |
| B | highest current ARR on the latest active term | finance board pack | none in query history: the ranking lived in a spreadsheet; 31 RevOps queries pasted its output as a fixed list of IDs |
Provenance: cannot settle it. B, the number leadership runs on, never appeared in query history, so history favours A by default. Sent to the owners.
## Decision
B, written as SQL on billing terms, with "some early stages never count" written into the metric's population.
Rationale, FP&A partner: "The board pack is the number leadership runs on. Deal count rewards accounts with many small deals."
RevOps lead: "Agreed. Sales ops keeps its tile, renamed 'most active accounts'."
## Effect
- Context changed: open_pipeline_top_accounts v3, owned by the RevOps lead and the FP&A partner; v2 retired, kept on record
- Business term "Top accounts" now points to v3
- Golden-set items affected: the pipeline question and the win-rate question; already sealed to B; resealed: no
- Next: v3 re-witnessed, then the whole set rerun; predicted fixes: the pipeline, slipped-deals and win-rate questions
- Reopen if: finance changes how the board pack ranks customers
Conflict: who the top 100 customers are
Status: resolved · Raised by: trace review, Phase 3 · Settled by: the owners, a 20-minute session the next day Room: RevOps lead (decides: deals) · FP&A partner (decides: top 100) · context engineer (presents, no vote) · eval owner (present, silent on the key) Prepared the day before: both variants as SQL, witnessed; the pasted list of 100 account IDs traced to the FP&A partner’s spreadsheet
The conflict
When someone asks about “our top 100 customers”, which 100 are they?
Variant
Definition
Where it is used
Provenance
A
most opportunities, any stage
sales ops “Top accounts” dashboard; approved v2
the only ranking in query history, run often by sales ops
B
highest current ARR on the latest active term
finance board pack
none in query history: the ranking lived in a spreadsheet; 31 RevOps queries pasted its output as a fixed list of IDs
Provenance: cannot settle it. B, the number leadership runs on, never appeared in query history, so history favours A by default. Sent to the owners.
Decision
B, written as SQL on billing terms, with “some early stages never count” written into the metric’s population. Rationale, FP&A partner: “The board pack is the number leadership runs on. Deal count rewards accounts with many small deals.” RevOps lead: “Agreed. Sales ops keeps its tile, renamed ‘most active accounts’.”
Effect
Context changed: open_pipeline_top_accounts v3, owned by the RevOps lead and the FP&A partner; v2 retired, kept on record
Business term “Top accounts” now points to v3
Golden-set items affected: the pipeline question and the win-rate question; already sealed to B; resealed: no
Next: v3 re-witnessed, then the whole set rerun; predicted fixes: the pipeline, slipped-deals and win-rate questions
Reopen if: finance changes how the board pack ranks customers
# Conflict: <short name>
Status: open | resolved on provenance | resolved by the owner | escalated · Raised by: <generation | repeated runs | trace review | user correction>, <when>
Room (owner decisions only): <who decides, on what> · <who presents, no vote> · <eval owner, silent on the key>
Prepared: <each variant as SQL, witnessed; any pasted list it touches, traced>## The conflict<the question the business had not decided, in one sentence>
| Variant | Definition | Where it is used | Provenance |
|---|---|---|---|
| A | <definition> | <dashboards, teams> | <analysts, runs, last run, matches the warehouse?> |
| B | <definition> | <dashboards, teams> | <analysts, runs, last run, matches the warehouse?> |
Provenance: <settles it: which variant and why | split: sent to the owner>## Decision<the variant chosen, or the new definition>
Rationale: <why, in the owner's words, or the provenance that settled it>
## Effect
- Context changed: <metric and new version | rule | business term>; retired: <version>
- Golden-set items affected: <ids>; resealed by the eval owner: <yes / no>
- Next: <re-witness, rerun, predicted fixes>
- Reopen if: <what would reopen it>
Conflict: <short name>
Status: open | resolved on provenance | resolved by the owner | escalated · Raised by: <generation | repeated runs | trace review | user correction>, <when> Room (owner decisions only): <who decides, on what> · <who presents, no vote> · <eval owner, silent on the key> Prepared: <each variant as SQL, witnessed; any pasted list it touches, traced>
The conflict
<the question the business had not decided, in one sentence>
Variant
Definition
Where it is used
Provenance
A
<definition>
<dashboards, teams>
<analysts, runs, last run, matches the warehouse?>
B
<definition>
<dashboards, teams>
<analysts, runs, last run, matches the warehouse?>
Provenance: <settles it: which variant and why | split: sent to the owner>
Decision
<the variant chosen, or the new definition> Rationale: <why, in the owner’s words, or the provenance that settled it>
Effect
Context changed: <metric and new version | rule | business term>; retired: <version>
Golden-set items affected: <ids>; resealed by the eval owner: <yes / no>
Next: <re-witness, rerun, predicted fixes>
Reopen if: <what would reopen it>
Phase 3: the hill climb
R2.7 Trace review sheet
One row per miss, read from the raw trace. The row decides the next context change. Walk each miss down Why did this miss? first; the kind column takes its branch.
trace-review.mdmarkdown
# Trace review: Sales, Phase 3, rounds 2 and 3 · reviewers: context engineer, agent builder; RevOps lead approves
| Question | Run | Verdict | Expected / returned | Served | Used? | Step where it guessed | Kind of miss | Proposed change | Approved |
|---|---|---|---|---|---|---|---|---|---|
| partner-org count | round 2 · 1 of 3 | wrong; passed in round 1 | sealed count, a partner org included / one org short | new rule "internal and test accounts are out", as an instruction | yes, too widely | turn 3: excluded every account that was not a direct customer | a break: a rule served too widely | scope the rule to the org-type field | RevOps lead, round 3 |
| win rate, fiscal Q3 | round 3 · 2 of 3 | wrong on 1 of 3 | fiscal Q3 / calendar Q3 | win_rate v4; rule quarter-means-fiscal | partly | turn 3: let the metric's period default read "Q3" as July to September | served, parameter bound wrong | make the time parameter required, no default | RevOps lead, round 4 |
| pipeline, top 100 | round 3 · 1 of 3 | wrong, same every run | $412M / a total above the key | open_pipeline_top_accounts v2 | yes | turn 3: the served metric ranked customers by deal count, with no early-stage rule | never written: finance's ranking was nowhere in the context | raise the top-100 conflict; write the stage rule into the metric | both owners, the next day |
| slipped deals | round 3 · 2 of 3 | wrong | 96 slipped ($118M) / 218 slipped | win_rate v4 (weak match); the trusted query not retrieved | partly | turn 3: "nothing served defines slipped"; counted any close-date change | written, not served | add alternate labels "pushed", "rolled" to "Slipped deal"; link the term to the query | RevOps lead, round 4 |
| pipeline created, by segment | round 3 · 3 of 3 | wrong, same every run | sealed value / wrong | a newly promoted trusted query | yes | none: the warehouse holds no "created and still open" state | the data | escalate to the platform owner | platform owner |
Trace review: Sales, Phase 3, rounds 2 and 3 · reviewers: context engineer, agent builder; RevOps lead approves
Question
Run
Verdict
Expected / returned
Served
Used?
Step where it guessed
Kind of miss
Proposed change
Approved
partner-org count
round 2 · 1 of 3
wrong; passed in round 1
sealed count, a partner org included / one org short
new rule “internal and test accounts are out”, as an instruction
yes, too widely
turn 3: excluded every account that was not a direct customer
a break: a rule served too widely
scope the rule to the org-type field
RevOps lead, round 3
win rate, fiscal Q3
round 3 · 2 of 3
wrong on 1 of 3
fiscal Q3 / calendar Q3
win_rate v4; rule quarter-means-fiscal
partly
turn 3: let the metric’s period default read “Q3” as July to September
served, parameter bound wrong
make the time parameter required, no default
RevOps lead, round 4
pipeline, top 100
round 3 · 1 of 3
wrong, same every run
$412M / a total above the key
open_pipeline_top_accounts v2
yes
turn 3: the served metric ranked customers by deal count, with no early-stage rule
never written: finance’s ranking was nowhere in the context
raise the top-100 conflict; write the stage rule into the metric
both owners, the next day
slipped deals
round 3 · 2 of 3
wrong
96 slipped ($118M) / 218 slipped
win_rate v4 (weak match); the trusted query not retrieved
partly
turn 3: “nothing served defines slipped”; counted any close-date change
written, not served
add alternate labels “pushed”, “rolled” to “Slipped deal”; link the term to the query
RevOps lead, round 4
pipeline created, by segment
round 3 · 3 of 3
wrong, same every run
sealed value / wrong
a newly promoted trusted query
yes
none: the warehouse holds no “created and still open” state
the data
escalate to the platform owner
platform owner
# Trace review: <domain>, round <n> · context v<x.y> · reviewers: <context engineer>, <agent builder>; <domain owner> approves
| Question | Run | Verdict | Expected / returned | Served | Used? | Step where it guessed | Kind of miss | Proposed change | Approved |
|---|---|---|---|---|---|---|---|---|---|| <question> | round <n> · <n of k> | <verdict; mark a break if it passed before> | <value> / <value> | <names and versions> | <yes / no / partly> | <turn, and what it assumed> | <key wrong / budget / never written / written, not served / served, ignored / the data / a break> | <one change> | <who, when> |
<key wrong / budget / never written / written, not served / served, ignored / the data / a break>
<one change>
<who, when>
R2.8 Iteration ledger
One row per round of context changes, with the prediction written before the run, so every gain is traceable and every loss is visible. The stop rule: stop when two rounds in a row move the total by no more than the run-to-run variation (how far the score moves between identical runs), and none of the predicted fixes lands. Cap Phase 3 at five rounds.
iteration-ledger.mdmarkdown
# Iteration ledger: Sales · golden set of 20 · run-to-run variation: 2 questions (the Phase 2 context run three times unchanged: 14, 13, 15) · score = right on every run
| Round | When | Context | Changes | Predicted fixes | Runs | Score | Fixed / broken | Decision, approved by |
|---|---|---|---|---|---|---|---|---|
| 0 | end of Phase 1 | bare schema | none (baseline) | none | 1 | 7 of 20 | none | Gate · eval owner |
| 1 | end of Phase 2 | v1.0 | six metrics, trusted queries, business terms, two rules | none (first scored run) | 1 | 14 of 20 | +7 / 0 | Gate · RevOps lead |
| 2 | Phase 3 | v1.1 | rule "regions roll up to NA, EMEA, APAC"; stage-aging query ranked above a stale one; rule "internal and test accounts are out" as an instruction | stage aging | 3 | 14 of 20 | stage aging / partner-org count, caught by the rerun | keep the first two; rescope the rule · RevOps lead |
| 3 | Phase 3, next day | v1.2 | the rule scoped to org type; "pipeline created by quarter" query promoted | partner-org count, pipeline created | 3 | 14 of 20 | partner-org count / win rate, 1 of 3 runs | keep; raise the top-100 conflict; pipeline created goes to the platform owner · RevOps lead |
| 4 | Phase 3 | v1.3 | top-100 conflict resolved: metric v3 with the stage rule inside; "Slipped deal" labels and link; win rate's time parameter required | pipeline, slipped deals, both win-rate questions | 3 | 18 of 20 | all four, 3 of 3 / none | keep · RevOps lead and FP&A partner |
| 5 | Phase 3 | v1.4 | column description on the stage field: "the first stage is not pipeline" | none expected | 3 | 18 of 20 | none / none | revert: the rule already lives in the metric · RevOps lead |
Stop rule: not fired. Rounds 2 and 3 held the total but each landed its predicted fix; round 4 moved it by 4; round 5 was the only quiet round.
Phase 3 ended at 18 of 20, and the set grew to 50 for the launch gate.
Iteration ledger: Sales · golden set of 20 · run-to-run variation: 2 questions (the Phase 2 context run three times unchanged: 14, 13, 15) · score = right on every run
Round
When
Context
Changes
Predicted fixes
Runs
Score
Fixed / broken
Decision, approved by
0
end of Phase 1
bare schema
none (baseline)
none
1
7 of 20
none
Gate · eval owner
1
end of Phase 2
v1.0
six metrics, trusted queries, business terms, two rules
none (first scored run)
1
14 of 20
+7 / 0
Gate · RevOps lead
2
Phase 3
v1.1
rule “regions roll up to NA, EMEA, APAC”; stage-aging query ranked above a stale one; rule “internal and test accounts are out” as an instruction
stage aging
3
14 of 20
stage aging / partner-org count, caught by the rerun
keep the first two; rescope the rule · RevOps lead
3
Phase 3, next day
v1.2
the rule scoped to org type; “pipeline created by quarter” query promoted
partner-org count, pipeline created
3
14 of 20
partner-org count / win rate, 1 of 3 runs
keep; raise the top-100 conflict; pipeline created goes to the platform owner · RevOps lead
4
Phase 3
v1.3
top-100 conflict resolved: metric v3 with the stage rule inside; “Slipped deal” labels and link; win rate’s time parameter required
pipeline, slipped deals, both win-rate questions
3
18 of 20
all four, 3 of 3 / none
keep · RevOps lead and FP&A partner
5
Phase 3
v1.4
column description on the stage field: “the first stage is not pipeline”
none expected
3
18 of 20
none / none
revert: the rule already lives in the metric · RevOps lead
Stop rule: not fired. Rounds 2 and 3 held the total but each landed its predicted fix; round 4 moved it by 4; round 5 was the only quiet round. Phase 3 ended at 18 of 20, and the set grew to 50 for the launch gate.
# Iteration ledger: <domain> · golden set of <n> · run-to-run variation: <questions>, from <k> identical runs · score = right on every run
| Round | When | Context | Changes | Predicted fixes | Runs | Score | Fixed / broken | Decision, approved by |
|---|---|---|---|---|---|---|---|---|| <n> | <when> | <v> | <changes> | <questions, written before the run> | <k> | <your run> | <questions> / <questions> | <keep / revert> · <owner> |
Stop rule: <fired | not fired | five-round cap reached>, and why.
Optional columns: cost and latency per question, from the traces.
Iteration ledger: <domain> · golden set of <n> · run-to-run variation: <questions>, from <k> identical runs · score = right on every run
Round
When
Context
Changes
Predicted fixes
Runs
Score
Fixed / broken
Decision, approved by
<n>
<when>
<v>
<changes>
<questions, written before the run>
<k>
<your run>
<questions> / <questions>
<keep / revert> · <owner>
Stop rule: <fired | not fired | five-round cap reached>, and why. Optional columns: cost and latency per question, from the traces.
R2.12 Sponsor readout
One page the exec sponsor reads in five minutes: the score against the golden set, what changed, and what needs a decision. Every week, and at each gate.
sponsor-readout.mdmarkdown
# Sponsor readout: Sales · end of Phase 2 · delivery lead
Status: on track. Gate this week: metrics published and scored. Met.
## Score against the golden set
Six metrics, one run per question: 14 of 20, up from the bare-schema baseline of 7 of 20.
## What changed
- Six metrics approved, each with an owner, a version and its provenance
- Most conflicts settled on provenance; the RevOps lead decided the split ones; one escalated to you (below)
- Win rate now excludes disqualified deals: the dashboard version predated that stage, and every recent analyst query excluded it
## Decisions needed from you
- For multi-year deals, is the amount first-year ARR or total contract value? The RevOps lead and the FP&A partner
disagree. Until you decide, the agent flags the conflict instead of answering. Decided at this readout: first-year ARR.
- Your question on why EMEA dropped waits until the numbers are released. It sits in the backlog with a date.
## Risks
- The graders must seal 30 more questions by the end of Phase 3 (owner: eval owner)
- The FP&A partner's hour in Phase 3, for any decision on the top 100 (owner: delivery lead)
## Next week
Measure run-to-run variation, then fix from traces; the RevOps lead approves each change; the set grows to 50.
Sponsor readout: Sales · end of Phase 2 · delivery lead
Status: on track. Gate this week: metrics published and scored. Met.
Score against the golden set
Six metrics, one run per question: 14 of 20, up from the bare-schema baseline of 7 of 20.
What changed
Six metrics approved, each with an owner, a version and its provenance
Most conflicts settled on provenance; the RevOps lead decided the split ones; one escalated to you (below)
Win rate now excludes disqualified deals: the dashboard version predated that stage, and every recent analyst query excluded it
Decisions needed from you
For multi-year deals, is the amount first-year ARR or total contract value? The RevOps lead and the FP&A partner disagree. Until you decide, the agent flags the conflict instead of answering. Decided at this readout: first-year ARR.
Your question on why EMEA dropped waits until the numbers are released. It sits in the backlog with a date.
Risks
The graders must seal 30 more questions by the end of Phase 3 (owner: eval owner)
The FP&A partner’s hour in Phase 3, for any decision on the top 100 (owner: delivery lead)
Next week
Measure run-to-run variation, then fix from traces; the RevOps lead approves each change; the set grows to 50.
# Sponsor readout: <domain> · <week or gate> · <delivery lead>
Status: on track | at risk | blocked. Gate this week: <gate>, <met / not yet>## Score against the golden set
<context version, score, change since last week, inside run-to-run variation or not>
## What changed<context changes this week, and how each conflict was settled>## Decisions needed from you<decision, why it matters, by when>## Risks<live rows from the risk log, with owner and mitigation>## Next week<plan to the next gate>
Sponsor readout: <domain> · <week or gate> · <delivery lead>
Status: on track | at risk | blocked. Gate this week: <gate>, <met / not yet>
Score against the golden set
<context version, score, change since last week, inside run-to-run variation or not>
What changed
<context changes this week, and how each conflict was settled>
Decisions needed from you
<decision, why it matters, by when>
Risks
<live rows from the risk log, with owner and mitigation>
Next week
<plan to the next gate>
R2.18 Risk log
The live list of what could stall the engagement. Open it at the kickoff from the engagement rows in R1 and read it at every readout.
risk-log.mdmarkdown
# Risk log: Sales · opened at the kickoff · delivery lead · as it stood after launch
| # | Risk | Signal to watch | Likelihood, impact | Owner | Mitigation | Status |
|---|---|---|---|---|---|---|
| 1 | No per-call trace export | the chat tool exports a nightly summary only | H, H | agent builder | build a per-call export; read one trace end to end before Phase 1 | closed in Phase 0 |
| 2 | Security review opens late | no walk-through booked | M, H | security lead | walk the data-flow diagram at the kickoff | closed in Phase 0 |
| 3 | Why-questions before the numbers are right | the CRO asked in Phase 2 | M, M | delivery lead | deferred by the brief; dated in the backlog | closed: why-set ran after launch |
| 4 | Pipeline-creation questions cannot pass | the same miss on every run, the data (Phase 3) | H, M | platform owner | held back by name; build the "created and still open" state | closed after launch |
| 5 | A schema change breaks served queries | the platform owner's schema alert | M, H | platform owner | the regression set reruns on every alert | fired after launch; fixed by the team alone |
Escalate a High/High to the exec sponsor the same day.
Risk log: Sales · opened at the kickoff · delivery lead · as it stood after launch
#
Risk
Signal to watch
Likelihood, impact
Owner
Mitigation
Status
1
No per-call trace export
the chat tool exports a nightly summary only
H, H
agent builder
build a per-call export; read one trace end to end before Phase 1
closed in Phase 0
2
Security review opens late
no walk-through booked
M, H
security lead
walk the data-flow diagram at the kickoff
closed in Phase 0
3
Why-questions before the numbers are right
the CRO asked in Phase 2
M, M
delivery lead
deferred by the brief; dated in the backlog
closed: why-set ran after launch
4
Pipeline-creation questions cannot pass
the same miss on every run, the data (Phase 3)
H, M
platform owner
held back by name; build the “created and still open” state
closed after launch
5
A schema change breaks served queries
the platform owner’s schema alert
M, H
platform owner
the regression set reruns on every alert
fired after launch; fixed by the team alone
Escalate a High/High to the exec sponsor the same day.
# Risk log: <domain> · opened <date> · <delivery lead>
| # | Risk (an R1 symptom, or new) | Signal to watch | Likelihood, impact | Owner | Mitigation | Status |
|---|---|---|---|---|---|---|
| 1 | <risk> | <the observable signal> | <H/M/L>, <H/M/L> | <role> | <action, due> | open / closed <date> |
Escalate a High/High to the exec sponsor the same day.
Risk log: <domain> · opened <date> · <delivery lead>
#
Risk (an R1 symptom, or new)
Signal to watch
Likelihood, impact
Owner
Mitigation
Status
1
<risk>
<the observable signal>
<H/M/L>, <H/M/L>
<role>
<action, due>
open / closed <date>
Escalate a High/High to the exec sponsor the same day.
Phase 4: release and hand over
R2.9 Release note
What shipped, what it scored against the sealed set, and how to roll it back.
release-note.mdmarkdown
# Release: Sales context v1.0 · Phase 4 · approved by the RevOps lead; signed by the CRO
Launch gate: governed 20 of 20, right on every run, refusing all 3 out-of-scope questions; exploratory 25 of 30 on every run
against a bar of 24; everything that passed at Phase 3 still passes; random pass audit done
| Type | Name | Version | Change | Settled by |
|---|---|---|---|---|
| metric | open_pipeline_top_accounts | v3 | added; v2 retired, kept on record | both owners (top-100 conflict) |
| metric | win_rate | v4 | added: won / (won + lost), by close date, disqualified out | provenance (recency) |
| metrics | closed_won_arr, open_pipeline, avg_deal_size, stage_conversion | v1 | added | provenance |
| business terms | Slipped deal (pushed, rolled, slid); Top accounts; 10 more | 2; 2; 1 | added; linked | none needed |
| rules | quarter-means-fiscal; regions-roll-up; flag-conflicts | 1 | added | RevOps lead |
| trusted queries | 38 | 1 | added | provenance |
Held back by name: pipeline-creation questions, until the "created and still open" state exists
Known limits: why-questions, follow-up turns and entity lookups are not measured
Rollback: repoint to the previous context version with the previous harness build; the RevOps lead decides
Next: the open conflicts on released questions, then the why-layer
Release: Sales context v1.0 · Phase 4 · approved by the RevOps lead; signed by the CRO
Launch gate: governed 20 of 20, right on every run, refusing all 3 out-of-scope questions; exploratory 25 of 30 on every run against a bar of 24; everything that passed at Phase 3 still passes; random pass audit done
Type
Name
Version
Change
Settled by
metric
open_pipeline_top_accounts
v3
added; v2 retired, kept on record
both owners (top-100 conflict)
metric
win_rate
v4
added: won / (won + lost), by close date, disqualified out
Held back by name: pipeline-creation questions, until the “created and still open” state exists Known limits: why-questions, follow-up turns and entity lookups are not measured Rollback: repoint to the previous context version with the previous harness build; the RevOps lead decides Next: the open conflicts on released questions, then the why-layer
# Release: <domain> context v<x.y> · <date> · approved by <domain owner>; signed by <exec sponsor>
Launch gate: <bar per lane> on the sealed set: <your run>; regression <held / not>; random pass audit <done>
| Type | Name | Version | Change | Settled by |
|---|---|---|---|---|| <metric / rule / business term / trusted query> | <name> | <v> | <added / changed / retired> | <provenance / owner> |
Held back by name: <kinds of question, and what brings them back>
Known limits: <unmeasured question types; open conflicts>
Rollback: <previous context version and harness build; who decides>
Next: <next-version backlog>
Release: <domain> context v<x.y> · <date> · approved by <domain owner>; signed by <exec sponsor>
Launch gate: <bar per lane> on the sealed set: <your run>; regression <held / not>; random pass audit <done>
Type
Name
Version
Change
Settled by
<metric / rule / business term / trusted query>
<name>
<v>
<added / changed / retired>
<provenance / owner>
Held back by name: <kinds of question, and what brings them back> Known limits: <unmeasured question types; open conflicts> Rollback: <previous context version and harness build; who decides> Next: <next-version backlog>
R2.19 Handover checklist
The Phase 4 test that the company runs the loop without the delivery team.
handover-checklist.mdmarkdown
# Handover checklist: Sales · Phase 4 · signed by the RevOps lead and the delivery lead
- [x] Every metric (6), rule (3) and business term (12) has an owner on the company's side and a version
- [x] The golden set (50) is sealed, owned by the eval owner, and versioned; the 45 always-right questions run as the regression set
- [x] The conflict records and the iteration ledger are edited by their owners, not by the delivery team
- [x] One pass run together: the open conflicts resolved, regression 45 of 45; run by the agent builder, graded by the eval owner
- [ ] One pass run alone within two weeks (done after launch: a schema change, rerun and fixed by the team)
- [x] Production traces reach the company's log store per call; user corrections reach the conflict list as proposed changes
- [x] A rerun fires on every context change (the full set) and on every schema change (the regression set); the platform owner owns the alert
- [x] The next-version backlog and the domain-two plan agreed
- [x] Postmortem and pattern write-up drafted, reviewed by the RevOps lead
Open: pipeline-creation questions wait on the new data state; the arbiter for words finance and sales both own
Handover checklist: Sales · Phase 4 · signed by the RevOps lead and the delivery lead
# Handover checklist: <domain> · Phase 4 · signed <date> by <domain owner>, <delivery lead>
- [ ] Every metric, rule and business term has an owner on your side and a version
- [ ] The golden set is sealed, owned by the eval owner and versioned; its always-right questions run as the regression set
- [ ] The conflict records and the iteration ledger are edited by their owners
- [ ] One pass run together
- [ ] One pass run alone within two weeks (due <date>)
- [ ] Production traces reach your log store per call; user corrections reach the conflict list as proposed changes
- [ ] A rerun fires on every context change and every schema change; <owner> owns the alert
- [ ] Next-version backlog and domain-two plan agreed
- [ ] Postmortem and pattern write-up drafted and reviewed by <domain owner>
Open: <what waits, and on whom>
Handover checklist: <domain> · Phase 4 · signed <date> by <domain owner>, <delivery lead>
R2.20 Pattern write-up
A short, anonymised account of what the engagement showed, for whoever owns the platform it ran on. The delivery lead drafts it within a week of launch:
Collect the decisions log, the iteration ledger and the postmortem.
Describe the domain’s shape: industry, lane split, estate size, and whether an agent already existed.
List what moved the score and what did not.
Sort every fix into two piles: keep the fixes the next engagement will need, throw away the ones that fitted only this estate.
Name each missing capability in one line, with the trace or decision that showed it.
Have the domain owner check the anonymisation, then send it.
pattern-write-up.txttext
Pattern: a definition kept in a spreadsheet hid a conflict until Phase 3
Domain shape: B2B software, sales pipeline; 20 governed and 30 exploratory questions at launch; CRM and billing; no agent at the start
What happened: graders disputed the top-100 source in Phase 1; the FP&A partner chose the board pack, and the choice stayed on the item.
Finance's ranking lived in a spreadsheet, so the only ranking in query history was the deal-count tile.
The 31 queries that pasted finance's list were set aside as a hard-coded list, which raised no conflict.
Phase 2 approved the deal-count ranking; the Phase 3 raw trace exposed it; the owners resolved it in 20 minutes.
What moved / what did not: a rule served too widely broke one question, caught by the rerun and fixed the next day;
the top-100 fix, a term link and a required time parameter took the score from 14 to 18 of 20; a column description moved nothing and was reverted
Platform: a set-aside list of IDs with no known source should ask the owners where it came from
Throw away: the "created and still open" state was specific to this warehouse
Missing capability: a sealing dispute should also reach the conflict list, with no sealed value attached
Reviewed for anonymisation by: the RevOps lead
Pattern: <one line>
Domain shape: <industry, kinds of question, lane split, estate size, starting point>
What happened: <the conflict, miss or result, and the round that showed it>
What moved / what did not: <from the ledger>
Platform: <fixes the next engagement will need too>
Throw away: <fixes specific to this estate>
Missing capability: <one line each>
Reviewed for anonymisation by: <domain owner>, <date>
R2.21 Field postmortem
A blameless review that examines the system, never a person. Run it at the end of every engagement, and whenever a gate slips by more than a week, a wrong number reaches a governed-lane user, the score drops after a release, a context change is rolled back, or the engagement stops before launch.
Write it about conditions. “The domain owner was slow to decide” is blame. “Decisions waited a week because the owner’s hours were agreed in Phase 0 and never put on a calendar” is a condition, and a condition has a fix. Run it in five steps:
Collect the record: decisions, the iteration ledger, risks and readouts.
Write the timeline in order, with no interpretation yet.
For each problem, find what in the plan, the roster or the tooling made it likely.
Write actions with owners and dates. Each changes a checklist, a template, a runbook step or the platform. “Be more careful” is not an action.
Review it with the domain owner and the sponsor in one 45-minute session, then feed it forward to the next engagement.
postmortem.mdmarkdown
# Postmortem: Sales · Phase 4
Trigger: engagement end · Author: delivery lead · Reviewed with: RevOps lead, CRO
## Timeline
Phase 1: graders disputed the source for the pipeline question; the FP&A partner chose the board pack; recorded on the item only
Phase 1: 20 sealed; by design, the context side never saw the item's history
Phase 2: generation set aside 31 queries with a pasted list of 100 account IDs; no conflict raised
Phase 2: the top-100 metric was approved in a batch of six, ranking customers by deal count
Phase 3: the raw trace of the pipeline question showed the ranking
Phase 3: the owners resolved the conflict the next day; the rerun fixed three questions on every run
## Conditions
The wall between the key and the context protected the key and also hid a conflict.
A set-aside list is not a conflict, so it never reached the owner.
Nobody approving the batch asked where the top-100 ranking came from.
Gate 2 passed the metric with its stage rule served only as an instruction, outside its SQL.
## Actions
| Action | Owner | Due |
|---|---|---|
| A sealing dispute about a definition also goes to the conflict list, with no sealed value | eval owner | domain two's Phase 0 |
| Every pasted list of IDs is traced to its source before the concept it touches is approved | context engineer | domain two's Phase 2 |
| Gate 2 reads each metric's SQL for the house rules that apply before approval | domain owner | domain two's Phase 2 |
New R1 row: symptom "graders disagree on a source"; cause "a conflict settled at sealing, never resolved"; fix "send it to the conflict list as well"
Postmortem: Sales · Phase 4
Trigger: engagement end · Author: delivery lead · Reviewed with: RevOps lead, CRO
Timeline
Phase 1: graders disputed the source for the pipeline question; the FP&A partner chose the board pack; recorded on the item only Phase 1: 20 sealed; by design, the context side never saw the item’s history Phase 2: generation set aside 31 queries with a pasted list of 100 account IDs; no conflict raised Phase 2: the top-100 metric was approved in a batch of six, ranking customers by deal count Phase 3: the raw trace of the pipeline question showed the ranking Phase 3: the owners resolved the conflict the next day; the rerun fixed three questions on every run
Conditions
The wall between the key and the context protected the key and also hid a conflict. A set-aside list is not a conflict, so it never reached the owner. Nobody approving the batch asked where the top-100 ranking came from. Gate 2 passed the metric with its stage rule served only as an instruction, outside its SQL.
Actions
Action
Owner
Due
A sealing dispute about a definition also goes to the conflict list, with no sealed value
eval owner
domain two’s Phase 0
Every pasted list of IDs is traced to its source before the concept it touches is approved
context engineer
domain two’s Phase 2
Gate 2 reads each metric’s SQL for the house rules that apply before approval
domain owner
domain two’s Phase 2
New R1 row: symptom “graders disagree on a source”; cause “a conflict settled at sealing, never resolved”; fix “send it to the conflict list as well”
# Postmortem: <domain> · <date>
Trigger: <engagement end | gate slipped | wrong governed number | a break | rollback | stopped early>
Author: <delivery lead> · Reviewed with: <domain owner>, <exec sponsor>## Timeline<when>: <what happened>, in order, no interpretation
## Conditions<what in the plan, roster or tooling made each problem likely>## Actions
| Action | Owner | Due |
|---|---|---|| <a checklist, template, runbook step or platform change> | <role> | <date> |
New R1 rows: <symptom, cause, fix>
Postmortem: <domain> · <date>
Trigger: <engagement end | gate slipped | wrong governed number | a break | rollback | stopped early> Author: <delivery lead> · Reviewed with: <domain owner>, <exec sponsor>
Timeline
<when>: <what happened>, in order, no interpretation
Conditions
<what in the plan, roster or tooling made each problem likely>
Actions
Action
Owner
Due
<a checklist, template, runbook step or platform change>
<role>
<date>
New R1 rows: <symptom, cause, fix>
After release
R2.13 Ontology fragment and business changes
The slice of the business graph a why-question needs. Every entity is bound to its tables and metrics. The business changes list holds the dated changes the agent can test as causes. Build it after the numbers are released.
sales-subgraph.yamlyaml
ontology: sales subgraph · imported from the company glossary (entities, vocabulary) and the BI semantic model (bindings), after launch
owner: RevOps lead # approved the two relationships the EMEA answer turns onentities: # five, cut to what the why-questions touch
- {name: Opportunity, tables: [crm.opportunity, crm.opportunity_snapshot], key: id, metrics: [open_pipeline_top_accounts, win_rate]}
- {name: Account, tables: [crm.account], key: id, metrics: [open_pipeline_top_accounts]}
- {name: Rep, tables: [crm.rep], key: id, metrics: []}
- {name: Territory, tables: [crm.territory], key: id, metrics: []}
- {name: Stage history, tables: [crm.stage_history], key: opportunity_id, metrics: []}
relationships: # the two the EMEA answer turned on
- {from: Territory, to: Rep, name: owned by, rule: a new rep re-qualifies the territory's deals, binding: crm.territory.owner_rep_id}
- {from: Opportunity, to: Stage history, name: re-signing on new terms returns a deal to the first stage, rule: a re-signed deal sits outside open pipeline until re-qualified, binding: crm.stage_history.opportunity_id}
business_changes:
- {date: 2026-05-01, change: EMEA territory realignment; many top-100 accounts changed owning rep, owner: Sales Ops, entities: [Territory, Rep, Opportunity], testable_by: deals whose owner changed that day and have not moved since}
- {date: 2026-05-15, change: enterprise pricing change; open deals re-signed on new terms, owner: Finance, entities: [Opportunity, Stage history], testable_by: enterprise deals back at the first stage after that date}
# The EMEA why-question: pipeline fell $53M. $31M sat in deals stuck after the territory realignment;# $19M was re-signed on new terms after the pricing change. The one why-set miss traced to a comp-plan change nobody wrote down.
ontology: <domain> subgraph · <sources it was imported or written from>, <date>owner: <domain owner>entities:
- {name: <Entity>, tables: [<schema.table>], key: <column>, metrics: [<metrics>]}
relationships:
- {from: <Entity>, to: <Entity>, name: <verb phrase>, rule: <what it means for the numbers>, binding: <join or column>}
business_changes: # written by the owning team as events happen
- {date: <YYYY-MM-DD>, change: <what changed>, owner: <team>, entities: [<Entity>], testable_by: <the SQL signal>}
Toolkit
Straight answers
Say what you measured, and what it means for your warehouse.
Read 3 min
The hardest reader of this book runs a data platform, has built text-to-SQL before and distrusts vendor numbers, with reason. Our numbers come from one warehouse, graded against keys our own analysts wrote. How we measured explains the benchmark and its limits.
The skeptic’s questions
The same questions come up in almost every room: a better model, few-shot retrieval, scale, and who pays for the owners’ time. The card Replies for the skeptic has a reply to each, plus semantic layers, row-level security and lock-in.
What score should we expect?
Quote no score before your baseline exists. Our ladder shows the order of what helped on one warehouse: past SQL beat documentation, metrics beat past SQL alone, and more prose on top added little. We expect that order to transfer. We don’t expect our absolute numbers to, because yours depend on how many of your business’s questions your analysts have already answered in SQL and in BI reports.
After the baseline, quote three scores: the baseline at the end of Phase 1, the metrics score at the end of Phase 2, and the launch gate at the end of Phase 4.
These figures are from July to September 2026, on one model through one reference harness, and nobody optimised for speed. Expect them to date within a quarter.
Measure
What we saw
Time per question
22 to 45 seconds
Best configuration
about 30 seconds and about 4¢ per right answer
What drives cost
model price: one frontier model cost far more per right answer on identical context
Three habits keep the numbers honest:
Report cost per right answer. Cost per call hides the most expensive thing an agent produces: a cheap wrong answer.
Measure latency and cost on your own harness, at the baseline and again after Phase 2. Your harness and model set most of both.
Price one full rerun of the golden set before Phase 3. The hill climb repeats it on every change, and so does the production loop.
What to do on Monday
You don’t need a budget or a vendor to start. You need an hour and one question.
Take one question your leadership asks every week and list the decisions a correct answer needs, with the exercise in The tenth question. Find two unwritten rules.
Pull 20 real questions with known answers for one domain, and run whatever agent you have against them. That is your baseline.
Export the last quarter of query history for that domain. The rules your agent is missing are mostly already in it.
Name the domain owner who will settle definitions, and ask for their hours in writing.
If the baseline is low and the rules are real, you have a context problem, and this book is the plan for fixing it.
Definition of done
Toolkit
Videos
Read 1 min
Every chapter that has a video, in reading order. Press play and watch them back to back, or pick one from the list. Each video is a short, narrated version of its chapter, and each one also sits at the top of its chapter. The narration says “certified metrics”, and the guide says “metrics”: in the benchmark, no person approved the metrics. In the method, each metric’s owner signs it off.
Every question your agent answers... goes through five steps. Intent. Context. SQL. Execute. Insight. And only one of them is still an open problem. This is the playbook in two minutes... how to solve that one.
The open one is context, what a question really means. Ask for our Q3 pipeline... and three rules apply. Fiscal Q3 starts in January. Early stages never count. And test accounts are out. Nobody wrote them down, so the agent guesses. The SQL runs clean... but the number's wrong.
So does fixing context actually work? We tested it on 107 real questions, graded by code. Given bare schema, just the tables, the model scored 31.8%. Then we gave it certified metrics as context... and the same model reached 83.2%.
So where's the gap? The hard half is joins. On bare schema, single-table questions came back right 64.3% of the time. Multi-table ones? Just 11.5%. With certified metrics, the same model got 82.0% of them right. So it's not a model problem... it's a context problem.
And software teams already run the loop that fixes this. Write the tests. Build. Debug. Release. Operate. For an agent, the golden set is the test suite. And certified metrics? They're the context you improve on.
Phase 0 happens before the clock starts. You prove access, and put a name in every role. Phase 1 seals 20+ real questions... and runs a baseline. Phase 2 generates certified metrics, and scores them on the same set. Phase 3 hill-climbs from traces. It runs until the set grows to 50... and nothing that passed has broken. Phase 4 releases, hands over, and books a first solo pass. After that, you keep it running... and the next domain starts from what this one certified.
Along the way, there are eight rules. First, fix the context before you change the model. Then write each business rule into a metric's SQL. Build the golden set before any context. Settle conflicts before the agent ever sees them... provenance first, then the owner. Choose the lane by the use, exploratory or governed. Start with one domain, and the people who own its numbers. Read the raw trace of every miss, and feed real usage back. Last, make the agent reliable on what happened... before you ask it why.
So now context has a test... and a loop around it. Write the tests first, and run every domain through the same loop. Eight short videos take each part, one at a time. Up next... what we learned on our benchmark. That's the evidence behind these rules.
Every question your agent answers... goes through five steps. Intent. Context. SQL. Execute. Insight. And only one of them is still an open problem. This is the playbook in two minutes... how to solve that one.
The open one is context, what a question really means. Ask for our Q3 pipeline... and three rules apply. Fiscal Q3 starts in January. Early stages never count. And test accounts are out. Nobody wrote them down, so the agent guesses. The SQL runs clean... but the number's wrong.
So does fixing context actually work? We tested it on 107 real questions, graded by code. Given bare schema, just the tables, the model scored 31.8%. Then we gave it certified metrics as context... and the same model reached 83.2%.
So where's the gap? The hard half is joins. On bare schema, single-table questions came back right 64.3% of the time. Multi-table ones? Just 11.5%. With certified metrics, the same model got 82.0% of them right. So it's not a model problem... it's a context problem.
And software teams already run the loop that fixes this. Write the tests. Build. Debug. Release. Operate. For an agent, the golden set is the test suite. And certified metrics? They're the context you improve on.
Phase 0 happens before the clock starts. You prove access, and put a name in every role. Phase 1 seals 20+ real questions... and runs a baseline. Phase 2 generates certified metrics, and scores them on the same set. Phase 3 hill-climbs from traces. It runs until the set grows to 50... and nothing that passed has broken. Phase 4 releases, hands over, and books a first solo pass. After that, you keep it running... and the next domain starts from what this one certified.
Along the way, there are eight rules. First, fix the context before you change the model. Then write each business rule into a metric's SQL. Build the golden set before any context. Settle conflicts before the agent ever sees them... provenance first, then the owner. Choose the lane by the use, exploratory or governed. Start with one domain, and the people who own its numbers. Read the raw trace of every miss, and feed real usage back. Last, make the agent reliable on what happened... before you ask it why.
So now context has a test... and a loop around it. Write the tests first, and run every domain through the same loop. Eight short videos take each part, one at a time. Up next... what we learned on our benchmark. That's the evidence behind these rules.
Pilots don't stall on the demo. They stall on the tenth real question. It touches two tables and a house rule... and the answer comes back confident, and wrong. So here's what we learned on our benchmark... what gets the tenth question right?
Take one question... what's our Q3 sales pipeline? The query gets the fiscal quarter right, and it returns $18.4 million. Now add one line... and it's $11.2 million. That's the number Finance plans on. No bug here. That rule just isn't in any table, column, or description.
That rule is one of five decisions hiding in this question. Which stages count? Which rows are always out? Which quarter, and which amount, on which table? And how do the rows get put together? Guess each one right 80% of the time... and you'll get all five right about one time in three. That's just arithmetic. On bare schema, only the tables, we measured 31.8%.
So we put it to the test. Our benchmark has 107 real questions, with sealed answers, graded by code. Swap the model, and bare schema scores anywhere from 29% to 40%. Give it five trusted past queries, and all three models we ran scored above 66%. Give it certified metrics with their SQL... and our default model hit 83.2%. So which matters more? Context added 26 points or more to each model we tested both ways. Switching models moved about 10. In fact, the best model without context lost to the weakest model with it.
Now, each kind of context, measured on its own. Descriptions and documentation reached 39.3%. Usage patterns from the query log... 43.9%. Certified metrics, with their SQL, reached 83.2%.
Where does context matter most? In the joins. On bare schema, single-table questions scored 64.3%. Multi-table questions? Just 11.5%. Add certified metrics, and they climb to 92.9%... and 82.0%. And refusals on join questions dropped from 31... to just 1.
Form matters too. Take the same rules, and write them in plain English... then in SQL. On multi-table questions, English scored 65.6%... while SQL scored 82.0%. On single-table questions, they tied... at 95.2%.
Then we rebuilt five published methods on top of our certified metrics... and ran the layer alone, the same way. Four scored lower, by up to 14 points... at three to five times the cost per right answer. The fifth, intent search, gained 1.9 points. That's inside the noise... at twice the cost. Context moved the score. The method of reasoning didn't.
So what does work? A certified metric. It seals every decision into one statement... that runs. Here's our running example. The sales team asks... how much open pipeline do we have with our top 100 customers? Left to guess, the agent said $1.31 billion. With the metric... $412 million. And the business can read it, and correct it. It carries its owners, and a version.
It's cheaper and faster, too. Against the average of the 12 other setups we ran... it cost less than half as much per right answer. And it answered in about a third of the time... 29 seconds a question, against 85. Only curated past queries were cheaper and faster... and they scored 75.7%.
Then choose the lane by asking one thing. If this answer is wrong, and nobody notices... where does it land? The top-hundred pipeline lands in the board pack. So it's governed... a certified metric, or no answer. Which deals slipped? That one's exploratory. The agent writes its own SQL from a trusted past query, and shows it. 96 deals had slipped. And win rate with those customers was 31%... against 24% elsewhere.
So the tenth question never needed a bigger model. It needed the missing rule. Fix the context before you blame the model. Next up: Why evals come first. Because without a golden set, you can't tell a fix from luck.
In software, QA decided what shipped. For agents... the eval does. Without one, saying "it works" is just an opinion, held by whoever built it. In this video... why evals come first, and how you'd know the agent works.
An agent changes every time you edit a metric, a rule, the model, or the prompt. So the eval reruns on every change, before users ever see it. Think of it like a test suite before a release.
And here's the thing... a demo can't settle three questions. Is it working? Did that change help, or did it just move the failures? And where, exactly, does it break?
A right answer, once, isn't a capability. So run each question three to five times. Right every time? It knows. Right some of the time? It's guessing. Never right... it can't.
On our benchmark, two runs of the same setup scored 86 and 80... out of 107. Now look across 154 runs, of every setup we tried. 105 of 107 questions got answered right at least once. Yet the best single run got 90. So the knowledge is there... the consistency isn't.
So what goes in one row of the golden set? Three parts. First, the question, in the business's own words. That's the only part the agent sees. Then the SQL, which is evidence for diagnosis. And the sealed answer, $412M... that's the grade.
An eval worth trusting has four properties. First, it's representative... keep the hard half. On bare schema, just the tables, single-table questions scored 64.3%. Multi-table? 11.5%. With certified metrics, it's 92.9% and 82.0%. So an easy set hides most of the difference between setups. Second, un-dominated. No single fact gets to swing the headline. Third, live. Questions grow out of real use, and when the set has a wrong answer, it gets corrected. Fourth, sealed. If anything in the pipeline can see the answer... the agent will find it.
Grade the answer first. Why? Because two different queries can both be right. LinkedIn found that about 60% of its questions had more than one valid answer. So grading isn't one check. It's a stack of them. Check the value, within tolerance. Look at the SQL and the trace. Have a judge check the answer's shape. And run a leak check. And count refusals apart from wrong answers... though both are still misses.
So what's the eval's real output? A work queue. Never patch context for one question. Instead, read every miss as one of three things... a definition never written, written but not served, or served and ignored.
So now, whether it works isn't an opinion. It's a score anyone can rerun. Build the golden set before you build any context. Without it, you can't tell progress from luck. Next up: Semantic views, or metrics? The form your context should take.
Give an agent semantic views as its only way in... and it scores 38.3% on our 107 questions. Now compare. The bare schema, with no context at all? 31.8%. Certified metrics, with their SQL? 83.2%. So, semantic views or metrics? In other words, how should an agent's context be organized?
Start with your gold layer. It carries technical names. But it says nothing about joins, formulas or dimensions. So what fills it? A semantic layer... it fills that gap. It's got four parts... what the tables mean, how they join, the metrics, and the dimensions.
You can lay that context out three ways... and each one repeats something. First, per table, like a data dictionary. The joins and cross-table metrics get copied. Second, per logical table, like a semantic view. Now meanings, joins and metrics get copied across views. Or third, per metric. The metric's stored once... and only joins and dimensions repeat.
Here's an illustrative case. Average order value lives in three views... orders, customers and stores. And each one defines it differently. Gross, or net of refunds. Per order, or per customer. So ask the agent, what was AOV last quarter? It can't tell which one to use.
For an agent, those copies are the first cost of views. And there are two more. Second, every question has to pick a view before it can start. Third, fixes land beside the view, as text... and the agent reinterprets them on every question.
So what's the alternative? Make the metric the unit. It's defined once, with its formula, verified SQL, joins and dimensions. And it compiles to the same SQL every time. The business can read it, and correct it... and the fix lands in the definition.
You don't have to replatform. Keep your views. Certified metrics sit beside them... and reach the agent in one context call, per question.
How do you test any layer? Ask it five questions. Here they are.
So that's the gap from the start. Views make the agent pick a copy... metrics give it one definition. Here's the rule. Organize context around the metric, the unit the business asks in. Next, Phase 0, before the clock... picking one domain, and the people who own its numbers.
The sales team's CRO asked for one thing... a pipeline number for the top accounts, one that matches Finance every time. In a 90-minute kickoff, the team picked sales, named two owners, and wrote a one-page brief. Then getting access... took the next two weeks. This is Phase 0: what has to be ready before the first question gets graded.
Phase 0 starts with one domain. Pick one where the questions are bounded, you know the users and the tables, and the owner has time. Try three domains at once... and you get three half-built golden sets.
The brief fits on one page. And it puts every kind of question into a lane. Some questions are governed, like the CRO's top-100 pipeline. Those have to be exact, on every run. Others are exploratory, like which deals slipped. Those clear one pass rate... and the sponsor writes it down before any result.
Next comes access. Every item gets proved by running its test. And the one that's left until last? Trace export... and Phase 3 depends on it. A nightly summary doesn't count. You need a record of every call.
Then put a person's name on every role. Why? RevOps can't settle a conflict... but the RevOps lead can. The co-owner's hour a week? That's the line teams forget. The builder's 20 hours a week? That's the one they underestimate.
Every analytics agent comes down to four parts... the surface, the harness, the model, and the context. Platform-native or custom, it's the same picture. The context layer plugs into the same place in both.
Then build the minimum harness... and stop. That's one context call per question, and one read-only SQL tool. Give it a step budget of 10... and trace every call. Building in-house? Then Phase 0 can take days, and three of its parts are optional.
So, two weeks in... one question could be followed from start to finish. Start with one domain, and the people who own its numbers. Next up, Phase 1: build the golden set that every later change gets scored against.
Two graders checked the same question against two trusted sources... and got two different hundred customers. The question? Open pipeline with our top 100 customers. The sources? The dashboard tile, and the board pack. So who was right? The RevOps lead chose the board pack... the one the sales team's CRO had promised. This is Phase 1: building the golden set... the test every later change is scored against.
Start with at least 20 real questions... the ones the business already asks. Where do they come from? The board pack, and leaders' dashboards. Analyst tickets from the last two quarters. Saved analyst queries, too. And the sponsor's own questions. Then ask the owner one thing... what was the last wrong number that reached a meeting?
Every item goes in one format, with six required fields. An ID and the question. Its lane, and its source. The expected answer, plus the SQL. Two more fields are optional, and they pay off in Phase 3. The decisions the question hides... and the decoy, the answer you get if you guess them.
Write the grading rules before any result exists. Rules written after... bend toward the results. Grade the data first... then the SQL. A wrong query can land near the right number by luck. Allow valid alternatives, like a total, or a breakdown that sums to it. And a governed answer only counts if it's right on every run.
Then seal the set away from the builders... and guard against three leaks. First, golden SQL in the context. Purge it, and record each removal by hash. Second, the agent reading its own work. Exclude its service account. Third, sealed values in served text. Scan every prompt... a hit invalidates the run.
Now run the bare agent, with only the tables, once per question. It got 7 of 20. Take the pipeline question. It came back at $1.31 billion... but the sealed answer is $412 million. So what went wrong? Four reasonable guesses. It ranked by deal count, counted every stage, summed contract value... and joined each deal to every subscription term. Each guess is a line of the decoy. And the SQL still ran clean. That's Gate 1. The sponsor sees where the agent starts.
Remember that disagreement? It's now a sealed item, with the owner's decision in its history. Seal the questions where the builders can't see them... and grade them by code. Next, Phase 2: turning the SQL your analysts already wrote into certified metrics.
By the first afternoon, the metrics agent had drafted candidate metrics... from the analysts' past SQL and their sales dashboards. Most of the conflicts settled on provenance. But one wouldn't. This is Phase 2, generating certified metrics. Phase 1 left the agent at 7 of 20.
Here's the question. On multi-year deals, did the amount mean first-year ARR... or total contract value? It went to the sales team's CRO, who answered, ARR... the figure the board pack uses.
So how do you get there? Five steps take you from past SQL to certified metrics. First, gather past SQL and BI reports... always together. Generate candidates. Witness each one. Resolve the conflicts. Then certify what survives.
Generating them needs no product. A script groups the statements by shape, and a model names each group. It writes no new SQL... and it never sees the golden set.
Nothing's certified until it's run. Every candidate gets five checks. Did it run, and how many rows came back? Does each row count once? Does the prose match the SQL? And is there a literal nobody can explain? If a candidate's uncertain, keep it out entirely. An agent can't weigh a warning.
So how do conflicts settle? On provenance... who ran it, how often, how recently, and whether it matches the warehouse. Win rate, for example, settled on recency. The dashboard version predated the Disqualified stage.
Then certify. Each metric becomes a file, governed like code... with an owner, a version, its provenance, and its SQL. Every house rule goes inside the SQL, where the harness runs it.
Serve it per question... in the form that runs. Does the form matter? In one test, we stripped parts out of each metric. The full metric scored 83.2%. Its name and SQL alone scored 84.1%... the same, within the noise. But its prose alone? That fell 8 points, to 74.8%.
Back to the sales team. Those first-afternoon drafts are now certified metrics. And the agent scores 14 of 20, up from 7. That's Gate 2.
So here's the rule. Write each business rule into a metric's SQL. The agent follows a query... but it skims a paragraph. Next, Phase 3, hill-climb from traces. That's where the definitions nobody raised show up.
Here's the question: how much open pipeline do we have with our top 100 customers? The summary said the agent used the certified metric... and it had. But the raw trace showed something else. It ranked them by number of deals. Finance ranks them by current ARR. This is Phase 3, hill-climbing from traces. Phase 2 got it to 14 of 20. So why do the rest still miss?
It's one loop, run in short rounds. Freeze the context... and predict what'll change. Run it, grade it, then read every miss. Make the smallest fix. Then rerun everything, and record it.
Teams skip two steps. The first: predict before you run. Which questions should each change fix? The second: rerun the whole set. Here's why. A rule meant to drop internal accounts also dropped a partner account... and only the full rerun caught it.
So what's in a trace worth reading? Each served item, by name and version... each tool call, every SQL statement, the answer, and what it cost in tokens, steps and time. Why not just ask again? Because a metric that's wrong the same way every time... never disagrees with itself.
Before you fix a miss, check two things. Is the sealed answer itself wrong? Or did the agent just run out of steps? If not, it's one of three kinds. It was never written. It was written, but not served. Or it was served... and ignored. Our top-100 ranking was never written. Slipped deals was written... but never served.
So how often does this happen? On our benchmark, the configuration we ship, certified metrics with their SQL, missed 18 of 107. 11 of those were about which rows belong. And 4 landed within 1% of the sealed answer.
Then make the smallest fix. Slipped deals took 2 edits to 1 business term... the synonyms "pushed" and "rolled", plus a link to the analyst's query. The top 100 took a 20-minute decision from its 2 owners: rank by ARR. And record the fixes you reverted, too.
Write the stop rule down first. Stop when two rounds in a row move the score less than the run-to-run variation. And don't raise the step budget to cut refusals. Why not? On our ontology setup, a bigger budget cut refusals from 46 to 31. But wrong answers jumped from 27 to 40. A refusal is telling you a decision's missing.
Back to the pipeline question. Ranked by ARR, it now returns $412 million. And Phase 3 closed at 18 of 20. So read the raw trace of every miss. The summary hides the step where the agent guessed. Next, Phase 4: release and hand over, on fresh questions nobody's climbed against.
Here's the trap... a score earned on the questions you tuned against? It flatters the agent. This is Phase 4... release and hand over. Phase 3 closed at 18 of 20. So by now, the golden set had grown to 50. The graders drafted the new ones... and the context engineer never saw them.
The launch gate runs all 50, sealed ones included. Each one runs 3 to 5 times, and governed questions must be right on every run. Then 5 passing questions, picked at random, get re-graded by hand.
And everything that passed at the last gate? It still has to pass. On our benchmark, bare schema, just the tables, got 34 of 107 right. Add certified metrics, and the agent kept every one... 34 of 34.
So what if something falls short? You've got three moves. Ship without it and name it... move it to the exploratory lane... or climb one more round. The CRO signed the launch, and held one question type back, by name. How much pipeline did we create this quarter? It's wrong on every run, because no table records it.
Next, wire the agent to wherever your users ask. There are three paths. A platform agent with context pushed in... the same agent, calling it over MCP... or a custom harness. Whichever you pick, all three reach the same context layer.
On launch day, four checks have to hold. And the one that slips? Traces, reaching a store the team can read. Without traces, the launch waits.
Then you hand over. Everything left behind gets an owner on your side. The decisions log... who settled each conflict, and when... outlasts the rest. Even a model swap. Run one pass together, with the context engineer only watching. Then one alone, within two weeks. The engineer's on call... and nobody calls.
So the CRO signed on a score that was earned... not flattered. The rule? Launch on questions nobody climbed against, and hand over only what your team has run alone. Then keep it running. Domain two starts from what this one certified.
Toolkit
Podcasts
Listen 3 episodes · 9–20 min each
Three conversations, one for each reading path. Pick the one for your role, and keep reading while it plays. The episodes are AI-generated from the guide, so expect the odd slip in tone or wording. The written guide and the episode clarifications hold the facts.
Sponsoring it
The Number Before the Board Meeting · AI-generated
Updated 27 October 2026 · English · AI-generated with NotebookLM. The written guide holds the full definitions and evidence. Episode clarifications correct or qualify what the hosts say.
Research and reference
What we found
Trust a number only when you can see the questions, the misses and the cost behind it.
Read 10 min
Every number in this book comes from one benchmark: 107 real questions our own teams asked of our go-to-market warehouse, each with a sealed answer, graded by code. We ran it more than 150 times, changing one thing at a time. No person wrote the context behind these scores, apart from the semantic-view comparison: our systems built it from the query log, the catalog and existing documentation. Why that rule matters. The rest of the book quotes a handful of those results. This page shows the rest, including what failed and what each answer cost. How we measured explains the method.
The scoreboard
Every setup on the same model and the same questions, ranked, with what each answer cost.
Every setup, one modelThe same 107 questions, ranked by accuracy.
SetupAccuracyPer runPer questionPer right answer
Metrics layer, retrieved per question83.2%$3.4529 s3.9¢
Curated past SQL, ranked by adoption75.7%$1.0722 s1.3¢
Whole layer and past queries in every prompt72.0%$7.2337 s9.4¢
Top five past queries, complete SQL70.1%$1.5545 s2.1¢
Whole layer in every prompt52.3%$4.8558 s8.7¢
Documentation and usage patterns43.9%$1.7378 s3.7¢
Data profiling34.6%$2.4864 s6.7¢
Bare schema31.8%$1.1631 s3.4¢
GLM-5.2 on every row, one run each. Runs vary by about eight questions, so treat gaps under 7 points as unresolved.
Figure
Accuracy, cost per run of all 107 questions, seconds per question and cost per right answer, on GLM-5.2.
Three things stand out:
Context moved the score; the method of reasoning didn’t. On the same model, the setups span 32% to 83%. All but one of the published methods we rebuilt on top of the metrics layer, from candidate generation and unit tests to model-written evidence, scored lower than the layer alone and cost three to five times as much per right answer. The exception, intent-embedding retrieval, came out 1.9 points ahead, inside the noise, at twice the cost.
Curation is cheap. Past queries deduplicated and ranked by how many analysts ran them scored 75.7% at 1.3¢ per right answer, the cheapest right answers on the board.
Structure alone didn’t help. Semantic views and a business ontology, each as the only way in, scored near bare schema, and the ontology took over five minutes a question.
What teams try first
Most teams build the prose forms first. We did too. None of it gave the agent a decision it lacked.
What teams try
What happened
What worked instead
Table and column descriptions
Accuracy barely moved
The table’s own definition, its DDL
Semantic views or a join graph
Questions across several tables stayed mostly wrong
Past queries that show the join working
Better table search
The agent found the right tables more often; its answers did not improve
Past queries served alongside the tables
Embedding search
Worse than plain keyword matching, 55.1% to 68.2%
Ranking on the field names themselves
Profiling the data
Twice the cost, and more confident wrong answers
Serving past queries whole instead of cut short
Loading everything into the prompt
Lower accuracy at twice the cost
A handful of relevant items per question
More documentation, glossary prose and a sharper retriever on top of metrics added little or nothing.
Every setup does well when one table holds the answer. The gap opens when the answer needs a join, and only worked SQL closes it. Four questions with no reference SQL sit in neither group.
Figure
Accuracy on questions one table can answer against questions that need a join, for six setups.
Every setup does well when one table holds the answer. Bare schema already got 64% of those. The setups separate on the 61 questions that need a join. With no context, the agent refused 31 of them outright. Semantic views and the ontology barely moved that. Worked SQL did: past queries reached 61%, and the metrics layer 82%. In a single run of each, the same metrics served as prose instead of SQL lost 16 points on joins and nothing on single tables.
Adding context also broke nothing. In a single run of each, every question bare schema got right, the metrics layer got right too.
By business area
Bare schemaTop five past queriesMetrics layer
Marketing events and campaigns40 questions
1 of 40
23 of 40
30 of 40
Sales pipeline and leaderboards21 questions
10 of 21
20 of 21
18 of 21
Customer success17 questions
4 of 17
11 of 17
15 of 17
Account and product-usage dashboards22 questions
17 of 22
17 of 22
21 of 22
Sales operations7 questions
2 of 7
4 of 7
5 of 7
Same model, same questions. Bare schema solved 1 of 40 marketing questions, because each one hinges on an event rule no table states. The layer's four misses among them trace to one missing exclusion rule.
Figure
Questions answered correctly in each business area, on three setups. The grouping into five areas is ours.
The gap is widest where the business has the most private rules. Marketing questions hinge on event rules that no table states: which campaign counts, which touch gets the credit, which contacts are staff. Bare schema solved 1 of 40. Account and usage dashboards read almost straight off the tables, and bare schema already got 17 of 22.
Worked examples
Four questions, and how four setups answered them. They show the pattern behind the averages, including where the metrics layer lost.
Example 1As of the date of last quarter's business review, how much open new-business and upsell pipeline closing that quarter did we have?
The hidden decision Rebuild each deal's stage, amount, close date and type as they stood on the review date, and leave out early-stage deals.
Bare schemaRefusedSpent all ten queries on one deal's history
Top five past queriesRightAdapted a retrieved point-in-time rebuild
Metrics layer+19% offThe early-stage rule was served three times and not applied
Semantic views−19% offRebuilt as of month end, not the review date
Example 2How much pipeline did the summit influence after the event, at account level?
The hidden decision The table repeats each account's pipeline on every row. Take one value per account, keep deals that entered the first stage after the event, then add up.
Bare schema+342% offSummed every row, with no date gate
Top five past queries+71% offHad the date gate; summed per deal, not per account
Metrics layerRightOne value per account, after the event
Semantic views+303% offOne value per account; no date gate
Example 3After the event, how many opportunities from booth-scan attendees have reached the first stage?
The hidden decision Use the dated stage-entry field and pin the exact booth campaign. Creation date and the "after event" flag both give the wrong count.
Bare schemaRefusedNever found the booth campaign
Top five past queriesRightThe retrieved query had the shape; one query
Metrics layerRightThe same shape; one query
Semantic views+48% offCounted the whole parent campaign
Still fails everywhereHow many customer accounts churned this quarter?
The hidden decision Churn is an event: the account's type changed away from customer this quarter, and deleted customer accounts count too.
Bare schema−40% offCounted a churn-date field on today's snapshot
Top five past queries−40% offThe same field
Metrics layer−40% offNo churn metric exists yet
Semantic views−40% offA churn date on the account
One run each, questions paraphrased. "Off" is the distance from the sealed answer.
Figure
Four benchmark questions, paraphrased, with the decision each one hides and how each setup did.
The first example is the uncomfortable one. The rule that early-stage deals don’t count was in the context three times, and the agent dropped it while adapting the query. A layer can serve the right rule and still lose it to a near-variant, which is why Phase 3 reads traces instead of only adding context. The last example is a gap in the layer: there is no churn metric yet, so every setup counted the wrong field.
Why the last answers still fail
The configuration we ship missed 18 of 107: 17 wrong answers and 1 refusal.
What the agent was missingThe decision behind each miss
Which rows belong: the population or cohort11
When: the time anchor or point in time3
Which touch gets the credit2
The grain: rows counted twice1
Which column is the governed one1
A literal value: a stage name or code0
How far off it wasDistance from the sealed answer
Within 1% of the key4
1% to 20% off6
20% to 50% off6
More than 50% off1
Refused to answer1
The 18 questions the shipping configuration missed: 17 wrong answers and 1 refusal, out of 107. No miss came from a wrong literal value; most came from a rule about which rows count.
Figure
The 18 misses of the shipping configuration, by the decision the agent was missing and by how far off it was.
Most misses are rules about which rows belong: a cohort, an exclusion, a population. None came from a wrong literal such as a stage name, because the metric SQL carries those. Four misses landed within 1% of the key, and all four trace to one missing rule that leaves out internal contacts. One added rule would fix four answers, which is how Phase 3 works: find the decision behind the miss, write it once, and score again.
What each part is worth
To find what carries the weight, we took the layer apart one piece at a time.
Take one layer awaySonnet 5.5. Compare the rows with each other only.
60%70%80%90%
Everything except glossary terms79.4
Except dimensions78.5
Except joins and relationships78.5
Except past queries71.0
Except metrics69.2
Take one part out of each metricGLM-5.2, the same day as the 83.2% run
60%70%80%90%
Metric name and SQL only84.1
The full metric object83.2
Without its trust tag81.3
Prose only, no SQL74.8
The axis starts at 60%. Removing metrics or past queries costs most. Removing the prose costs nothing, and removing the SQL costs 8 points.
Figure
Accuracy with one layer removed, and with one part removed from each metric.
Removing the metrics or the past queries cost the most. The glossary terms, dimensions and join notes could go with almost no loss. Inside each metric, the SQL carried the value: with the prose stripped out, the score didn’t drop, and with the SQL stripped out it fell 8 points.
No single ingredient explains a rescue. Of the 21 questions that SQL turned from wrong to right, none was fixed by literal values alone. The SQL supplied the business values, the right column and the shape of the aggregation together. That is why this book serves whole statements.
How much to trust a gap
86 vs 80The same configuration, run twice8 questions changed verdict between the runs
75 vs 73A second setup, run twice4 questions changed verdict
105 of 107Solved by at least one runAcross more than 150 runs; the best single run solved 90
46 → 31Refusals, when the step budget went up on one setupWrong answers rose from 27 to 40; right ones moved from 34 to 36
Figure
How much results move between runs.
The same setup run twice moved by six questions, and eight questions changed verdict. So we treat a gap under about seven points as unresolved, and quote the configuration we ship rather than its best run. DoorDash reports a run-to-run spread of about four points on its own data agent benchmark. Some movement is the price of an agent that writes its own SQL.
The union is a warning about cherry-picking. Across all our runs, 105 of 107 questions were answered correctly at least once. A team that keeps the best answer from many runs can report almost any number. Score one run, the way users will meet the agent.
What others found
Our numbers are from one warehouse. The direction matches what others report:
DoorDash’s Vera rose from 43% to 90% on about 1,900 questions across 19 business areas. Its team credits harness and data work over new models, and on 100 questions with the same model, Vera passed 73% where a general coding agent with the same tools passed 48%.
Hex’s DataBench reports cost and latency beside every score, the practice this page follows.
What others found covers the published methods we rebuilt and how they did on our questions.
Research and reference
How we measured
A score means something only when the questions are real, the answers are sealed and the grader is code.
Read 5 min
Every number in this book comes from one benchmark we built on our own go-to-market warehouse. This page says what it is, how a run works, how an answer is graded and what it cannot tell you. Use it to judge our numbers, and as a pattern for the golden set you build in Phase 1.
No hand-written context
The benchmark had one rule from the start: no person writes the context. From bare schema to the configuration we ship, every metric, past query, join and term the agent saw was built by our own systems from what the warehouse already had: the analyst query log, the catalog and existing documentation. The pipeline mined the definitions, merged the duplicates, ran each metric against the warehouse to check it, and ranked what it kept by how often analysts used it. Where two definitions with the same name disagreed, it held both back. Nobody picked a winner.
People did two things: they wrote the questions and sealed the answers. The one exception is a comparison: the semantic-view setup ran on 40 semantic model files written by hand, because that is how such a layer is built. It scored 38.3%, well below the layer our systems built.
We set the rule because hand-written context doesn’t scale. An analyst can tune one domain’s context until the score looks good, and the next domain starts from zero. So the scores show what automation reaches on its own. In the benchmark, each metric was mined, checked by running it and ranked by use, with no person approving it. In an engagement, the domain owner reviews and approves each metric on top of that, as in Phase 2. We have not measured what that review adds.
The questions
We started from 120 questions our own teams had asked of the data: dashboard tiles, questions from business reviews, and requests that came to analysts. Each one has a single right answer, usually a number, a count or a date. We set thirteen aside because they needed knowledge that sits in no table, query or document the agent could reach, such as the meaning of a list kept only in an event brief. That leaves 107.
They span five areas of a go-to-market business: marketing events and campaigns, sales pipeline and leaderboards, customer success, account and product-usage dashboards, and sales operations. Most ask “how much” or “which ones”. None asks “why”.
Each question hides at least one decision the schema doesn’t state. Six examples, paraphrased:
The question
The decision it hides
As of the date of last quarter’s business review, how much open new-business and upsell pipeline did we have?
Rebuild every deal’s stage and amount as they stood on that date. Today’s values give a different answer.
How many customer accounts churned this quarter?
Churn is an event: the account’s type changed from customer this quarter. The current type field can’t tell you when.
What share of agent tool requests were reads?
The business divides reads by reads plus writes, not by every request.
How many customer contacts registered for our spring event?
Leave out deleted records and our own employees.
How much pipeline did the summit influence?
Count each account once before you sum, or one account’s deals are counted several times.
How many opportunities entered the first stage after the event?
Use the dated stage-entry field. Creation date and the “after event” flag both give the wrong count.
Every answer key was written by running the correct SQL against the frozen warehouse and checking the result against the source the business trusts, such as the dashboard or the review deck.
How a run works
Questionone of 107 real questions, with the table names
→
Context under testbare schema, descriptions, past queries or metrics
→
Agentone read-only SQL tool, a fixed step budget, every call traced
→
Answera number, a count, a date, or a refusal
→
Gradercode compares it with the sealed key; a refusal is a miss
Frozen warehouse the agent queries a read-only copy, so the right answer never movesFirewall the sealed key, correct SQL and hidden decision stay on the grader's side
Figure
One run, end to end. The agent sees only the question, the tables and the context under test. The grader alone sees the sealed answer.
A frozen warehouse. Every run queries the same read-only copy of the warehouse, so the right answer never moves.
One agent, one tool. The agent gets the question, the context being tested, and one read-only SQL tool. It explores, queries and answers within a fixed step budget.
Only the context changes. Between arms of a comparison, the model, the tool, the budget and the questions stay the same. Only the context in front of the question changes: bare schema, descriptions, past queries, metrics.
A firewall. Each question is split in two. The agent’s half holds the question and the table names. The grader’s half holds the answer, the correct SQL and the hidden decision. The grader checks the exact prompt of every run and flags any that saw part of the answer.
How an answer is graded
Code grades every answer. Nobody reads an answer and decides it is close enough.
Numbers match when they agree within half a percent, so rounding doesn’t fail a correct answer. A percentage given as a fraction, or the other way round, still matches.
Dates match on the day, and on the minute when both sides carry a time.
A refusal is a miss. “I can’t determine this” scores the same as a wrong number. An agent that refuses often looks careful and still fails the business.
One boundary case gets a small band: a trailing 90-day window where three start dates are defensible.
How to read the numbers
Runs vary. The same setup run twice moved by about eight questions out of 107. Treat a smaller gap as unresolved.
We quote the configuration we ship. Results for other configurations are separate comparisons.
One model by default. Most comparisons use GLM-5.2. The model chart in The tenth question and the Sonnet ablation chart name their models.
Cost and time are recorded. Every run logs tokens, cost and seconds per question, so a better score can be weighed against what it costs.
What it can’t tell you
It is one warehouse, in one business, with our own analysts’ questions. Expect your absolute numbers to differ, and the order of what helps to hold: past SQL beats documentation, and metrics add to both. The questions are about what happened, not why, and the set does not measure why-questions.
Research and reference
What others found
Read 6 min
Other teams have shipped talk-to-data agents and written up what worked, and researchers have tested the same ideas on public benchmarks. Read that work for its mechanisms. Each source ran on a different warehouse, with different questions and its own definition of a right answer, so its scores won’t transfer to yours. The last section shows what happened when we rebuilt eight of these methods on our own benchmark.
Past queries and examples
Uber, QueryGPT.Uber scopes each agent to a curated workspace for one domain and builds its golden set from real query logs. Both ideas carry over. A small, curated scope beats the whole warehouse, and the questions worth testing are the ones people already ask.
Pinterest, text-to-SQL in Querybook. Pinterest summarises its tables and past queries, embeds the summaries, and retrieves by similarity before writing SQL. It reported that table documentation raised its table-search hit rate from 40% to 90%. That number measures finding the table. In our runs, better table search left accuracy flat, so judge a retriever by the answers it leads to.
Vanna. A vendor test found schema-only prompts about 3% accurate, and about 80% with ten relevant example queries. It is a small set run by a vendor. The direction matches our ladder, where past SQL was the largest single step.
Automatic metadata extraction (arXiv 2505.19988). This paper extracts context three ways: profiling the data, analysing the query log, and having a model describe each past query in plain words. Profiling alone took first place on the BIRD leaderboard, because BIRD ships no query log. For an enterprise, the query log is the part to study, since you have one and BIRD doesn’t.
Governed metrics
Lyft, Metric Semantic Layer. Lyft keeps each widely used metric in one versioned package: a YAML definition, a SQL template and two owning teams. A business owner answers for the definition, an operational owner for the data behind it, and every change needs both. A metric qualifies only with at least two distinct uses. The same definitions feed dashboards, data quality checks, ML models and an MCP server that hands agents the SQL. Lyft says agents answer metric questions more accurately with it, and publishes no figure. This is the closest public match to the metrics in this book, down to the owners.
OpenAI, in-house data agent. OpenAI describes an internal agent that combines warehouse metadata, business context, table knowledge drawn from code, and memory of past analyses. When an intermediate result looks wrong, the agent investigates and tries again. Read it as a design description of what a production data agent draws on, since it gives no score on a fixed question set.
Retrieval, evidence and checks
CHESS (arXiv 2405.16755). Four agents split the work. One searches an index of the database’s actual values and descriptions, one prunes the schema, one writes and revises candidate queries, and one writes unit tests to choose between candidates. It reported 71.10% on the BIRD test set, within 2% of the best proprietary method with about 83% fewer model calls. The value index is the part to borrow: it finds literals such as status codes and tag names that no description mentions.
SEED (arXiv 2506.07423). BIRD supplies a hand-written hint with each question. SEED has a model read the schema, descriptions and sample values and write those hints itself. Its authors report a clear gain over no hints, and sometimes over BIRD’s own. The risk for a practitioner is that a generated hint reads as fact whether or not it matches the data.
Anthropic, context engineering. Anthropic’s guidance for agents is to serve the smallest set of high-signal context the task needs, retrieved when the agent needs it, instead of loading everything up front. Our runs agree: loading the whole metrics layer into every prompt scored 52%, and serving a handful of items per question scored 83% at under half the cost per right answer.
How to measure
Anthropic, evals for agents. Build eval tasks from real failures, keep a capability suite apart from a regression suite, and read the transcripts instead of trusting a pass rate. This is the golden set, the regression rerun and the raw trace of this book, arrived at from the agent side.
LinkedIn.About 60% of more than 130 questions had more than one valid answer. Write answer keys that accept the alternatives, or you will grade correct answers as misses.
BIRD. 12,751 question and SQL pairs over 95 databases, with a hint of outside knowledge written for each question. At release, ChatGPT scored 40.08% against 92.96% for people. Its hints are written once per question. A library of definitions your owners maintain is a different thing, and BIRD scores say little about it.
Spider 2.0. 632 tasks drawn from enterprise workflows. The best agent at release solved 21.3%, against 91.2% on Spider 1.0 and 73.0% on BIRD. Enterprise warehouses are much harder than academic sets, so put a date on any leaderboard figure you quote.
Real past SQL is the strongest single input. Uber, Vanna and Pinterest build on it, and it was the largest step on our ladder.
Less context, chosen well, beats more. Anthropic’s guidance and our runs agree: a few high-signal items per question beat the whole layer in every prompt.
Generated context helps from a weak start and hurts from a strong one. SEED and profiling report gains over bare or hint-free baselines. Added on top of our strong context, every method that injected a claim lost accuracy.
On our benchmark
We rebuilt each method and ran it once on 107 questions from our own go-to-market warehouse. Most methods ran on top of our metrics layer, so each row measures what the method adds to an already strong setup. That is a harder test than the papers set themselves. Treat a gap under about 8 questions as unresolved.
Approach
Source
How it works
Accuracy
Cost per run
Seconds per question
Intent-embedding retrieval
Pinterest
Past queries retrieved by embedding a model-written description of each query’s intent, in place of matching field names.
66.4%
$5.24
68
Metric groups
Lyft
The agent picks a governed metric by name and a renderer writes the SQL. Pilot domains only.
64.5%
$2.12
43
Value index and cross-check
CHESS
An index of every column value, several candidate queries, and unit tests to pick one.
57.9%
$11.29
222
Fused candidates
CHESS, SEED and Companion Agents
Parallel candidate generation from the three papers, combined with unit testing.
57.0%
$8.14
134
Generated evidence
SEED
A model writes hints about the data, served to the agent as fact.
50.5%
$6.15
142
Semantic views
Hand-written semantic models (OSI format)
40 hand-written semantic model files and no schema.
38.3%
$4.87
146
Data profiling
arXiv 2505.19988
Column statistics, sample values and inferred joins on top of bare schema.
34.6%
$2.48
64
Ontology in SPARQL
Ontop and R2RML
The agent queries a business ontology in SPARQL, translated to SQL at run time. No schema.
33.6%
$8.14
317
For scale, our metrics layer, metric SQL plus trusted past queries served per question, scored 83.2%, and bare schema scored 31.8%. No rebuilt method came close to the metrics layer, and profiling and the ontology landed near bare schema.
This page lists what goes wrong by the symptom you see, with the smallest fix for each. Use it in two places. In Phase 3, walk a miss down the card Why did this miss?, then find its symptom here and record the fix in the iteration ledger. At the kickoff, seed the risk log from the engagement rows and review it at every readout.
Every row names its branch on that card:
never written: the decision exists nowhere in the context, or sits in the wrong place.
written, not served: it is in the context and did not arrive for this question, or arrived crowded out or cut short.
served, ignored: it arrived and the agent took another path.
key wrong: the fault is on the measuring side: the golden set, the grader, or reading run-to-run variation as a real change.
budget: the fault is in the harness. It ran out of steps, errored, or cannot export what the loop needs.
For an engagement row, the branch is the kind of miss the failure first shows in the traces.
The Evidence column says measured when a benchmark comparison backs the row, and diagnosis when the row comes from reading traces or from engagements, with no measured comparison.
Agent failures
A plausible number from clean SQL, and finance says it is wrong
CauseA business decision, such as which stages count or which accounts are out, is written nowhere
FixWrite it into a metric; let provenance or the owner settle it
never writtenPhase 2measured
Different numbers for the same question on different runs
CauseA missing decision, made afresh on each run
FixAsk the question several times and compare the SQL; send each split to the conflict list
never writtenPhase 3measured
The agent silently picks one of several definitions in use
CauseA conflict nobody resolved
FixFlag the conflict instead of answering; resolve it by provenance, then the owner
never writtenPhase 2measured
A metric returns a total above the key, and its SQL looks clean
CauseThe metric encoded one team’s definition where the question has two owners (top 100 by deal count, not ARR)
FixRaise the conflict from the raw trace; both owners resolve it; version the metric
never writtenPhase 3diagnosis, not measured
A house rule is served as an instruction, and a governed answer still breaks it
CauseAn instruction never reaches SQL the harness runs as served
FixWrite the rule into the metric’s population and filters
never writtenPhase 3diagnosis, not measured
Totals are several times too large
CauseWrong grain: a deal counted once per contract term
FixState the grain; check that each key appears once when you test the metric against the warehouse
never writtenPhase 2diagnosis, not measured
Multi-table questions fail with a join graph or semantic views in place
CauseDeclared joins say what connects, never how the answer is assembled
FixServe a composed statement: a metric or a complete trusted past query
never writtenPhase 2measured
Every piece is served and a multi-step answer still fails
CauseThe state it needs does not exist in the warehouse, such as “created and still open”
FixPre-assemble it as a metric, or have the platform owner build the state; hold that kind of question back until then
never writtenPhase 3measured
Filters, joins and metric names are all in context, and the answer is still wrong
CauseThe parts were served as separate hints
FixServe whole decisions: population, grain, time rule and filters in one statement
never writtenPhase 2diagnosis, not measured
A large documentation effort barely moves the score
CauseDocumentation describes tables and carries no decisions
FixKeep it as the floor; spend the next hour on metrics
never writtenPhase 2measured
Generation yields hundreds of trivial “metrics”
CauseProfiling and scratch queries promoted to candidates
FixFilter candidates by provenance: distinct analysts, runs, recency
never writtenPhase 2diagnosis, not measured
Right on launch day, drifting within weeks
CauseDefinitions change and nothing feeds back
FixFeed traces and user corrections to the conflict list; rerun the golden set on every change
never writtenIn productiondiagnosis, not measured
Loading the whole context into the prompt lowers accuracy and raises cost
CauseDumping instead of retrieving
FixRetrieve per question from the context layer
written, not servedPhase 2measured
A written term or trusted query is never retrieved
CauseThe question’s word (“slipped”) appears in neither the query’s text nor its title
FixGive the business term its alternate labels and link it to the query
written, not servedPhase 3measured
Glossary definitions on columns add context and no accuracy
CauseBusiness terms served as column prose
FixUse business terms to route question words to the right metric or query
written, not servedPhase 2measured
The agent copies the start of a served query and improvises the rest
CauseSQL cut short to save tokens
FixServe complete statements, literals kept
written, not servedPhase 2measured
A second retriever on top of metrics adds nothing
CauseNear-variants compete with the metric
FixRank metrics above retrieved queries; never blend the lanes
written, not servedPhase 2measured
Wide dashboard objects cost questions
CauseThey crowd the decisive metric out
FixKeep metrics narrow and atomic; cap what is served per question
written, not servedPhase 2measured
Search recall improves and accuracy does not
CauseRecall counts candidates found; accuracy needs the decisive one served
FixMeasure answers against the golden set, never retrieval alone
written, not servedPhase 3measured
Column profiles bloat the prompt with no gain
CauseProfiling describes data shape and carries no decisions
FixLook up values only when a question names one
written, not servedPhase 2measured
Generic methodology or instruction packs add cost and no accuracy
CauseGeneric prose competes with domain rules
FixServe small, owned, domain-specific rules only
written, not servedPhase 2measured
Embedding search misses the query that shares the question’s field names
CauseEmbeddings blur identifiers and literals
FixRank on field names and literals first, provenance as the tie-break
written, not servedPhase 2measured
The agent answers from the wrong table
CauseTable choice fails before any SQL is written
FixServe one authoritative source per concept; put metrics on it
written, not servedPhase 2measured
A schema change silently breaks trusted queries
CauseNothing re-checks them when a table changes
FixRerun the regression set and re-test against the warehouse on every schema change; pull what fails
written, not servedIn productiondiagnosis, not measured
An ontology makes number questions slower and worse
CauseIt mirrored the schema, and it was used to write SQL when its job is to explain causes
FixMetrics for what, ontology for why; bind entities to metrics
written, not servedWhy-questionsmeasured
The metric was served and the agent ignored it
CauseContext that is only placed in front of the agent gets skipped
FixMake it a rule the agent must follow, or run the metric’s SQL as served
served, ignoredPhase 3measured
The metric is in context and still assembled wrong
CauseThe metric was served as prose
FixServe name and SQL
served, ignoredPhase 2measured
The agent retyped a served statement and broke it
CauseLong served SQL copied by hand
FixFill the declared parameters and run the served statement as stored
served, ignoredPhase 3diagnosis, not measured
The agent found the right value, kept exploring, and answered something else
CauseNo rule to stop
FixA rule the agent follows: a value from a query that matches the definition is the answer
served, ignoredPhase 3diagnosis, not measured
A governed question returns the wrong number from the right metric
CauseA parameter took a default, such as a calendar quarter for win rate
FixMake the time parameter required, with no default; check at the launch gate
served, ignoredPhase 3diagnosis, not measured
The governed lane says “no metric” on a question it should answer
CauseNo metric covers it, or retrieval missed it
FixCount wrong refusals next to correct ones at the launch gate; add the metric or fix the term link
written, not servedPhase 4diagnosis, not measured
A house rule served as an instruction breaks a question that passed
CauseThe rule caught more than it meant (a partner org the key counts)
FixRerun the whole set after every change; scope the rule to the field that defines it
never writtenPhase 3diagnosis, not measured
A high score nobody reproduces on a fresh set
CauseGolden-set SQL leaked into the context
FixPurge by hash; exclude the agent’s own queries from history; audit runs for leaks
key wrongPhase 1measured
A business term hands the agent the answer
CauseA term matches the expected answer’s label
FixServe a value term only when the question names that value
key wrongPhase 1diagnosis, not measured
Answers within tolerance are graded right while the logic is wrong
CauseGrading on data alone
FixGrade returned data first, then the SQL against the item’s decisions
key wrongPhase 1diagnosis, not measured
A question no change ever fixes, or one the agent gets right on every run and is graded wrong
CauseThe key itself is wrong (the grader used the calendar quarter)
FixAudit the key before tuning; the eval owner corrects and reseals it
key wrongPhase 3measured
An item passes on every run and the answer is still wrong
CauseThe key is wrong and the agent matched it
FixAt every gate, re-grade five random passes by hand against their source; correct in either direction
key wrongPhase 4diagnosis, not measured
A governed answer is wrong the same way on every run
CauseA wrong metric is wrong every time, for everyone; repeat runs can’t see it
FixTest every metric and have its owner approve it before it serves; keep a golden-set item per metric; run the random pass audit
never writtenPhase 2diagnosis, not measured
A one-run gain is announced as progress
CauseSingle runs vary by several questions
FixTreat gaps smaller than your run-to-run variation as unresolved; score items right on every run
key wrongPhase 3measured
A high overall score hides confident wrong answers on board numbers
CauseExploratory SQL is right most of the time and wrong the rest
FixPut exact recurring numbers in the governed lane: metric or no answer
key wrongPhase 0measured
Errored runs drag the average down
CauseHarness errors counted as wrong answers
FixReport errors separately; never average them in
budgetPhase 3diagnosis, not measured
A higher step budget turns refusals into wrong answers
CauseFreed refusals become guesses
FixFix the missing context before you touch the budget
budgetPhase 3measured
An exploration toolkit adds nothing
CauseMore discovery keeps the agent sampling instead of committing
FixFewer, stronger tools; one context call before any SQL
budgetPhase 0measured
The harness spends its step budget finding its tools
CauseA deferred-tool pattern in the harness
FixLoad the context tool up front; size the budget to the harness
budgetPhase 0diagnosis, not measured
Engagement failures
These rows come from our field engagements. Each maps to a Phase 0 decision or to a practice in running the engagement.
The weeks slip; decisions wait for one person
CauseThe domain owner can spare only minutes a week
FixNamed people, hours agreed with the owner’s manager and on calendars; provenance settles what it can
never writtenPhase 0diagnosis, not measured
The conflict list grows faster than the owner can resolve it
CauseEvery conflict treated as urgent and sent to a person
FixLet provenance settle the clear cases; bring the owner only the split ones, ranked by use; the rest wait in the backlog
never writtenPhase 2measured
A dispute settled while sealing surfaces weeks later in a trace
CauseThe wall between the key and the context hid the conflict along with the value
FixSend the dispute to the conflict list as well, with no sealed value attached
never writtenPhase 1diagnosis, not measured
A pasted list of IDs is set aside and nobody traces it
CauseA set-aside item is not a conflict, so it never reaches the owner
FixTrace every pasted list to its source before approving the concept it touches
never writtenPhase 2diagnosis, not measured
The sponsor asks “why did it drop?” before the agent gets the number right twice
CauseWhy-questions pulled forward
FixDefer why until the numbers are released; put the question in the backlog with a date
never writtenPhase 2diagnosis, not measured
Three domains in scope, and none reaches the bar
CauseGoing broad
FixOne domain, its problem and its users; domain two starts from what domain one built
never writtenPhase 0diagnosis, not measured
A governance steward attends every review and nothing gets decided
CauseGovernance stands in for the domain owner
FixDecisions come from the definition’s owner
never writtenPhase 0diagnosis, not measured
Every answer must be exact, judged against a dashboard
CauseThe use case is a dashboard
FixExact recurring numbers go through the governed lane, or stay on the dashboard
never writtenPhase 0diagnosis, not measured
The company cannot run a round of fixes without the delivery team
CauseThe loop was run for them; the handover was a document
FixOne pass together, one alone, before the delivery team leaves
never writtenPhase 4diagnosis, not measured
Two domains own the same word and disagree, and nobody can decide
CauseNo one decides across domains
FixThe sponsor names an arbiter before domain two’s Phase 0 ends
never writtenPhase 4diagnosis, not measured
High pilot accuracy fails the first real user
CauseThe test set came from the tuning examples
FixBuild the golden set from real questions, seal it, hold some back
key wrongPhase 1diagnosis, not measured
The golden set is still being written in Phase 3
CauseDrafted from scratch
FixStart from verified dashboards, reports and analyst work; seal 20 in Phase 1
key wrongPhase 1diagnosis, not measured
Every miss becomes a question for the delivery team
CauseNobody on the company’s side owns correctness
FixThe eval owner and graders own the golden set; the domain owner settles definitions
key wrongPhase 0diagnosis, not measured
The sponsor rejects a result the team celebrated
CauseThe bar was never written down
FixSet the bar in Phase 0, before any result exists
key wrongPhase 0diagnosis, not measured
Phase 3 starts with no traces to read
CauseTrace export arrived last
FixTest one trace end to end, per call, before Phase 1
budgetPhase 0diagnosis, not measured
The clock starts, then stops for a data-handling review
CauseSecurity was approached late
FixWalk security through what leaves the building in Phase 0
budgetPhase 0diagnosis, not measured
Score changes cannot be traced to any context change
CauseThe harness or model changed and the baseline was not rerun
FixRerun the golden set on any harness or model change before comparing
budgetPhase 3diagnosis, not measured
The agent is rebuilt after launch for a different surface
CauseThe surface was decided late
FixChoose the agent architecture in Phase 0
budgetPhase 0diagnosis, not measured
The engagement ships custom code nobody can maintain
CauseDelivery built one-off tooling
FixLeave metrics, the golden set, the decisions log and the iteration ledger
budgetPhase 4diagnosis, not measured
The company asks the delivery team to run the agent
CauseHarness ownership was never made explicit
FixSettle it in Phase 0: the harness is the company’s
budgetPhase 0diagnosis, not measured
When a miss will not sort cleanly
Sometimes a miss will not sort into one branch of Why did this miss?. These checks find where the remaining gap lives. Run the first one before the others, because it needs no golden set.
Check
How
What it tells you
Ask it several times
Run the same question with everything fixed and compare the SQL
Where the runs split, two definitions compete; resolve it as a conflict
Serve one source at a time
Serve a single kind of context per run
What each kind of context is worth
Serve the answer as prose
Give the agent its own procedure in words
If accuracy does not move, the gap was never knowledge; serve SQL or a rule
Count the steps
Compare the steps the expected SQL needs with the steps the agent built
Whether the miss is assembly; pre-build it as a metric or a table
The last three need the golden set to score. The eval owner runs the scoring, and the context engineer sees only the verdicts.
Research and reference
R2
Glossary
One word, one meaning. Where a chapter disagrees with the glossary, the glossary wins and the chapter gets fixed.
Read 8 min
Every term names part of the method.
Agent architecture. The four parts of an analytics agent: the surface where people ask, the harness that runs the loop, the model, and the context it reads before writing SQL. It is either platform-native, such as Databricks Genie or Snowflake CoWork (formerly Snowflake Intelligence), or custom, built on a framework such as Google ADK or LangGraph.
Agent builder. The company’s engineer who builds and runs the harness, exports traces and runs every eval, baseline, round and gate.
Answer key. See golden set.
As-of date. The fixed snapshot every expected answer is computed at, such as a fiscal year-end. The harness passes it on every eval run, so sealed answers stay reproducible.
Bare schema. The agent with the warehouse schema and nothing else: no descriptions, past queries, metrics or rules. It is the benchmark’s floor, and the Phase 1 baseline for a domain with no context yet.
Baseline. The first scored run, at the end of Phase 1: the agent on bare schema, or on its existing context, once per sealed question. It prices the decisions your schema leaves out.
Business changes. A dated record of what changed in the business, such as a territory realignment or a pricing change, tied to ontology entities so the agent can test them as causes. It is the part of the why-question context that decays first.
Business term. A word the business uses, defined once, with its alternate labels, and linked to the metric, query or entity it names. Its main job is retrieval: “slipped” finds a query about deals “pushed” past quarter end. Internal names such as project and product names belong here.
Card. A one-page checklist you can print. Most cards close a chapter, and all are collected in Cards. Cards are called by their titles.
Clock. The build, Phases 1 to 4. It starts once Phase 0’s gate is met, so Phase 0 runs before the clock.
Conflict. Two definitions of the same thing, both in use, such as two rankings of “top 100 customers”. The agent flags a conflict instead of picking a side. It is resolved by provenance or by the domain owner.
Conflict record. The record of a resolved conflict: the variants, their provenance, the decision, who made it, what changed and what would reopen it. Kept on its template.
Context. Everything the agent is given besides the question: the schema, metrics, trusted past queries, rules, business terms and, for why-questions, the ontology.
Context call. The one call the harness makes per question, before any SQL, to fetch the context that applies. Its shape is fixed before the baseline so later scores compare.
Context engineer. The person running the engagement, from a partner or your own team (in-house: an analytics engineer), who generates candidates, reads traces and runs the hill climb. Never sees an expected answer.
Context layer. The governed store of context that sits under any agent and serves it per question.
Decoy. The wrong answer you get when the choices a question hides are guessed the obvious way, recorded on the golden-set item. For the pipeline question it is $1.31B.
Definition of done. The checklist that closes a chapter’s phase, checked item by item.
Delivery lead. The person who runs the engagement phase by phase, from the kickoff to the handover: sessions, gates and readouts.
Domain. One business area with its own questions, users, tables and owner, such as sales pipeline. The method runs one domain at a time.
Domain owner. The company’s person who owns the business definitions in a domain. Signs off the golden set, decides the conflicts provenance cannot settle, and approves every context change. A definition that crosses teams has a co-owner, as the FP&A partner co-owns “top 100 customers”.
Drift. The slow loss of accuracy as the business changes and the context does not. Traces, user corrections and repeated runs feed it back.
Eval owner. The one named person who drafts and seals the golden set with the graders, and grades every run. The sponsor accepts the eval owner’s verdicts.
Exec sponsor. The executive who sets the bar, chooses the domain and the agent architecture, and decides at each gate and at launch.
Exploratory lane. Long-tail and diagnostic questions, answered by SQL the agent writes, grounded in trusted past queries. The bar is one pass rate the sponsor sets before any result, and every answer shows its SQL and sources.
Gate. The checkable condition that ends each step: Phase 0 (brief agreed, access proved), Phase 1 (20 or more sealed, baseline scored), Phase 2 (metrics scored), Phase 3 (misses closed, set grown to 50) and the launch gate in Phase 4.
Generate metrics. Phase 2’s core task: a metrics agent reads past SQL, BI reports and semantic models, and proposes candidate metrics with the real queries behind them. Candidates are then witnessed, conflicts resolved, and the survivors approved by their owner.
Golden set. The sealed questions with expected answers, expected SQL and a grading method, built from questions the business already asks: at least 20 in Phase 1, 50 by the launch gate. Also called an answer key.
Governed lane. The numbers the business runs on. They come only from a metric, run as served, and the lane fails loudly: no metric, no answer. The bar is exact, on every run.
Grain. What one row represents before aggregation, such as one row per customer. Most inflated totals are grain errors.
Harness. The agent runtime around the model: its loop, tools, prompts and step budget. It belongs to the company, which builds it, runs it and owns it.
Hill climb. Phase 3’s loop: run the golden set, read the raw trace of each miss, classify it, make the smallest fix, and rerun. “Hill climb” is the noun; “hill-climb” is the verb.
House rule. A rule that holds for every question in the domain, such as “quarter means fiscal quarter”. Serve it as a rule, and write it into every metric it touches, because an instruction never reaches SQL the harness runs as served.
Iteration ledger. The record of every round: what changed, the fixes predicted before the run, the score, and whether the change was kept.
Launch gate. The Phase 4 test on the golden set grown to 50: governed questions right on every run, exploratory at their pass rate, nothing that passed has broken, and the random pass audit done. The sponsor decides go, no-go or go with conditions.
LLM judge. A model that grades what code cannot, such as whether an answer states its period, filter and unit. It never grades the number itself when code can, and it counts only once calibrated against human graders.
Metric. A business number as one executable SQL statement: population, grain, time rule, formula, exclusions and filters, with its provenance. It is versioned like code. In the method, its owner signs it off. In the benchmark, no person approved the metrics.
Metrics agent. Any model-driven script that reads past SQL, BI reports and semantic models and drafts candidate metrics, each cut from a real statement.
Metrics layer. The benchmark setup the book ships: metrics served as SQL, plus trusted past queries, retrieved per question. What we found scores it against bare schema.
Ontology. The business as a graph: entities, relationships and vocabulary, each bound to its tables and metrics. It serves why-questions; metrics serve the numbers.
Provenance. The evidence behind a query or metric: who ran it, how many different people, how often, how recently, and whether it runs clean and matches the warehouse. Provenance settles most conflicts without a meeting, and it is served with every metric.
Random pass audit. At every gate, the eval owner re-grades five passing items, chosen at random, by hand against their source. A key found wrong is corrected in either direction, and the score is reported after the correction.
Refusal. The governed lane’s answer when no metric covers the question: it says so, with no number. Correct on an out-of-scope question, and a miss on an in-scope one. On the benchmark every refusal counts as a miss.
Regression set. The golden-set questions the agent already answers right on every run, rerun on every context change and every schema change.
Resolve a conflict. Settle which of two definitions is right. Provenance decides first; the domain owner decides the rest, with a co-owner when a definition crosses teams. The decision is written into the metric as SQL.
Round. One small batch of context changes, followed by a rerun of the whole golden set, recorded as one row of the iteration ledger.
Rule. A small, owned, versioned instruction the agent must follow, such as quarter-means-fiscal or “regions roll up to NA, EMEA and APAC”. Also called a skill. A rule that touches one metric goes inside that metric; a rule that touches many stays a rule.
Run-to-run variation. How far the score moves between identical runs of an unchanged configuration. A change whose effect sits inside it is unresolved. Measure your own before the first round.
Seal. A golden-set item is sealed when its expected SQL has run read-only on the snapshot, the result matches the trusted source, no dispute is open, and the eval owner has signed it. Sealed items are versioned and never edited to make the agent pass.
Semantic layer. Metric and join definitions kept in a tool, so every query reuses them. Snowflake semantic views, Databricks metric views, LookML and dbt MetricFlow are all semantic layers. In Phase 2 you treat yours as a source, like past SQL. See Why a metric, and not a view.
Step budget. A fixed cap on tool calls per question. Ten is a sound default. Raising it tends to turn refusals into wrong answers.
Stop rule. Stop the hill climb when two rounds in a row move the total by no more than the run-to-run variation and none of the predicted fixes lands. Cap Phase 3 at five rounds. If the bar is not cleared by then, take the gap to the sponsor.
Trace. The full record of one agent run: every context call, what was served, every SQL statement, the answer, tokens and time.
Trusted past query. A complete, real analyst SQL statement, literals kept, served as a worked example with its provenance. It grounds the exploratory lane.
Version. An approved, numbered release of a context object or of a domain’s context, with a diff and a one-step rollback.
Witness. Running a candidate metric or query read-only against the warehouse to prove it runs, returns sane values and has the grain it claims.
Research and reference
R3
Tooling and sources
The method runs by hand. Tooling changes the upkeep, never who decides.
Read 5 min
This page holds how to run every step on your own stack, the context-call contract, the external sources behind the book, and how the book itself changes.
Running it on your own stack
Keep one file per context object in version control, in the formats of the templates, with the domain owner as required approver. Generate and witness candidates under a read-only identity with a script, keep conflicts in a spreadsheet with each variant’s provenance, and give the harness a retrieval function it calls before any SQL. Log every call with what was served and its version. Grade with a value-matching script, then read the SQL of every item that passes. Keep the iteration ledger in a shared sheet, tag each release with its eval results, and rerun the regression set on every context change and schema change. The method, the gates and the owners are the same either way.
The context-call contract
This is the shape between a harness and a context layer, whoever builds either side. It is a design we have not benchmarked. The builder's minimum harness puts a harness around it, and the templates have a filled example.
In · one call before any SQL
question textthe user's words, unedited
domainwhich domain's layer to search
user identitypassed through; SQL runs under the user's or a scoped identity's permissions
trusted past queriestop-k matches, each as complete SQL with its provenance
rulesthe ones that apply to this question, as instructions
business termsthe terms the question matched
lanegoverned when a metric covers the class; otherwise exploratory
every call traced: each served item by ID and version governed hint + no matching metric = no answer
Figure R3.1
One call per question, before any SQL. The shape stays fixed from the baseline on, so the scores compare.
The call goes in with the question text unedited, the domain to search, and the user’s identity, passed through. It comes back with metrics (name, version, complete SQL, owner, provenance), the top trusted past queries as complete SQL, the rules that apply, the business terms the question matched, and which lane the question falls in. On a governed question with no matching metric, the harness refuses: no metric, no answer. When a metric answers, the harness runs its SQL as served, filling only declared parameters. The case for that is consistency: the same number on every run, and no long statement broken in the retyping.
Sources
Every external source the book draws on. Any number quoted is the source’s own.
An in-house data agent graded on 1,900 contributed questions across 19 business areas. Harness and context work mattered more than the model. Graded by a model judge, not by code. Checked 2026-10-02.
A public benchmark for data agents that reports cost, tokens and latency beside each score, and publishes example tasks with their grades. A pattern for showing results. Checked 2026-10-02.
A metric view is rooted on one source table and can join several levels deep; a Genie Agent (formerly a Genie space) holds up to 50 tables, views or metric views. Checked 2026-10-27.
Where each puts the metric: in a source; in a cube that reaches other cubes over multi-hop joins; in a dataset or beside datasets in one model. Checked 2026-10-27.
Blameless postmortems with an explicit trigger list.
Contributing
The playbook is versioned like the context it describes. Published by Atlan. Maintained by the playbook maintainers, who approve every merge and keep the source evidence current.
How to propose a change
Open a pull request against the chapter file in chapters/, one topic each.
Source every number. An internal benchmark number names its ledger arm, n and run date. A field result is anonymised and says so. An external claim carries its URL. The maintainers assign evidence IDs; contributors never mint one.
Keep to the method. A new phase, framework or practice needs a source: our own work, or an external guide cited with an X-ID and labelled external.
Keep the conventions. Chapter shape, callouts and roles follow the authoring guide, and the glossary is the vocabulary. All SQL runs on DuckDB.
Keep the invariants. No customer, system or people names. The company owns and runs the harness and the model. No page carries product status labels.
Keep the method map in step. The map on the lifecycle page restates each phase’s steps, owners, templates and cards in short form. If your change renames, adds, removes or reorders any of them, or changes a section the map links to, update diagrams/method-map.html in the same pull request. The build checks the map’s links, not its words, so a stale map still passes.
Rebuild with python3 build.py --check, read the changed chapter, and add a line to CHANGELOG.md in the repository.
Report a field result that contradicts the playbook the same way, with its evidence. Negative results are as welcome as positive ones.
Research and reference
Semantic layers compared
The useful test for any layer is how far a metric can reach.
Read 2 min
Why a metric, and not a view makes the case for organizing context around the metric. This page is the reference behind it: how far a metric reaches in each of today’s tools, and one model written in six syntaxes so you can see where the metric lives in each.
WatchSemantic views or metrics?2:36Read the transcript
The narration says "certified metrics", and the guide says "metrics": in the benchmark, no person approved the metrics. In the method, each metric's owner signs it off.
Give an agent semantic views as its only way in... and it scores 38.3% on our 107 questions. Now compare. The bare schema, with no context at all? 31.8%. Certified metrics, with their SQL? 83.2%. So, semantic views or metrics? In other words, how should an agent's context be organized?
Start with your gold layer. It carries technical names. But it says nothing about joins, formulas or dimensions. So what fills it? A semantic layer... it fills that gap. It's got four parts... what the tables mean, how they join, the metrics, and the dimensions.
You can lay that context out three ways... and each one repeats something. First, per table, like a data dictionary. The joins and cross-table metrics get copied. Second, per logical table, like a semantic view. Now meanings, joins and metrics get copied across views. Or third, per metric. The metric's stored once... and only joins and dimensions repeat.
Here's an illustrative case. Average order value lives in three views... orders, customers and stores. And each one defines it differently. Gross, or net of refunds. Per order, or per customer. So ask the agent, what was AOV last quarter? It can't tell which one to use.
For an agent, those copies are the first cost of views. And there are two more. Second, every question has to pick a view before it can start. Third, fixes land beside the view, as text... and the agent reinterprets them on every question.
So what's the alternative? Make the metric the unit. It's defined once, with its formula, verified SQL, joins and dimensions. And it compiles to the same SQL every time. The business can read it, and correct it... and the fix lands in the definition.
You don't have to replatform. Keep your views. Certified metrics sit beside them... and reach the agent in one context call, per question.
How do you test any layer? Ask it five questions. Here they are.
So that's the gap from the start. Views make the agent pick a copy... metrics give it one definition. Here's the rule. Organize context around the metric, the unit the business asks in. Next, Phase 0, before the clock... picking one domain, and the people who own its numbers.
How today’s tools compare
Every tool reviewed can join across tables. What differs is where the metric is defined and what bounds it. LookML, Malloy and Cube define a measure in one view, source or cube, and reach other tables through its joins. Snowflake semantic views, Databricks metric views, Apache Ossie (formerly OSI) and Genie hold metrics inside one view, model or agent. dbt MetricFlow can define a ratio metric at the top level of the project, from metrics in different semantic models, with entities as the join keys.
Figure
Where each tool defines a metric and what bounds it, from public documentation checked on 27 October 2026.
Tool
Where the metric is defined
What bounds it
Looker (LookML)
In a view, one per table
The explore it is queried through
Malloy
In a source
The source and its joins
Cube
In a cube, usually one per table
The data model’s joins, across several hops
Databricks metric views
In the view, rooted on one source table
The metric view; joins can run several levels deep
Databricks Genie
In a Genie Agent (formerly a Genie space)
The agent, up to 50 tables, views or metric views
Snowflake semantic views
Per logical table; derived metrics at view level
The view
Apache Ossie
In a dataset, or at model level beside the datasets
The model
dbt MetricFlow
Simple metrics on a semantic model; ratio and derived metrics at the top level
The join graph
None of these ties verified SQL to an individual metric. Snowflake semantic views and Genie Agents keep verified or example SQL for the whole view or agent. The metric spec template keeps a metric’s formula, named joins, dimensions and verified SQL together as one unit. We measured the SQL part of that; the rest is design.
Figure
Feedback that lands in the model compiles the same way every time. Feedback kept beside it is text the agent has to reinterpret, and the pile grows with every fix.
One model in six syntaxes
Each snippet defines orders joined to customers, a revenue metric and a region dimension, adapted from each vendor’s documentation and not run. Watch where the metric lives. Product names are their owners’ trademarks; the comparison is drawn from public documentation on the date stated and is not an endorsement.
Snowflake semantic view. The metric is named per table; only the derived metric sits at view level.
sql
CREATE SEMANTIC VIEW sales_sv
TABLES (
orders AS db.sch.orders PRIMARY KEY (order_id),
customers AS db.sch.customers PRIMARY KEY (customer_id)
)
RELATIONSHIPS (
orders_to_customers AS orders (customer_id) REFERENCES customers
)
FACTS ( orders.order_amount AS amount )
DIMENSIONS ( customers.region AS customers.region )
METRICS (
orders.total_revenue ASSUM(orders.order_amount),
customers.customer_count ASCOUNT(customers.customer_id),
revenue_per_customer AS orders.total_revenue / customers.customer_count
);
Databricks metric view. Everything is rooted on one source table; joins can run several levels deep.
yaml
version: 1.1
source: main.sales.orders
joins:
- name: customers
source: main.sales.customers
on: source.customer_id = customers.customer_id
fields:
- name: Region
expr: customers.region
measures:
- name: Total Revenue
expr: SUM(amount)
LookML. Measures live in the view, joins in the explore, and drill paths hang off the measure.