Skip to content

About

Browser-based analytical runtime for learning semantic models, DAX evaluation and filter context, with a conformance-tested expression engine.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

BI Notebook Lab

Learn how DAX actually evaluates.

A browser-based Power BI learning lab with a real expression engine, semantic models, filter context and execution-based exercises. Write a measure, add a slicer, and trace exactly which rows survived and why.

▶ Live Demo · Run locally · Release notes · Contribute · Report a DAX disagreement

CI Status: V1 DAX conformance: 82/83 hand-verified License: MIT

Context Explorer: filter propagation and measure dependency trace

Context Explorer: pick a measure, add a filter, and follow it through the relationships down to the rows that were evaluated. Built-in synthetic sample data.

Try it in the browser: raulmermans.github.io/bi-notebook-lab → Free Lab → "Filter Context Lab". Nothing leaves your browser: projects are stored locally in IndexedDB.

Or run it locally (Node.js 20+, no account, no backend):

git clone https://github.com/RaulMermans/bi-notebook-lab && cd bi-notebook-lab
npm install && npm run dev    # open http://localhost:5173 → Free Lab → "Filter Context Lab"
What you get Evidence
One lexer → parser → binder → evaluator behind every calculated column, measure, visual and grader 1,024 passing tests, tsc clean (Evidence)
CALCULATE, iterators, time intelligence, 1:*/1:1/*:* and bidirectional relationships, USERELATIONSHIP/CROSSFILTER 82 of 83 hand-verified DAX conformance cases pass
Exercises graded by running your model under several filter contexts, not by matching strings docs/VALIDATION_ENGINE.md

Not a Power BI replacement. BI Notebook Lab implements a deliberately bounded subset of Power BI semantics to teach the mental model. Where it diverges from real DAX, the divergence is documented and tested. See Semantic honesty.

Found a case where it disagrees with real Power BI? That is the most useful thing you can report. Open a DAX divergence report with the expression, the model shape and what Power BI returns. Contributions start at CONTRIBUTING.md.

What it solves

Practising Power BI usually means Power BI Desktop, often on a shared virtual machine at work, which makes quick experiments awkward. BI Notebook Lab runs entirely in the browser: local-first (IndexedDB), with no backend, no account and no telemetry. You build a model step by step and get immediate feedback on whether it behaves the way you think, not just whether a chart renders.

Dataset → Power Query → Model → Calculated Column → Measure → Visual → Question → Test

Each concept is an executable notebook cell: DataCell, QueryCell, ModelCell, CalculatedColumnCell, MeasureCell, VisualCell and TestCell.

Architecture

Runtime architecture: expression engine, filter and relationship engine, consumers

  • One expression engine. Calculated columns and measures share the same lexer → parser → AST → binder → evaluator pipeline. Measures bind through a second binder over the same engine, not a copy.
  • One measure runtime for everything. Visuals, the Context Explorer and the validation engine all evaluate through the same evaluateMeasure. There is no second aggregation engine that could disagree.
  • Explicit filter context. Direct filters, relationship propagation (1:*, 1:1, *:*, single and bidirectional, active and inactive), CALCULATE replacement semantics, and a fail-closed guard against ambiguous or cyclic relationship paths.
  • Headless by rule. React only renders state. Every layer beneath it is framework-free TypeScript that runs in tests without a browser (an enforced guardrail in AGENTS.md).

More detail: ARCHITECTURE.md · docs/EXPRESSION_ENGINE.md · docs/FILTER_CONTEXT.md

Key engineering decisions

Decision Why
Grade by execution, not string matching The validation engine runs your model and measures through the real runtime across several filter contexts, so a hard-coded constant can't pass. It has weighted partial credit, required rules, and a staleness fingerprint so an outdated PASS is never shown as current.
Typed Applied Steps instead of an M interpreter Power Query is modelled as 19 typed step kinds that can be inspected and graded, with no arbitrary M execution.
Conformance labelled by provenance DAX cases are hand-verified and labelled by where the expected value came from, never claimed as "Power BI-verified".
Known divergences are tests, not footnotes BLANK() + 5 returns BLANK() here, where real DAX returns 5. It is kept as a skipped conformance case that states the reason.
Local-first IndexedDB persistence and portable .bilab.json project bundles, with no server to trust or run.

Evidence

Measured on the default branch (master) with npm test, npm run conformance, npm run typecheck, npm run build and npm run benchmark:

Check Result
Unit and integration tests 1,024 passing, 1 skipped (115 test files)
DAX semantic conformance 82 of 83 hand-verified cases pass. The 1 skipped case is the documented divergence above.
Type checking tsc -b clean
Production build Passes
End-to-end (Playwright) 2 of 2 user journeys pass: first-time Free Lab, and portable project export/import
Performance harness 17 runtime operations at 1k / 10k / 50k / 100k rows. None exceeded 1 s; the slowest recorded in docs/PERFORMANCE.md is about 250 ms at 100k rows.

Performance figures come from Node/V8, not a browser tab under UI load, and vary by machine, so the shape of the result matters more than the exact milliseconds. CI runs typecheck, the unit/integration suite (which includes conformance) and the build on every push; the Playwright and benchmark suites run locally. Release-time results are recorded in CHANGELOG.md.

Screenshots

Semantic model. A star schema on a canvas, with relationship validation against the real row data.

Semantic model: star schema canvas with relationships

Measures over the semantic model Visuals on the same measure runtime
Measure cells with DAX expressions and results Bar visual of Gross Margin by Category
Power Query (typed Applied Steps) Automatic checkpoint grading
Power Query editor with Applied Steps Checkpoint grading with per-criterion scores
Guided exercises Free Lab and practice projects
Exercise catalogue Free Lab landing with practice projects

All screenshots show the app's built-in synthetic sample data.

Capabilities

Feature matrix

Area Status
CSV / Excel import ✓
Power Query (typed Applied Steps, 19 kinds) ✓
Semantic model (generic relationships, USERELATIONSHIP/CROSSFILTER) ✓
Calculated columns ✓
Measures ✓
CALCULATE ✓
Iterators (SUMX/AVERAGEX/...) & table expressions ✓
VAR/RETURN, ISBLANK, HASONEVALUE, KEEPFILTERS ✓
Classic time intelligence ✓
Visuals (KPI/Bar/Line/Table/Slicer) ✓
Context Explorer (filter-propagation trace) ✓
Automatic validation / guided Exercises ✓
Portable project export/import (.bilab.json) ✓
Practice Projects & onboarding ✓
Semantic conformance suite ✓
Calculated Tables, CALENDAR/CALENDARAUTO, SUMMARIZE ✗ (deferred)
Full DAX / full M compatibility ✗ (bounded subset, by design)
PBIX/PBIP import, Fabric integration ✗ (out of scope)
Accounts, collaboration, backend ✗ (out of scope)

Semantic honesty

This project implements a bounded educational subset of Power BI semantics — not full DAX, not full M, not a Power BI replacement. It backs that claim with a conformance suite (npm run conformance): 83 hand-verified DAX cases across 10 families, run through the real runtime APIs, honestly labeled by provenance rather than claimed as power-bi-verified.

One known divergence is tracked deliberately rather than hidden: BLANK() + 5 returns BLANK() here, where real DAX coerces blank to 0 for +. This codebase propagates blank uniformly through every arithmetic operator instead of replicating DAX's per-operator coercion table. See docs/SEMANTIC_CONFORMANCE.md for the full list of what's verified and what's still approximate.

Tech stack

TypeScript · React 18 · Vite · React Flow (@xyflow/react) · Recharts · PapaParse and SheetJS (CSV/Excel import) · IndexedDB (idb-keyval) · Vitest (+ fake-indexeddb) · Playwright

Status

V1 complete. The full learning loop works end to end: import → Power Query → model → calculated columns → measures → filter context → visuals → validation → guided lessons.

Deferred: calculated tables, CALENDAR/CALENDARAUTO and SUMMARIZE. Out of scope: PBIX/PBIP import, Fabric, accounts and collaboration. See ROADMAP.md.

Limitations

  • A bounded subset of DAX and Power Query. It is not full DAX or M.
  • Blank handling in arithmetic differs from real DAX (documented and tested).
  • Performance is measured headlessly under Node/V8; very large datasets (beyond the 100k-row tested limit) are not a goal.
  • Browser-only persistence: projects live in IndexedDB until you export them.

Run locally

Requires Node.js 20+.

npm install
npm run dev          # http://localhost:5173
npm test             # unit + integration
npm run conformance  # DAX conformance suite
npm run benchmark    # performance report
npm run test:e2e     # Playwright journeys

Start from a practice project in Free Lab (Retail Modeling, DAX Playground, Power Query Cleaning or Filter Context Lab), or import your own CSV/Excel. A step-by-step tour is in docs/WALKTHROUGH.md.

Contributing

The highest-value contributions are DAX conformance cases (especially ones checked against real Power BI), filter-propagation edge cases, and divergence reports. Start with CONTRIBUTING.md and the issues labelled good first issue.

Documentation

Scope guardrail

Do not attempt to recreate Power BI Desktop, Microsoft Fabric, or full DAX compatibility. Power Query is now in scope, but only its Applied Steps transformation workflow (Sprint 12) — not an arbitrary M parser/interpreter, query folding, the Advanced Editor, custom M functions, connectors, parameters, or dataflows. See docs/POWER_QUERY_RUNTIME.md "M-language boundary".

The learning target is the smallest runtime that can faithfully teach the mental models used in real BI work.

About

Browser-based analytical runtime for learning semantic models, DAX evaluation and filter context, with a conformance-tested expression engine.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages