Get started

Engineering NotesStructured data and NL2SQL

Revenue differs by team, so questions carry the approved definition

Ask for "last month's revenue" and sales thinks of booked orders, while finance thinks of invoiced amounts net of returns. The revenue ledger has the columns for both calculations, so whichever one the model writes, the SQL runs without an error, and sometimes it produces a third number that matches neither. Which calculation counts as this company's revenue is something the organization decided. It is not written in the DDL, in the column comments or in the table cards that analysis builds.

So we keep business definitions in the organization glossary, together with their formulas and linked tables, and when a term appears in a question, only that entry goes right before the question. The only definitions that reach the glossary are ones an administrator approved. This post covers what a glossary entry holds, how terms are found in a question and loaded, and who decides the definitions.

The definition of revenue is an organizational decision, not data

Schema analysis in “DDL doesn't say what a column means, so we read its values first” reads a column's meaning from its actual values. Whether AMT is the supply price net of VAT, or whether C in STATUS_CODE means canceled, can be settled by looking at value distributions and code tables. Revenue is different. "Invoiced amount minus returns, minus intercompany transactions" combines several columns and conditions, and that combination came out of the meeting that set the basis for management reporting. No amount of looking at values reveals that intercompany transactions should be excluded.

"Active customer," "new account" and "utilization rate" work the same way. One name, slightly different formulas in each department, and the definition usually lives in a report footnote or in someone's head. Without it, the model picks a column that looks like revenue and sums it. The result even comes out as a tidy table, so only someone who knows the definition can tell it's wrong.

What happens if you load the whole glossary or leave it to table notes

The simplest approach is to attach the whole glossary to the system prompt. With a few dozen terms, that works. With hundreds, only a handful relate to any one question, and the other formulas pull the model toward the wrong tables. Ask about "revenue" with the formula for "receivables turnover" loaded alongside, and the model finds a reason to open the receivables table too. There is also a cost every time an administrator edits a term: the system prompt changes, and every user's prompt cache has to be recomputed (“One system prompt edit zeroes cache reads, so changing blocks go last”).

The other approach is to leave it to table notes. A table note is a shared record the model attaches to a table when a user mentions a fact during a conversation, and it goes into the answers of everyone who uses that table as a hint (“Wrong-table SQL still runs, so search narrows the candidates first”). Notes accumulate quickly, but nobody approves them. If a sales rep's conversation leaves "revenue is booked orders" and a finance analyst's leaves "revenue is invoiced amount minus returns" on the same table, the model has to pick one and has no way to know which is the organization's standard.

A definition needs someone who set it and a scope it applies to. So we keep business definitions apart from notes, and load only approved entries, only when a question mentions them.

A glossary entry holds the definition, the formula and the linked tables

Meetings, data questions and document generation share one organization glossary. It is the glossary meeting minutes already used to get proper nouns right (“Transcripts misspell internal names; the minutes model fixes them”), with fields added for data questions, because "net revenue" can't mean one thing in the minutes and another in a chat answer at the same company. An entry has these fields.

Field What it holds Used by
Term "net revenue" All
Definition One or two sentences for people to read All
Synonyms and abbreviations Other names for the same concept ("NS," "revenue net of returns") Data questions, documents
Formula An SQL fragment (SUM(ISSUE_AMT) - SUM(RETURN_AMT)) or a sentence ("customers with at least one order in the last 90 days") Data questions, documents
Linked tables A list of locations: database connection, table, column. One term can span several tables in several databases Data questions
Misheard forms Spellings the transcription gets wrong Meeting minutes

Synonyms and misheard forms are separate fields. A synonym is a correct name people actually use; a misheard form is how speech recognition gets it wrong. Mix them, and the minutes treat "NS" as a typo and rewrite it as "net revenue."

When departments really do count differently, split the term and define each one. Keep "booked revenue" and "invoiced revenue" as separate entries, and write in the definition of "revenue," the term used in management reporting, which of the two it means. A glossary holds only one entry per spelling, so "revenue" can't carry two meanings at once.

Only the terms in the question are loaded, right before the question

When a turn starts, the turn runner looks for the glossary's terms and synonyms in the user's question. A turn is one round of question and answer, from receiving a question to producing its answer. The lookup is a string match. The leading boundary is strict, so "net revenue" inside a longer word doesn't count. For terms ending in Hangul the trailing boundary stays open, so forms with Korean particles attached, such as "순매출을" and "순매출은" ("net revenue" plus a particle), count as the same term. At the same position the longer term wins, so asking about "net revenue" doesn't also load the "revenue" entry. Differences in letter case and whitespace are ignored.

The matched entries, with their definitions, formulas and linked tables, are bundled into one glossary block placed in the user message right before the question. Because the content changes with every question, it sits on the user message side rather than in the system prompt, so the cached beginning of the system prompt stays the same even when the glossary changes. The number of entries per turn is capped, and the number dropped by the cap is logged.

