Lineage & Impact
Trace any field from its data source down to the report visuals that use it, see exactly what breaks before you change it, and find what is genuinely safe to remove. Built offline from your model, available in the Studio and over MCP.
Two questions this tab answers. Forward: "if I change or remove this, what downstream breaks?" Reverse: "which objects can I delete with zero impact?" The reverse question is the hard one, because a model-only "unused" check over-reports (a descriptive column a report displays looks unused, since no measure references it). Report-aware analysis closes that gap.
#In the Studio
The Lineage & Impact tab renders the dependency graph with a force-directed view plus DAG and tree layouts, and a drill-down that expands node by node from data source to table to column or measure to report, page, visual and the exact field. On the force graph, click a node to select it and light up everything it touches, click another to walk the graph node by node, click empty space to step back out, and Reset restores the default view. Two modes toggle: Impact highlights everything downstream of a selected object, and Safe-to-remove lists the deletion candidates. Nodes carry a reference count, an impacted count and, for the safe-to-remove sweep, the tri-state verdict with a "blocked by" badge naming what still uses an object.
#Assess a proposed change
Impact Assessment starts with the change you intend to make, not just the object you selected. It reports the affected model objects and report visuals, explains anything it could not inspect, and produces an evidence record that Change Plan and workflows can carry into review. Cloud report discovery is supported; unreadable reports are listed with a reason and are never treated as safe.
#Over MCP
The same lineage is a tool surface, so your own AI Assistant can answer "what breaks if I drop Sales[Discount]?" or "list the safely removable measures".
get_lineage # the offline lineage graph: nodes + directed edges
impact_of measure:Sales/Margin # forward: everything that breaks if this changes
get_dependencies <objRef> # what an object's DAX consumes (check before editing)
get_dependencies <objRef> direction=dependents # what references it (check before delete / rename)
unused_objects # reverse safe-to-remove sweep (tri-state verdicts)
remove_safe_objects # delete the verified-safe set in ONE undoable step (Pro for >1)
analyze_reports <pbip-folder> # report-aware: which fields each local report uses
get_lineage builds the graph offline from the model (TOM): data source to table, table to
column and measure, DAX dependency edges, and foreign-key to primary-key relationships. For the star
schema itself, model_graph_summary is the cheap first call and get_model_graph
the full graph.
#Impact of a change
Before you edit or delete a measure or column, impact_of returns everything that breaks
transitively: the DAX dependents (measures, calculated columns and tables, calculation items, KPIs, RLS)
plus, for a column, the relationships, hierarchies and sort-by columns that use it, with a breadth-first
depth and counts by kind. get_dependencies (direction dependsOn) lists what an
object's DAX consumes, and get_dependents lists what references it, so "check dependents
before delete" is one call.
#Safe-to-remove, conservatively
unused_objects is the reverse sweep: every measure and column that nothing references, as a
deletion-candidate list. It is deliberately conservative and gives a tri-state verdict per item so it
never overstates safety:
| Verdict | Meaning |
|---|---|
| safe | Nothing in the model references it. A column used by a relationship, hierarchy, sort-by or RLS filter is never listed here. |
| used by an unused object | Referenced only by other dead objects, surfaced with what blocks it, so you can retire the chain together. |
| caution | A dependent report could not be read, so the object is not declared safe. |
Safe-to-remove fails loud rather than guessing. If a report cannot be read, the verdict degrades to caution instead of claiming the object is unused. On its own the model-only sweep cannot see report usage, so a field used only by a published report will still appear as a candidate until you add report analysis. Verify report usage before you delete.
#Report-aware lineage
Picking the reports to analyze no longer means hand-typing paths and workspace GUIDs. A Browse button opens the host folder picker for local project folders, and the workspace box becomes a picker that lists your workspaces by name and auto-selects the one that matches the open model, with an escape hatch to enter an id manually. A live progress channel streams per-report advancement ("Analyzing N of M") so a multi-report run never looks frozen, and stale responses from a model switch or a mid-flight edit are invalidated so an analysis can never target the previous model's workspace.
analyze_reports closes the model-only blind spot for local reports: point it at a Power BI
project folder in PBIR format and it parses which model fields each report actually uses, then recomputes
the safe-to-remove sweep excluding anything a report displays. Field references are reconciled to the
open model by name, so the model must be the one the reports bind to.
For published reports, analyze_cloud_reports does the same against the live service and
list_reports finds which published reports bind to the open model. Because the Fabric
report-definition API has no read-only scope, the cloud path requires a write-capable Fabric scope and an
explicit consent=true (the behaviour stays read-only: Semanticus never modifies a report).
Any report it cannot read (a paginated report, an encrypted sensitivity label, a download error) is
reported as unreadable with a reason, never silently dropped, so "safe" is never overstated.
#Remove what is safe, in one step
The sweep has an act half. On the tab, every removal candidate row carries a free delete (with a
verdict-aware confirm, and it is undoable), and the header offers Remove all N safe to
remove. Over MCP the same act is remove_safe_objects. Either way, the engine does
not trust a stale screen: the safe set is recomputed server-side and every item is re-verified at the
moment of deletion, so an item whose verdict changed since your scan (something now references it, a
report displays it) is skipped with a plain reason, never deleted stale. The still-safe set is deleted
as one undoable transaction, a single audit record carries the removed and skipped evidence, and
dry_run rehearses the whole sweep, including the would-be removed and skipped lists,
without touching anything.
Removing one item at a time is free (the same per-item delete as delete_object); removing
more than one in a single step is Pro, and the refusal names the free path.
Lineage, impact and safe-to-remove analysis are in the free tier, and so is removing items one at a time. See Pro for the one-click bulk engine that removes or applies a reviewed batch in one undoable transaction.
Semanticus