agentsclimarketplace

Fabric mlv

Skill wardawgmalvicious/claude-config/skills/fabric-mlv

Personal Claude Code config — skills, subagents, hooks, and rules for Microsoft Fabric and Power BI workflows on Windows. Cherry-pickable, no semver.

Install
npx -y skills add wardawgmalvicious/claude-config --skill fabric-mlv

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Use for Fabric Materialized Lake Views (MLVs) — `CREATE MATERIALIZED LAKE VIEW` Spark SQL (GA March 2026) + still-preview `@fmlv.materialized_lake_view` PySpark decorator on a schema-enabled lakehouse (Runtime 1.3). Covers CREATE / SHOW / ALTER RENAME / DROP / REFRESH FULL syntax, `CONSTRAINT ... CHECK ... ON MISMATCH DROP|FAIL` data quality rules, partitioning + TBLPROPERTIES, optimal refresh (skip / incremental / full) and CDF prerequisite, the supported-SQL-constructs table for incremental-vs-full fallback, lineage-driven dependency ordering, `RefreshMaterializedLakeViews` REST job-type (schedule + on-demand), run history (25 runs / 7 days; Success / Failed / Skipped / Canceled), data quality report, and gotchas: no ALTER definition only RENAME, no DML / UDF / temp views / time-travel, all-uppercase schemas rejected, names lowercased, `spark.conf.set` ignored on refresh, PySpark always full-refresh + lineage-schedule-only + no variables in `@fmlv` args, deleting defining notebook breaks PySpark refresh.

SKILL.md

13.8 KB, as published. Nobody here has run it

Fabric Materialized Lake Views (MLV)

Declarative SQL/PySpark transformations that persist as Delta tables in a schema-enabled lakehouse. Fabric handles refresh strategy, dependency order, and data quality enforcement so you don't write notebook orchestration.

When to use vs not

Use MLVs for medallion bronze→silver→gold pipelines, frequently-queried aggregates, declarative data quality, and reporting datasets that need automatic refresh. Skip them for one-off queries, sub-second streaming (use Real-Time Intelligence), or transformations that need ML inference / external API calls / non-SQL Python (use a regular Spark notebook).

Prerequisites

  • Schema-enabled lakehouse — required. enableSchemas is immutable per lakehouse; you can't retrofit it.
  • Fabric Runtime 1.3 — earlier runtimes can't author MLVs.
  • Region — not available in South Central US (as of 2026-04).
  • CDF on source tables — required for incremental refresh: ALTER TABLE bronze.x SET TBLPROPERTIES (delta.enableChangeDataFeed = true). Without it, optimal refresh degrades to skip-or-full only.

Spark SQL — CREATE

CREATE [OR REPLACE] MATERIALIZED LAKE VIEW [IF NOT EXISTS]
  [workspace.lakehouse.schema].MLV_Identifier
[(
    CONSTRAINT name1 CHECK (expr1) [ON MISMATCH DROP | FAIL],
    CONSTRAINT name2 CHECK (expr2) [ON MISMATCH DROP | FAIL]
)]
[PARTITIONED BY (col1, col2, ...)]
[COMMENT "..."]
[TBLPROPERTIES ("k1"="v1", ...)]
AS select_statement
ClauseNotes
OR REPLACEMutually exclusive with IF NOT EXISTS
CONSTRAINT ... CHECKMultiple allowed. Only deterministic built-ins permitted
ON MISMATCH DROPSilently drops violating rows. Each row dropped at most once even if it violates multiple constraints
ON MISMATCH FAILDefault. Stops the refresh with an error
PARTITIONED BYImproves filtered-read performance
TBLPROPERTIESSet delta.enableChangeDataFeed=true here to enable CDF on the MLV itself for downstream MLVs

Workspace names with spaces require backtick-quoting: `My Workspace`.lakehouse.schema.view_name.

CREATE OR REPLACE MATERIALIZED LAKE VIEW silver.cleaned_orders
( CONSTRAINT valid_qty CHECK (quantity > 0) ON MISMATCH DROP )
PARTITIONED BY (category)
TBLPROPERTIES (delta.enableChangeDataFeed=true)
AS SELECT p.productID, p.category, o.orderDate, o.quantity, o.totalAmount
FROM bronze.products p INNER JOIN bronze.orders o ON p.productID = o.productID;

Spark SQL — manage

SHOW MATERIALIZED LAKE VIEWS IN silver;
SHOW CREATE MATERIALIZED LAKE VIEW silver.cleaned_orders;
ALTER MATERIALIZED LAKE VIEW silver.cleaned_orders RENAME TO silver.cleaned_orders_v2;
DROP MATERIALIZED LAKE VIEW silver.cleaned_orders;
REFRESH MATERIALIZED LAKE VIEW silver.cleaned_orders FULL;

