What’s Still Missing From Apache Ossie, and Where This Goes From Here
Part one covered the concept. Part two deployed one model for real against Databricks, Snowflake, and dbt, and found that the numbers agree everywhere, the metadata doesn’t. This one closes the series: the one problem I don’t think the current spec actually solves, where this project goes from here, and what an Ossie path into Power BI would need to look like.
Definitions versus evaluation
Ossie standardizes the schema: a name, a description, an expression per SQL dialect. Evaluation, how that expression actually gets computed once real joins are involved, is deliberately left to whoever’s on the other end of the conversion. That’s not a gap, it’s the same division of labor covered in part one: Ossie is the interchange format, not the runtime, closer to a .proto file than a query engine. What that division actually implies is worth spelling out, though, because it’s easy to read “write once, query anywhere” as a stronger guarantee than the spec is actually making.
- Every metric in the part two demo was single-table (
SUM(order_amount),COUNT(*),AVG(order_amount), all aggregatingordersalone). None of them ever had to cross theorders-to-customersjoin to compute a result. That’s exactly why the dialect expressions were trivial and portable, and why they matched everywhere. - The moment a metric needs to aggregate across a one-to-many join, fan-out becomes a real risk: summing a value from the “one” side after joining in the “many” side double-counts it, silently, no error. Every vendor tested in part two already has its own answer to this, and by design, not by accident. Databricks derives
rely.at_most_one_matchstraight from a dataset’sprimary_key, confirmed in our own convertedmetric_view.yaml, and resolvesMEASURE()against it at query time. dbt’s MetricFlow has done entity-based join inference (primary/foreign/unique keys) since before OSI existed. Snowflake’sCREATE SEMANTIC VIEWtakes a third shape: itsRELATIONSHIPSclause resolves joins viaREFERENCES, and the referenced table has to declare aPRIMARY KEY, which is exactly what shows up in our own exportedsemantic_model.yaml(customers/ordersboth carry aprimary_keyblock). No explicit cardinality flag the way Databricks has one, but the same underlying fact, that the referenced side is unique, is what Snowflake’s join resolution actually depends on. All three read the cardinality they need straight out of what Ossie already provides:primary_keyandrelationships, no missing field required, just three different places in three different DDLs to put the same fact. - What Ossie doesn’t do, and isn’t really its job to do, is check that a given dialect expression is actually correct once it crosses that join. The spec has no way to verify “this
SUMis fan-out-safe for this target,” it just carries the text. That check, if it happens at all, happens inside each vendor’s own engine, at whatever level of rigor that vendor built. - So the honest version of “write once, query anywhere”: proven, in this repo, for aggregates that stay within one table. Genuinely untested here for anything that needs a vendor’s own fan-out logic to actually kick in, across all three, not because the mechanism looks doubtful on paper, all three clearly have what they’d need, but because nothing in this demo ever asked them to use it.
Where this project goes next
- The ontology spec was never the focus of this series. Part one flagged it as a separate, newer, less-tooled part of Ossie, and every deploy in part two stayed entirely on the metrics side. Worth naming anyway:
apache/ossie’s ownconverters/directory has no ontology converter at all yet, but at least one company is already storing and editing real ontology files directly in the native Ossie format, no converter needed because they built straight on the spec itself. Entropy Data’s own writeup describes their Semantics product doing exactly that: ontologies stored natively in Ossie, editable, importable/exportable, and reachable through an MCP server for AI access, ahead of the ontology spec itself even being finalized (still draft, version 0.2.0, by their own account). - Query execution is a named goal, not active work. The roadmap lists a “Semantic Query Language & Reference Engine” — a standard query interface, a reference compiler from Ossie to SQL, a conformance test suite — under Future Efforts, not Current Efforts / Working Groups. No active working group is driving it yet, just a named goal with no committed timeline. Any tool today that executes queries directly against Ossie YAML, without going through a converter into a platform’s native format, is running ahead of any Apache reference implementation, not implementing one.
- Governance has no spec-level answer yet, and the community already knows it. Also a Future Effort, under “Governance, Identity, and Validation”: the motivation section states plainly that enterprise adoption requires consistent identifiers, validation, and governance hooks. Open discussions circle around a “Certified and Certifying Authority” concept for metrics, not full lineage or freshness tracking, which is the right scope: a certification flag records that someone approved a definition without asking the interchange format to carry live operational state about physical tables.
- There’s no native way to mark a field as sensitive. Two open issues, #58 and #59, ask for a “contains personal data” attribute and a “confidential indicator,” neither of which exists in the spec today. For anything under DSGVO or similar, that’s a real gap: today it has to go through
custom_extensions, meaning every consuming platform has to know your organization’s private convention for it. - The state of the repository itself is still very much in development: some converters have real bugs, like the two found in this series, and others simply don’t exist yet at all. AtScale, for one, has no converter directory in
apache/ossieat all, despite being one of the backers named in part one. - No Python package on PyPI yet, for any of it:
apache-ossie,apache-ossie-dbt, none of the converters this series tested. Every install in this whole series went throughuv’s git dependency support, pointed straight at a commit of theapache/ossierepo, not a normalpip install. Probably just a reflection of how early-stage this still is, a nine-month-old Apache Incubator podling, not a red flag on its own, but worth knowing before expectingpip install apache-ossieto work. - Power BI, when this was written, wasn’t just missing a converter, it was missing at the syntax level, one step further down than “nobody’s built it yet.” The core spec’s dialect enum was
ANSI_SQL,SNOWFLAKE,MDX,MAQL,TABLEAU,DATABRICKS,BIGQUERY. No DAX, noPOWER_BIoption at all.MDXwas in there, and Power BI’s engine can technically run an MDX query against a Tabular model, but that’s not how anyone writes a modern DAX measure. That one has since been fixed, and the section below has been rewritten around what shipped.
The Power BI gap, now closed

