learn-ai-infra-with-phoebe / Practitioner session 6 of 10
Learn AI Infra with Phoebe · Practitioner track · Session 6 of 10

One metric, defined once

This is the layer where your organization decides what "revenue" means. Right now it probably decides four times: once in the BI tool, once in somebody's notebook, once in a spreadsheet that finance actually trusts, and once inside a feature pipeline nobody has opened in a year. Tonight you learn what a semantic layer really sells, why the hard part is the join graph rather than the YAML, and what it does to your bill - because it is a compiler, not a storage layer, and it does not make the warehouse cheaper.

🟠 Practitioner track Platform · DE · architects Vendor-neutral · real rate cards 45 min
0-3 · Welcome 3-18 · Metric truth as a chokepoint 18-42 · Build-along: the analyst's surface 42-45 · Q&A
Part 1 · covers the dbt Semantic Layer and MetricFlow documentation

Metric truth as a chokepoint 7 min live

The job of this layer is embarrassingly narrow and enormously consequential: hold the definition of every business metric in one place, and serve it to everything that asks. Without it, definitions get re-implemented inside every BI tool, every notebook, every spreadsheet and every feature pipeline that needs them. The visible symptom is two dashboards disagreeing on revenue. The real problem is that nobody can adjudicate, because there is no artifact to point at.

Defined once, served everywhere Re-implemented in every tool revenue one YAML metric BI dashboard $4.21M Notebook $4.21M Spreadsheet $4.21M AI agent $4.21M SQL in the BI tool Notebook pandas code Spreadsheet formula Feature pipeline SQL $4.21M own logic $3.98M own logic $4.40M own logic $3.86M own logic One artifact to point at when people disagree. Four answers, and nothing to adjudicate between them.
🔍 Click to zoom - the same metric, defined once versus defined four times
LiveThe proposition, stated plainly3 min▶

Define the metric once in version-controlled code, and serve it everywhere through an API. That is the entire pitch, and it is a good one - it moves metric truth out of tool configuration, where it is invisible and unreviewable, into a repository where it gets a diff, a reviewer and a history.

The dbt Semantic Layer, built on MetricFlow, serves that definition over JDBC, GraphQL, a Python SDK, and a dbt MCP server. Note the last one: the same definitions that feed a dashboard also feed an agent. Hold that thought - it is the whole argument of Part 4.

The vocabulary is worth learning exactly, because every competing product uses some variant of it:

  • Semantic models - the mapping from your physical tables into the layer.
  • Entities - "the join keys of your semantic model."
  • Dimensions - "the ways you want to group or slice/dice your metrics."
  • Measures - the raw aggregatable columns.
  • Metrics - what the business actually asks for, built from measures.
LiveMost "our numbers disagree" fights are not definition fights4 min▶

This is the most useful sentence in dbt's own FAQ, and it will save you months of pointless meetings:

From dbt's Semantic Layer FAQ "If the underlying metric aggregation is different, then these would be different metrics. However, if teams have different definitions because they're using specific filters or dimensions, it's still the same metric."

Read the diagnostic out of it. When two teams report different revenue, there are only two possibilities, and they need completely different responses:

  • Different aggregation - one team sums gross, the other sums net of refunds. These are genuinely two metrics and should be named as two metrics. This is rare.
  • Same aggregation, different filter or grain - one team excludes internal test accounts, one reports on order date and the other on ship date, one is in the reporting currency and one is not. This is the same metric, sliced differently. This is almost always what is happening.
Two teams, two numbers - and only one of the two causes is a definition problem Two teams report different revenue Is the underlying aggregation different? yes no Genuinely two metrics one sums gross, the other net of refunds. Name them as two. This is rare. The same metric, sliced test accounts excluded, order date vs ship date, currency conversion. Filter and grain, almost always. From dbt's own Semantic Layer FAQ. Diagnose which one you have before you act. Treat every disagreement as a definition problem and you get forty near-identical metrics.
🔍 Click to zoom - filters and grain look like definition fights and are not

The practical consequence: most "our numbers disagree" fights are filter and grain disputes, not definition disputes. A semantic layer helps enormously with the second kind, because filters and grain become explicit parameters on a shared definition rather than invisible choices buried in someone's WHERE clause. But it only helps if you diagnose correctly first. Teams that treat every disagreement as a definition problem end up with forty near-identical metrics and are worse off than when they started.

