Semantic-model golden references & DAX-oracle strategy
Before any semantic-model / DAX work, this pins the golden references we’d build and validate against, and — the crux — records where an executable oracle exists and where it doesn’t. That split decides the whole approach.
See parity.md for why Power BI is 🔴 today (item management only, no modeling engine), and third_party/ for the vendored references and the provenance pattern.
The four layers, and whether each has a live oracle
Section titled “The four layers, and whether each has a live oracle”| Layer | Golden reference (paper) | Machine-readable? | Executable oracle (CI-able?) |
|---|---|---|---|
| Model format (TMSL/TMDL) | bi-shared-docs tmsl/, tmdl/ | TMSL JSON schema; TMDL grammar | ✅ round-trip vs real .tmdl/model.bim fixtures |
| DAX language | learn.microsoft.com/dax (function ref); [MS-SSAS-T] query semantics | ❌ no grammar/OpenAPI | ⚠️ only a live AS engine → oracle = captured (query → rows) fixtures |
| XMLA wire | [MS-SSAS-T], [MS-SSAS] xmla-rs:rowset, bi-shared-docs XMLA ref | XSD for envelopes/rowsets | ⚠️ ADOMD.NET, and it IS endpoint-overridable — runs on Linux and connects to a host we name; asserted weekly by e2e/xmla |
| executeQueries REST | third_party/powerbi-rest-swagger/swagger.json | ✅ official OpenAPI (MIT) | ✅ real REST client + the schema |
The decisive distinction
Section titled “The decisive distinction”Every e2e we ship works by pointing a real, unmodified client at the emulator via an endpoint override (delta-rs, ABFS, azure-sdk, fabric-cicd, the Livy proxy). Two of these four layers cannot support that:
-
XMLA — deferred, but the CAUSE recorded here was wrong and has been retested. 32-xmla-plan.md carries the scope.
e2e/xmlapoints Microsoft’s own ADOMD.NET at a listener we control, from Linux, in a container, and it connects: thepowerbi://<host>form is endpoint-overridable, a self-signed CA is trusted the usual way, and the bearer token comes from the connection string. Its first call is plain JSON REST (GET /powerbi/databases/v201606/workspaces), not SOAP. That suite runs weekly, so a change in the client’s contract is a failing build rather than a rediscovery.So “can’t be pointed at a hand-rolled Go server” is false, and a CI oracle exists. It now reaches XMLA/SOAP as well (2026-08-10): answering
clusterResolvewithNameResolutionResult.clusterFQDN— the contract read off the assembly, not screened — takes the client past routing, and it POSTs a SOAPExecutecarryingBeginSession mustUnderstand="1"and an empty<Statement/>. Opening a connection is a session handshake, not a query.What stands is still the SIZE, for a narrower reason than before. Connect has cost one thing per gate (one reply field, one
ExecuteResponse, one echoedx-ms-xmlacaps-negotiation-flags), but the client has not yet been asked to run a query, so nothing about rowset serialisation — the real work — is measured.docs/24’sLis unchanged, and should not move on the strength of a handshake. Deferred on cost, not on feasibility. -
DAX — correctness is defined by a live engine (Power BI / SSAS / AS), none of which is pure-Go or CI-runnable. Its golden reference can only be captured
(DAX query → rows)fixtures, recorded once from a real engine and vendored as test data — a snapshot oracle, weaker than a live client.
Only executeQueries has both a machine-readable golden spec and a live oracle. That is why, if the semantic-model engine is built, it should expose the executeQueries REST contract (conforming to the vendored swagger), backed by a bounded-but-real DAX evaluator — not the XMLA endpoint.
The DAX oracle on macOS (this dev box)
Section titled “The DAX oracle on macOS (this dev box)”Power BI Desktop and DAX Studio are Windows-only — neither has a macOS
build; on a Mac they run only inside a Windows VM or a cloud PC. macOS-native
options for capturing golden (query → rows) fixtures:
- executeQueries REST against a real dataset (best) — callable from macOS over HTTP against a Power BI PPU/Fabric-trial dataset. Captures goldens through the exact contract we’d implement, so it doubles as a real-API shape check. Needs a Power BI account with a supported capacity.
- Hand-computed goldens — for a small hand-authored model, compute
expected rows by hand. Fully hermetic and macOS-native, but validates
against our own arithmetic, so keep the queries unambiguous (SUM / COUNT /
DIVIDE / single-group
SUMMARIZECOLUMNS). - Windows VM — Parallels/UTM (Windows 11 ARM; Power BI Desktop x64 under emulation) → DAX Studio capture. Heaviest; only if we need complex DAX.
Recommended starting point: a small authored model with hand-computed goldens for the deterministic core, optionally strengthened by executeQueries-REST captures against a PPU trial when an account is available.
Vendored now
Section titled “Vendored now”- ✅
third_party/powerbi-rest-swagger/swagger.json— the executeQueries golden OpenAPI (MIT, pinnedc7755706). - ✅
third_party/bi-shared-docs/PROVENANCE.md— XMLA/rowset/TMSL/TMDL specs, pinned by reference (SHA328074568, CC-BY-4.0).
Still to identify before implementation: a golden model fixture (a small
TMDL/TMSL model mirroring the tutorial’s Store/Time/Sales + TotalUnits /
Total Units This Year|Last Year measures) and its captured (query → rows)
goldens.