This section originally described a gap and two open pull requests. Both merged, and on 30 September 2026 Microsoft made it official: Christian Wade’s commitment to Apache Ossie on the Power BI blog, timed with FabCon Europe, alongside Snowflake’s engineering post from the other side. Rewritten below around what shipped.
DAX is in the core spec’s dialect enum. There is a converters/microsoft package doing bidirectional Power BI conversion, and the vendor token registered for it is MICROSOFT, not POWER_BI, because Power BI, Fabric, Azure Analysis Services and SQL Server Analysis Services share one object model and a model file cannot tell you which of the four it came from.
Worth keeping the point this section always made about DAX, because shipping does not make it less true. ANSI_SQL, SNOWFLAKE, DATABRICKS and BIGQUERY are all SQL, close enough in shape that this series watched SUM(order_amount) survive from one dialect tag to the next with barely a syntax change. DAX is not a SQL dialect running on a different engine, it is a different kind of language: no SELECT, no FROM, no GROUP BY, calculations defined through row and filter context instead. A converter cannot lean on syntactic similarity the way it can between SQL dialects.
Its answer to that is a deliberately narrow translator: a closed set of shapes with unambiguous DAX equivalents, and a refusal for everything else. Which needs a correction to what I wrote here before. I called the design “refusal-first,” and described it as unsupported constructs being reported and skipped rather than silently machine-translated. That is half right. Refusal is real and loud, but translation inside the supported set happens with no warning at all, and the condition attached to it, that a column must resolve to exactly one dataset, means COUNT(*) already fails in an ordinary two-table model. Assume it covers single-table metrics and write the DAX yourself for the rest.
I have written up what the converter does in detail in a separate post, including the handful of things that will stop a model loading in Fabric. One finding belongs here, though, because it lands directly on the thesis of this series.
A model that passes through Power BI on its way somewhere else arrives without its measures. Convert an Ossie model to Power BI and back, and every metric returns with DAX as its only dialect. The original SQL is not lost, it is preserved as an annotation inside a POWER_BI stash, but no other converter reads another vendor’s stash. Take that document on to Databricks and every metric is dropped for want of a DATABRICKS or ANSI_SQL dialect.
The obvious reading of that is unfair, though. A Power BI model that leaves and comes home is perfect: import then export gives a byte-identical file, and the stash is exactly what makes that work. The same stash is what breaks the onward trip. Fidelity is preserved in a vendor-private channel, which serves a model returning to where it came from and defeats one being handed to anybody else.
The practical rule that falls out: keep your Ossie models as the source of truth and convert outward to each platform. Never feed one platform’s export into another. Which is, conveniently, the same conclusion the rest of this post reaches from a different direction.
The payoff, once this matures, is the one part one argued matters most: grounding an AI agent’s answer. Copilot in Power BI needs the same kind of governed, versioned metric definition Cortex Analyst and Genie already ground their answers in.
How an organization would actually run this
The shape I keep coming back to: one team owns an Ossie repo, git-versioned, PR-reviewed, the way apache/ossie’s own examples are structured. Every other team, every other tool, whether that’s a BI dashboard, a dbt project, or an AI agent answering a business question, consumes from that one source instead of redefining “revenue” locally. Change a metric once, in one reviewed PR, and every downstream converter picks it up. That team can’t be purely technical, either, not if the thing it’s approving is what “revenue” means. Part one’s whole opening was that nobody had written that definition down anywhere shared; owning the repo means someone now has to, and that’s a business call as much as a syntax one.