Self-studyWhat the layer looks like in code3 min read▶

Shape only - the point is which blocks exist, not the exact syntax of any one version:

semantic_model:
  name: orders
  entities:
    - name: order_id      # primary -> the grain of this model
    - name: customer_id   # foreign -> how it joins to customers
  dimensions:
    - name: ordered_at    # the ways you slice the metric
    - name: sales_region
  measures:
    - name: order_total   # the raw aggregatable column

metric:
  name: revenue           # defined once, served everywhere
  type: simple
  measure: order_total

Nothing here is difficult. That is exactly why the layer gets underestimated - the YAML is the easy half, and Part 2 is about the half that is not.

Part 2 · covers MetricFlow's join resolution and dbt's published trade-offs

The real product is the join graph 8 min live

If you take one thing from this session, take this. A semantic layer is not a place to store metric definitions. It is a query compiler that knows the shape of your data model, and its hardest job is deciding how to join tables without silently corrupting the number it returns. MetricFlow, in its own documentation, "captures the types of each identifier and then helps users navigate to appropriate joins. This allows us to avoid the construction of fan out and chasm joins as well as generate legible SQL."

LiveWhat a fan-out join does to your revenue number4 min▶

Take an orders table with one row per order, carrying an order total. Take a line-items table with one row per product in that order. Join them so an analyst can slice revenue by product category, then sum the order total.

An order with three line items now contributes its total three times. The SQL is valid. The query runs. The dashboard renders. The number is wrong by however many line items the average order carries, and it is wrong in a way that scales with your business, which means it looks like growth.

That is a fan-out join. A chasm join is its cousin: two independent one-to-many relationships hanging off one table, multiplied against each other. Both produce plausible, confident, wrong numbers - the same failure signature you will meet again in b9.

One order, three line items, the total counted three times ORDERS · 1 ROW PER ORDER LINE_ITEMS · 1 ROW PER PRODUCT JOINED, THEN SUMMED order_1 · order_total order_1 · product A order_1 · product B order_1 · product C product A · order_total product B · order_total product C · order_total SUM(order_total) = 3 × order_total valid SQL, wrong number A chasm join is its cousin: two independent one-to-many paths multiplied together. It is wrong in proportion to your average order size, so it looks like growth. Do not ask how metrics are defined. Ask how the join path is resolved.
🔍 Click to zoom - the query runs, the dashboard renders, the number scales with your business
★ The line to remember A naive metrics layer silently double-counts on one-to-many joins. Students who learn only "define metrics in YAML" have missed the difficult part. When you evaluate any product in this category, do not ask how metrics are defined - ask how the join path is resolved, and what happens when two measures live at different grains.
LiveIt is a compiler, not a storage layer4 min▶

The second thing that surprises buyers. MetricFlow generates SQL at query time. Nothing is precomputed by default - dbt says so directly: "you're not materializing any data by default."

So the semantic layer does not save warehouse spend. Every query still hits the engine, and now it hits the engine with generated SQL rather than hand-written SQL. What the layer actually does to your cost structure is move it: from human duplication to machine compute plus a licence fee. That is very often a good trade, because the human duplication was costing you reconciliation meetings, wrong decisions and analyst attrition. But it is a trade, and a finance stakeholder who was told "this will reduce our warehouse bill" will remember that sentence.

Present the trade honestly and it survives the budget review. Present it as a saving and it does not.

Livedbt's own admitted trade-offs4 min▶

Credit where due: these come from dbt's documentation, not from a competitor's comparison page. Any vendor whose docs list constraints this plainly is easier to plan around than one whose docs do not.

Trade-offWhat it means for your plan
Requires a paid plandbt Core users get the local CLI only - no APIs, no integrations. The thing that makes the layer valuable is the serving surface, and the serving surface is the commercial product.
Metered by "Queried Metrics"Your bill scales with how successfully you drive adoption. Model this before you evangelize internally, not after.
"You're not materializing any data by default"The warehouse pays compute on every query. Budget engine spend and licence spend together.
No custom aggregations on measuresAnything exotic stays in a dbt model upstream. Check your five weirdest metrics against this before signing.
Real world