Only the terms in the question go before it as a glossary block
Figure 1. Only the terms in the question go before it as a glossary block

Linked tables go through permissions too. A table the user's role can't see is dropped from the block's list even when the term points to it, and only the definition and formula are loaded. When a table disappears from the source database or the connection account can no longer see it (“Schema analysis goes stale, so only changed tables get reanalyzed”), the link is not deleted. It is marked inactive, the glossary screen shows "linked table unavailable," and an administrator can see that the definition still stands while the data it points to is gone, and fix it.

Meeting minutes use the same string match differently. The minutes load as hints only the misheard forms actually found in the transcript, and they load every term and definition in the glossary into the system prompt (“Transcripts misspell internal names; the minutes model fixes them”). A transcript can misspell any term in a form nobody has registered yet, so strings can't be used to pick entries in advance. A chat question is text a person typed, so terms usually appear in their correct spelling, and that is what makes it possible to load only the entries the question mentions.

The model fits the formula to the actual columns on the table card

The formula doesn't write the SQL. SUM(ISSUE_AMT) - SUM(RETURN_AMT) names columns, but which table holds them and which date column the period condition goes on differ from question to question. So the model opens the table cards (“DDL doesn't say what a column means, so we read its values first”) for the linked tables in the block, checks the columns and works the formula into SQL. With linked tables in hand it can open the cards directly without going through table search (“Wrong-table SQL still runs, so search narrows the candidates first”), so even a table whose card never mentions "net revenue" is reached in the first round. If a column the formula refers to isn't on the card, the model doesn't guess another column; it says so in the answer. The resulting SQL goes through the same read-only execution tool as any other (“Read-only and query cancellation have to reach the database server”).

When the glossary and a table note say different things about the same term, the system prompt tells the model to follow the glossary. The glossary holds definitions the organization approved; a note is a field record loaded as a hint to verify.

The answer shows which definition was used. If the "revenue" entry reads "Management reporting basis: invoiced amount minus returns and intercompany transactions," the model says the number was counted on that basis. A sales rep who wanted booked orders sees the difference as soon as they read the answer and can ask again for "booked revenue."

Administrators approve organization definitions; definitions from a conversation stop at the person's own glossary

Administrators edit the organization glossary. One revenue definition goes into every data answer in the organization, so we gave it different permissions from table notes, which anyone can edit. Entries an administrator adds directly take effect right away, and every addition, edit and deletion is recorded in the organization's audit log.

AI can also find candidates. When an administrator picks the organization's document collections and database analysis results in Find terms with AI, the AI extracts term candidates from that material and puts them on the review list. A candidate isn't a term in use, so it doesn't go into prompts until an administrator edits and approves it into the glossary.

Most definitions first come up in conversation. When a user says "we count an active customer as one who ordered in the last 90 days," the model proposes a candidate with the term, definition, formula and linked tables. The candidate goes not to the organization's review list but to the speaker's personal glossary review list. A conversation is a record only its owner sees, and administrators don't open other people's conversations. Putting a definition taken from a conversation on the organization's list would show fragments of that conversation to others. A personal entry the person approved is loaded only into their own questions; if the definition should become the team's standard, an administrator registers it in the organization glossary.

When the organization glossary and a personal glossary have the same spelling, data questions use the organization entry. Personal entries fill in only spellings the organization glossary doesn't have. Meeting minutes do the opposite and use the meeting owner's personal entry first (“Transcripts misspell internal names; the minutes model fixes them”): minutes are that person's record, while a revenue figure ends up in reports that several people check against each other. Whoever asks, "revenue" is counted the same way.

Design choices

Terms are found by string match. Finding entries by embedding similarity would catch questions phrased in words the glossary doesn't have, such as "revenue minus returns" for "net revenue." But similar yet different entries ("return rate") could come along too, and which entries load for the same question would depend on thresholds and model versions. A definition has to load the same entry for the same words every time, so we chose string matching. Expressions that refer to the same concept in other words are caught once they're added to the synonyms field, and table search and table notes cover everything else.

Leaving the trailing boundary open has a cost. "매출채권" (accounts receivable) is a compound, not "revenue" plus a particle, yet it matches "매출" (revenue). Splitting boundaries by a list of particles produces endless edge cases between endings and compounds, so this case is handled by registering "accounts receivable" as its own term. The longer term wins at the same position, so once it is registered, asking about accounts receivable no longer loads the "revenue" entry.

The glossary goes through approval. It is where the organization's official definitions live, so we chose accuracy over speed. The cost is that a good definition one person found applies only to that person's questions until an administrator registers it. Field knowledge that has to work in the conversation right away belongs in table notes, which load only as hints.

If your organization counts different numbers under the same name in each department, start by picking a few metrics used in management reporting and registering them with their formulas and linked tables, and split any term whose basis varies into separately named entries. People register the definitions; the turn runner loads them into every question that mentions them.