That’s not a new idea on its own, a mature dbt-metrics or LookML shop already runs something close to it. What Ossie actually changes is that the PR isn’t locked to one vendor’s format. The same reviewed change ships into Databricks, Snowflake, and dbt at once, instead of getting rebuilt by hand in each. That cuts both directions: migrating off a platform stops being a rebuild-everything-by-hand project, and staying put stops being the path of least resistance just because leaving would mean redoing every metric from scratch. Less vendor lock-in isn’t a side effect here, it’s close to the whole point.
It’s also, unintentionally, an argument for centralizing that this whole series makes without meaning to. Every real bug found in part two, and the two dbt bugs found independently in two separate codebases, traced to exactly one place: one converter, one specific field, one specific model. None of them were diffuse the way the original “three definitions of revenue” problem from part one was, where nobody could say which of three people was wrong, only that they disagreed. That kind of disagreement is exactly why some companies end up running a standing weekly meeting, across reporting teams and platforms, just to reconcile why the same KPI came out different in two dashboards this week. Centralizing on Ossie doesn’t make the converters less buggy. It makes it obvious, immediately, which converter got it wrong, instead of the standing meeting having to find out.
The honest tradeoff: that central team now needs to actually know each target’s specific failures, not just write portable YAML and assume it works. Somebody on that team needs to know that Databricks’ Metric Views won’t auto-qualify a joined column inside a function call, that this converter of dbt’s needs a primary_key column to also be a declared field or it drops the entity silently, that Snowflake wants metrics nested per table with no warning if you get it wrong. That’s real depth per platform, not the “define once, forget about the rest” pitch this series opened with, and it’s exactly the kind of central team that becomes a bottleneck if it’s understaffed relative to how many metrics are actually changing.
Worth naming as a “not yet, but”: this whole series has effectively been running that team’s job by hand, for one tiny model, converter by converter, checking warnings, running real deploys, comparing real numbers. Nothing about that is specific to a demo. Once the spec and its converters are mature enough to trust running unattended, that work belongs in a CI pipeline, not with a person doing it by hand: every PR against the Ossie repo triggers every target converter, fails loudly on new warnings, and, further out, runs a live query against a real (probably scratch) warehouse to confirm the number didn’t move. Not there yet, given how much of this series was three converters each failing in their own way, but it’s a straight line from “one person doing this manually” to “a semantic-model pipeline with its own test suite,” not a reinvention.