The modelling tension, in dbt's own words: "A star schema data model offers more flexibility for dimensions... but will require more joins. A fully denormalized data model is simpler... but won't be able to join to other tables."

There is no free option here. Denormalize and you get fast, simple, cheap queries that cannot answer the cross-domain question your CFO will ask in month three. Keep the star schema and you get flexibility that the join graph has to earn every single query. This decision is made at the modelling layer, in b5 territory, and it constrains everything you can do in b6. That is the strongest argument in the course for not treating these as separate projects.

Part 3 · covers Cube and Open Semantic Interchange

The analyst's surface, and the alternative shape ★ 12 min · everyone follows along

Everything above this layer is what the analyst actually ships: dashboards people open on Monday, scheduled reports that arrive in an inbox, and PDF exports that get pasted into a board pack and live forever. Those artifacts are the reason metric truth matters. A wrong number in an ad-hoc query gets corrected in the next message. A wrong number in a recurring PDF gets quoted back to you for two years.

List every recurring artifact your team produces - dashboard, scheduled email, PDF pack, spreadsheet refresh. For each, write down where its numbers are defined. Most teams find at least three distinct definition homes on the first pass.

For each artifact, ask the chokepoint test from b1: what stops someone bypassing the definition? If an analyst can write raw SQL in the BI tool, your semantic layer governs exactly the people who were already following the rules.

Now look at the alternative shape. Cube describes itself in four pillars: "data modeling, access control, caching, and APIs." Note the two that dbt's layer does not lead with - access control and caching. If your pain is "the same dashboard query runs 400 times a morning," that is a caching problem, and it points at a different product.

Check the protocol list, because it decides who can actually use the layer. Cube serves SQL, REST, GraphQL and MDX/DAX. That last pair is the one nobody mentions in a demo and everybody needs: it is what lets Excel connect. Your finance team is not migrating off Excel because you bought a semantic layer.

Read the marketing shift out loud. Cube repositioned from "universal semantic layer" to "agentic analytics platform" - with the same core product underneath. That is a category claim following a funding cycle, not a technology change. Learning to spot this is a durable skill: the four pillars are the falsifiable part, the positioning is not.

LiveOpen Semantic Interchange, and why a standard would matter here4 min▶

Open Semantic Interchange (OSI) is a Snowflake-led effort announced 2025-09-23: a standardized YAML format for exchanging semantic models between tools. Partners include Alation, Atlan, Cube, dbt Labs, Hex, Sigma and ThoughtSpot.

The reason to care is portability. Right now, the definitions you write are the deepest lock-in in the stack - deeper than the table format, because a metric definition encodes business agreement that took nine months of meetings to reach. If those definitions become an exchangeable artifact, the switching cost of a semantic layer drops sharply, which is exactly why an announcement with this partner list is interesting.

Two honesty notes. First, a partner list is an announcement, not an implementation - the useful question is which of those seven have shipped import and export against it. Second, we could not verify a v1.0 date or repository at the time of writing, so treat OSI as a direction of travel, not as something you can build a migration plan on today.

LiveCritical reading: the vendor stat that does not match the repo4 min▶

A small, concrete exercise you can repeat on any vendor in any category.

SourceClaim
Cube homepage18,000 GitHub stars
cube-js/cube repository, fetched 2026-08-0720,564 stars (2,104 forks)

Notice which direction the error runs. The vendor is understating its own number, which tells you exactly what happened: someone hardcoded the figure into the page during a redesign and nobody has touched it since. That is the general lesson - vendor stat blocks are frozen marketing artifacts, not telemetry. They are a snapshot of a number on the day a designer wrote the HTML.

Two follow-ons. Stars themselves are a weak proxy for anything: they are cumulative, never decay, and reward age over activity. And if a vendor's own homepage number is two years stale, ask the same question of every other number on that page - especially the ones you cannot check against an API.

Part 4 · self-study · sets up b9

The self-serve case and the AI case are the same case ◐ 6 min read

Here is the argument that makes this the pivot session of the practitioner track, and the reason a layer that looks like a BI concern is on the critical path for everything you are about to build in b7, b8 and b9.

Self-studyWhy an agent fails for exactly the reason a second BI developer fails6 min read▶

Consider two scenarios that look completely different and are structurally identical.

Scenario one. A second BI developer joins, is pointed at the warehouse, and builds a revenue dashboard. They do not know that internal test accounts are excluded, that revenue is reported on ship date, or that one region's currency conversion happens upstream. They write reasonable SQL. Their number differs from the existing dashboard by four percent. It takes three weeks and two meetings to find out why.

Scenario two. An agent is given warehouse credentials and asked for revenue by region. It writes reasonable SQL. It does not know any of those three things either, because none of them are written down anywhere the agent can read. Its number differs by four percent. Nobody investigates, because nobody knows to.

Same failure, same cause: the business logic lives in people's heads and in tool configuration rather than in an addressable artifact. The only differences are speed and volume. The second BI developer produces one wrong dashboard a fortnight and is eventually corrected by a colleague. The agent produces forty wrong answers before lunch, each one delivered with the same confident formatting as a correct one, to people with no way to tell the difference.

This is why "we will add the semantic layer later, after we ship the AI assistant" is the sequencing error the whole course exists to prevent. The assistant does not create the problem. It removes every human checkpoint that was quietly containing it.

The corollary is more encouraging than it sounds: the work you do on this layer is not BI work that also happens to help AI. It is the same work, and it is the best-returning investment available at this point in the stack, because it pays out twice. b9 is the evidence session that measures exactly how much it pays.

Homework

Try it yourself - this week ◐ 30-40 min total

Source material

Official sources covered

Vendor documentation and first-party repositories, with marketing claims labelled as marketing claims and unverified items labelled as unverified. This page covers:

✓dbt Semantic Layer documentation and FAQParts 1-2 · the filter-versus-definition diagnostic, the four admitted trade-offs
✓MetricFlow documentation - semantic models, entities, dimensions, measures, metricsParts 1-2 · the join graph, fan out and chasm joins, compiler not storage
✓Cube documentation and homepage · cube-js/cube repository (fetched 2026-08-07)Part 3 · the four pillars, MDX/DAX for Excel, the 18,000 versus 20,564 gap
◐Open Semantic Interchange announcement (2025-09-23), Snowflake-ledPart 3 · partner list verified · v1.0 date and repository unverified, flagged in session
Check yourself

Three questions before you go 🎯 ◐ 90 seconds

1 · Two teams report different revenue figures. Before you touch any tooling, what is the most likely diagnosis?

dbt's FAQ draws the line precisely: a different underlying aggregation makes it a different metric, but different filters or dimensions leave it the same metric. Most disagreements are the second kind. Teams that treat every one as a definition problem end up with forty near-identical metrics.

2 · A vendor demos metric definitions in clean YAML. What is the question that actually separates products in this category?

MetricFlow's documented job is capturing identifier types and navigating to appropriate joins "to avoid the construction of fan out and chasm joins." The YAML is the easy half. An order with three line items contributing its total three times is the hard half, and it looks like growth.

3 · Your CFO asks whether the semantic layer will reduce the warehouse bill. What is the honest answer?

dbt states it directly: "you're not materializing any data by default." The warehouse pays compute on every query, and the layer is metered by Queried Metrics on top. The trade is usually worth it, but it is a trade, and a finance stakeholder promised a saving will remember the promise.

Practitioner session 6 cheat sheet · pin this

The jobDefine each metric once in version-controlled code, serve it everywhere through an API - JDBC, GraphQL, Python SDK, dbt MCP server.
The vocabularySemantic models · entities (join keys) · dimensions (the slices) · measures (aggregatable columns) · metrics (what the business asks for).
The diagnosticDifferent aggregation = different metric. Different filters or grain = same metric. Most fights are the second kind.
The hard partThe join graph. Fan-out and chasm joins produce valid SQL with silently double-counted numbers that look like growth.
Compiler, not storageSQL generated at query time, nothing materialized by default. Cost moves from human duplication to compute plus licence.
dbt's admitted limitsPaid plan for APIs · metered by Queried Metrics · no custom aggregations on measures · star schema flexibility versus denormalized simplicity.
Cube's four pillarsData modeling, access control, caching, APIs. SQL/REST/GraphQL/MDX-DAX, so Excel connects. Positioning shifted, product did not.
Read vendor stats criticallyCube's homepage says 18,000 stars; the repo has 20,564 (2026-08-07). Stat blocks are frozen marketing artifacts, not telemetry.