You cannot ALTER the definition — only RENAME. To change SELECT, constraints, or partitioning: drop and recreate (or CREATE OR REPLACE).

PySpark (fmlv — preview)

Use when transformations need UDFs, external Python libraries, or reusable helper functions that are awkward in SQL.

import fmlv
from pyspark.sql import functions as F

@fmlv.materialized_lake_view(
    name="LH1.silver.customer_enriched",
    partition_cols=["year", "city"],
    table_properties={"delta.enableChangeDataFeed": "true"},
    replace=True
)
@fmlv.check("nonnull_sales", "sales IS NOT NULL", "drop")
def customer_enriched():
    df = spark.read.table("LH2.bronze.customer_bronze")
    return df.withColumn("sales_in_usd", F.col("sales") * 1.0)

Notebook organization rules (PySpark only)

  • One @fmlv decorator per cell — multiple per cell is unsupported.
  • Helper functions go in cells above the @fmlv cell.
  • The defining notebook must not be deleted — scheduled refresh re-executes its cells. Deletion silently breaks every MLV defined there.
  • After editing the decorator, re-run the notebook to register the change. Otherwise the next refresh executes the new code with stale registration metadata and may fail.
  • No variables in @fmlv arguments — all parameters must be hardcoded literals. name=view_name will not work.
  • Only %%pyspark and %%sql magics, and only at the top of a cell.
  • Don't mix MLV definitions with unrelated code in the same notebook.

PySpark trade-offs vs SQL

CapabilitySpark SQLPySpark (fmlv)
Optimal (incremental) refresh❌ — always full refresh or skip
On-demand refresh from notebook✅ (REFRESH ... FULL)❌ — lineage-schedule only
Rename via SQL✅ (ALTER ... RENAME)❌ — drop+recreate, or rename in lakehouse explorer

Optimal refresh

Optimal refresh is on by default. Per-run, Fabric picks one of three strategies based on Delta commits on source tables:

StrategyWhen
SkipNo new Delta commits on any source table
IncrementalNew commits + query uses only the supported-construct subset + all sources have CDF enabled + append-only
FullSource has updates/deletes, unsupported constructs, non-Delta source, or PySpark-defined MLV

Toggle: lakehouse → Materialized lake viewsManageOptimal refresh. Off = every scheduled run does a full rebuild.

What blocks incremental refresh

ConstructBehavior
SELECT aggregates (SUM, COUNT, AVG, MIN, MAX, STDDEV)Full refresh
GROUP BY, DISTINCT, window functionsFull refresh
Non-deterministic funcs (rand(), uuid(), current_timestamp())Full refresh
INNER JOIN, LEFT OUTER, LEFT SEMI, UNION ALLIncremental — but LEFT joins fall back to full if the right-side table changes
Subqueries / EXISTSFull refresh if any referenced table changes
WITH (CTE)Incremental if every clause inside is supported
Source is non-Delta tableAlways full refresh

Unsupported constructs don't block creation — they just downgrade to full refresh. Audit MLVs whose runs always show as Full when you expected Incremental.

Lineage and scheduling

When an MLV references another MLV or table, Fabric builds a dependency DAG (the lineage view). A single schedule runs the whole DAG in the right order — you don't write orchestration. Currently one active schedule per lineage per lakehouse.

UI path: lakehouse → Materialized lake viewsManageScheduleNew schedule.

Run history retention: last 25 runs OR last 7 days, whichever comes first.

Run stateMeaning
In progressCurrently running
SuccessAll views in DAG refreshed
FailedAt least one view failed; downstream children auto-marked Skipped
SkippedSame view already refreshing in another active run
CanceledManually canceled from Monitor hub

Note: Monitor hub may show a Skipped MLV run as Canceled — they're the same thing in the lineage view.

REST API (job scheduler)

{jobType} is RefreshMaterializedLakeViews for every MLV endpoint.

# On-demand refresh of the entire lineage
POST /v1/workspaces/{ws}/lakehouses/{lh}/jobs/RefreshMaterializedLakeViews/instances
→ 202 Accepted, Location: .../jobs/instances/{jobInstanceId}

# Schedule CRUD
POST   /v1/workspaces/{ws}/lakehouses/{lh}/jobs/RefreshMaterializedLakeViews/schedules
GET    /v1/workspaces/{ws}/lakehouses/{lh}/jobs/RefreshMaterializedLakeViews/schedules
GET    /v1/workspaces/{ws}/lakehouses/{lh}/jobs/RefreshMaterializedLakeViews/schedules/{id}
PATCH  /v1/workspaces/{ws}/lakehouses/{lh}/jobs/RefreshMaterializedLakeViews/schedules/{id}
DELETE /v1/workspaces/{ws}/lakehouses/{lh}/jobs/RefreshMaterializedLakeViews/schedules/{id}

# Job instance status / cancel
GET  /v1/workspaces/{ws}/lakehouses/{lh}/jobs/RefreshMaterializedLakeViews/instances
GET  /v1/workspaces/{ws}/lakehouses/{lh}/jobs/instances/{jobInstanceId}
POST /v1/workspaces/{ws}/lakehouses/{lh}/jobs/instances/{jobInstanceId}/cancel

Polling pattern: take Location from the 202, poll the Get Item Job Instance endpoint until statusInProgress. Job-scheduler limits cap schedules-per-lakehouse and visible historical instances.

Data quality report

Auto-generated Power BI report tracking CHECK violations and DROP counts. Lakehouse → Manage materialized lake viewsData quality reportGenerate report.

  • Two pages: Overview (last 7 days, top MLVs/constraints) and MLV Detail (filterable by SchemaName / MLVName / RelativeDate).
  • Built on DirectQuery — capped at 1M rows per query on non-premium capacity.
  • Workspace/lakehouse names with special characters or spaces can fail report generation.
  • Recipients need at least Read or ReadData on the SQL analytics endpoint.
  • Violations ≥ drops (one row only ever dropped once even if it violates multiple constraints).

Limitations and gotchas

IssueCauseFix
MLV name unexpectedly lowercasedNames are case-insensitive, normalized to lowercaseReference as lowercase everywhere; don't rely on MyView resolving distinct from myview
ALTER to change SELECT failsOnly RENAME is supported via ALTERDrop + recreate, or CREATE OR REPLACE
INSERT/UPDATE/DELETE rejectedMLV is populated only by its SELECTModify the source table or rewrite the SELECT
Time-travel in definition rejectedVERSION AS OF / TIMESTAMP AS OF not allowedMaterialize the historical snapshot to a regular table first
UDF / temp view in definition rejectedNot supported in CREATE MATERIALIZED LAKE VIEWRewrite without UDFs, or switch to PySpark fmlv
Schema name MYSCHEMA rejectedAll-uppercase schema names not supportedUse mixed-case or lowercase schema names
spark.conf.set(...) doesn't apply on refreshSession-level Spark properties are dropped on scheduled refreshSet lakehouse- or workspace-level properties instead
Optimal refresh always picks FullUnsupported construct (aggregates / window / non-deterministic / non-Delta source) or no CDF on sourceCheck the supported-construct table; enable CDF; restructure SELECT
Incremental refresh skips changes from a LEFT join's right sideRight-side change triggers full refresh by designExpected; or rewrite as INNER if right side is fully populated
PySpark MLV refresh fails after notebook editDecorator changed but notebook wasn't re-runRe-execute every cell once after editing; refresh re-uses the latest cell contents
PySpark MLV stops refreshingDefining notebook deletedThe notebook is load-bearing for PySpark MLVs — don't delete it
@fmlv.materialized_lake_view(name=view_name) errorsVariables not allowed in decorator argsHardcode every parameter as a literal
MLV name with . rejectedPeriods reserved for workspace.lakehouse.schema.name qualificationUse _ or another separator
Two MLVs in one PySpark cell — only one registersOne decorator per cell limitSplit into separate cells
Run shows as Canceled in Monitor hub but Skipped in lineageMonitor hub maps Skipped → CanceledTrust the lineage view's status
Data quality report fails to generateWorkspace/lakehouse name has spaces or special charactersRename, or generate the report against a clean-named lakehouse
Data quality report missing rowsDirectQuery 1M-row cap on non-premiumUse premium capacity, or recreate the report after pruning history
Cross-lakehouse MLV chain doesn't workCross-lakehouse lineage and execution not supportedKeep MLV chains within a single lakehouse

Reference

See also

  • fabric-spark — PySpark in Fabric notebooks (the broader Spark surface; MLVs are one consumer)
  • fabric-eventhouse — KQL materialized views (different engine, similar concept)
  • fabric-error-handling — notebook/pipeline error patterns; useful when wrapping MLV refresh in a larger flow
  • fabric-monitoring — Monitor hub and Workspace monitoring
  • pbip-project-structure.Lakehouse/ folder placement when MLV-bearing lakehouses live in a PBIP repo

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.