Warning: This skill is incomplete and still in progress, but may provide value already as-is -- Kurt
Reviewing Semantic Models
Structured evaluation of Power BI semantic models against quality, performance, and best practice standards. Produces actionable findings with prioritized recommendations.
Review Workflow
Step 0: Gather Context
Before analyzing TMDL, collect metadata and understand the business context.
Run the model info script:
python3 scripts/get_model_info.py -w <workspace-id> -m <model-id>
This returns: storage mode, model size, connected reports, deployment pipeline, endorsement status, sensitivity label, data sources, refresh schedule, last refresh, and capacity SKU.
Ask the user:
- What business process does this model represent?
- Who are the primary consumers? (report developers, analysts, executives, AI/Copilot users?)
- Are they the developer of both the model and its reports, or only one?
- Is the model in development, testing, or production?
- Where should findings be documented? (scratchpad, agent-docs, wiki, etc.)
Understanding the business context is critical. A model for 3 analysts has different requirements than one consumed by Copilot across the organization. The audit categories and their severity shift based on this context.
Step 1: Analyze Model Structure
Inspect the model definition to evaluate its structure. The approach depends on available tooling -- use whatever is available to read the model's tables, columns, measures, relationships, and expressions. Do not prescribe a specific tool; common options include Tabular Editor, the te-cli, fab export to TMDL, or programmatic access via APIs.
Step 2: Audit Categories
Evaluate findings across categories, ordered by severity:
Critical
- Bidirectional relationships (ambiguity risk)
- Circular dependencies between tables
- Missing data types on columns
- Tables without relationships (orphaned)
Memory and Size
- High-cardinality columns with large dictionaries (GUIDs, transaction IDs, composite keys)
- IsAvailableInMdx enabled on hidden or high-cardinality columns (wastes memory on attribute hierarchies unused by DAX; disable for columns not consumed via Analyze in Excel / MDX)
- Unsplit DateTime columns (near-unique precision creating massive dictionaries)
- Auto Date/Time tables (hidden LocalDateTable_* bloating memory)
- Inappropriate data types (Double for currency, String for numeric)
- Calculated columns that could be measures
- Unused columns or tables (no references in measures or visuals or other downstream items)
Data Reduction
- Unfiltered history in fact tables (no date-range filter or incremental refresh)
- Columns that aren't necessary for reporting or calculations or consumption
- Pre-summarization opportunities (detail grain not needed for reporting)
- Columns better handled upstream (i.e. calculations not done in calc columns or PQ)
DAX Anti-Patterns (for systematic DAX query optimization, use the dax skill)
- Filtering tables instead of columns in CALCULATE (causes both correctness and performance issues)
- Unhandled division by zero (use DIVIDE() or explicit zero-check; note: plain
/ is fine when the denominator is guaranteed non-zero and can be faster)
- Iterators with callbacks or nested iterators over large tables (use aggregators like SUM/AVERAGE when possible; iterators over large tables are fine if the expression is Storage Engine-pushable)
- Missing KEEPFILTERS around non-equality filter predicates in CALCULATE
Measure Hygiene
- Implicit measures used where explicit measures should exist
- Report-scoped extension measures that should be model-level
- Duplicate or overlapping measures with ambiguous names
Documentation
- Tables or columns missing descriptions
- Missing display folders for measures
- Inconsistent naming conventions (use the
standardize-naming-conventions skill)
Design
- Star schema violations (direct fact-to-fact relationships, snowflake patterns)
- Missing or misconfigured date table: must be marked (
dataCategory: Time in TMDL, with a key Date column), have continuous daily dates (no gaps), span the full range of fact data, and relate to fact tables via a single-column relationship. Missing any of these causes time intelligence functions (DATEADD, SAMEPERIODLASTYEAR, TOTALYTD) to return BLANK
- Excessive columns per table (>30 suggests denormalization issues)
- Many-to-many relationships without bridging tables
- Multiple fact tables relating to the same dimension via different keys without a shared conformed dimension (causes slicers on one fact to not filter the other)
- Inactive relationships without corresponding USERELATIONSHIP in measures (orphaned relationships that suggest incomplete modeling)
Direct Lake (if applicable)
- Delta table health (parquet file count, V-Order, row group sizes)
- DirectQuery fallback risk (RLS definitions, SQL endpoint views)
AI and Copilot Readiness (see references/ai-readiness.md)
- Duplicate field names across tables (confuses Copilot/data agents)
- Missing AI instructions
- Missing or inadequate descriptions for AI consumption
- Complex patterns (disconnected tables, many-to-many, inactive relationships) are valid model design but AI may struggle with them
Step 3: Performance Analysis
For performance-specific analysis, see references/performance.md.
Step 4: Report Findings
Produce a structured markdown report with:
- Summary table of finding counts by severity
- Detailed findings with file locations and line numbers where possible
- Specific remediation recommendations for each finding
- Prioritized action list (critical first)
Using the Semantic Model Reviewer Agent
Dispatch the semantic-model-auditor agent to perform the structural audit. The agent handles export, analysis, and reporting autonomously.
Notes
- The structural audit analyzes model metadata -- it does not execute DAX queries or check data quality
- For DAX query performance testing, see
references/performance.md
- For DAX optimization, use the
dax skill
- For companion report review, use the
review-report skill in the reports plugin
References
references/ai-readiness.md -- Copilot/Data Agent preparation: AI instructions, descriptions, schema, verified answers
references/performance.md -- Performance testing methodology, unused column detection, memory analysis
scripts/get_model_info.py -- Quick model metadata overview (storage mode, size, reports, pipeline, endorsement, data sources)
Related Skills
dax -- DAX performance optimization
review-report (reports plugin) -- Companion skill for report-level review
standardize-naming-conventions -- Naming audit and remediation
lineage-analysis -- Downstream report discovery
refresh-semantic-model -- Refresh monitoring and troubleshooting
1---2name: powerbi-review-semantic-model3description: Review, audit, and validate Power BI semantic models against quality, performance, and best practice standards. Automatically invoke when the user asks to "review a semantic model", "audit a semantic model", "check model quality", "optimize my model", "validate model design", "check AI readiness", "prepare model for Copilot", or mentions model validation or quality assessment.4license: MIT5---67Warning: This skill is incomplete and still in progress, but may provide value already as-is -- Kurt89# Reviewing Semantic Models1011Structured evaluation of Power BI semantic models against quality, performance, and best practice standards. Produces actionable findings with prioritized recommendations.1213## Review Workflow1415### Step 0: Gather Context1617Before analyzing TMDL, collect metadata and understand the business context.1819**Run the model info script:**2021```bash22python3 scripts/get_model_info.py -w <workspace-id> -m <model-id>23```2425This returns: storage mode, model size, connected reports, deployment pipeline, endorsement status, sensitivity label, data sources, refresh schedule, last refresh, and capacity SKU.2627**Ask the user:**2829- What business process does this model represent?30- Who are the primary consumers? (report developers, analysts, executives, AI/Copilot users?)31- Are they the developer of both the model and its reports, or only one?32- Is the model in development, testing, or production?33- Where should findings be documented? (scratchpad, agent-docs, wiki, etc.)3435Understanding the business context is critical. A model for 3 analysts has different requirements than one consumed by Copilot across the organization. The audit categories and their severity shift based on this context.3637### Step 1: Analyze Model Structure3839Inspect the model definition to evaluate its structure. The approach depends on available tooling -- use whatever is available to read the model's tables, columns, measures, relationships, and expressions. Do not prescribe a specific tool; common options include Tabular Editor, the `te-cli`, `fab export` to TMDL, or programmatic access via APIs.4041### Step 2: Audit Categories4243Evaluate findings across categories, ordered by severity:4445**Critical**46- Bidirectional relationships (ambiguity risk)47- Circular dependencies between tables48- Missing data types on columns49- Tables without relationships (orphaned)5051**Memory and Size**52- High-cardinality columns with large dictionaries (GUIDs, transaction IDs, composite keys)53- IsAvailableInMdx enabled on hidden or high-cardinality columns (wastes memory on attribute hierarchies unused by DAX; disable for columns not consumed via Analyze in Excel / MDX)54- Unsplit DateTime columns (near-unique precision creating massive dictionaries)55- Auto Date/Time tables (hidden LocalDateTable_* bloating memory)56- Inappropriate data types (Double for currency, String for numeric)57- Calculated columns that could be measures58- Unused columns or tables (no references in measures or visuals or other downstream items)5960**Data Reduction**61- Unfiltered history in fact tables (no date-range filter or incremental refresh)62- Columns that aren't necessary for reporting or calculations or consumption63- Pre-summarization opportunities (detail grain not needed for reporting)64- Columns better handled upstream (i.e. calculations not done in calc columns or PQ)6566**DAX Anti-Patterns** (for systematic DAX query optimization, use the [`dax` skill](../dax/))67- Filtering tables instead of columns in CALCULATE (causes both correctness and performance issues)68- Unhandled division by zero (use DIVIDE() or explicit zero-check; note: plain `/` is fine when the denominator is guaranteed non-zero and can be faster)69- Iterators with callbacks or nested iterators over large tables (use aggregators like SUM/AVERAGE when possible; iterators over large tables are fine if the expression is Storage Engine-pushable)70- Missing KEEPFILTERS around non-equality filter predicates in CALCULATE7172**Measure Hygiene**73- Implicit measures used where explicit measures should exist74- Report-scoped extension measures that should be model-level75- Duplicate or overlapping measures with ambiguous names7677**Documentation**78- Tables or columns missing descriptions79- Missing display folders for measures80- Inconsistent naming conventions (use the `standardize-naming-conventions` skill)8182**Design**83- Star schema violations (direct fact-to-fact relationships, snowflake patterns)84- Missing or misconfigured date table: must be marked (`dataCategory: Time` in TMDL, with a key Date column), have continuous daily dates (no gaps), span the full range of fact data, and relate to fact tables via a single-column relationship. Missing any of these causes time intelligence functions (DATEADD, SAMEPERIODLASTYEAR, TOTALYTD) to return BLANK85- Excessive columns per table (>30 suggests denormalization issues)86- Many-to-many relationships without bridging tables87- Multiple fact tables relating to the same dimension via different keys without a shared conformed dimension (causes slicers on one fact to not filter the other)88- Inactive relationships without corresponding USERELATIONSHIP in measures (orphaned relationships that suggest incomplete modeling)8990**Direct Lake (if applicable)**91- Delta table health (parquet file count, V-Order, row group sizes)92- DirectQuery fallback risk (RLS definitions, SQL endpoint views)9394**AI and Copilot Readiness** (see `references/ai-readiness.md`)95- Duplicate field names across tables (confuses Copilot/data agents)96- Missing AI instructions97- Missing or inadequate descriptions for AI consumption98- Complex patterns (disconnected tables, many-to-many, inactive relationships) are valid model design but AI may struggle with them99100### Step 3: Performance Analysis101102For performance-specific analysis, see `references/performance.md`.103104### Step 4: Report Findings105106Produce a structured markdown report with:107108- Summary table of finding counts by severity109- Detailed findings with file locations and line numbers where possible110- Specific remediation recommendations for each finding111- Prioritized action list (critical first)112113## Using the Semantic Model Reviewer Agent114115Dispatch the `semantic-model-auditor` agent to perform the structural audit. The agent handles export, analysis, and reporting autonomously.116117## Notes118119- The structural audit analyzes model metadata -- it does not execute DAX queries or check data quality120- For DAX query performance testing, see `references/performance.md`121- For DAX optimization, use the [`dax` skill](../dax/)122- For companion report review, use the `review-report` skill in the reports plugin123124## References125126- **`references/ai-readiness.md`** -- Copilot/Data Agent preparation: AI instructions, descriptions, schema, verified answers127- **`references/performance.md`** -- Performance testing methodology, unused column detection, memory analysis128- **`scripts/get_model_info.py`** -- Quick model metadata overview (storage mode, size, reports, pipeline, endorsement, data sources)129130## Related Skills131132- **[`dax`](../dax/)** -- DAX performance optimization133- **`review-report`** (reports plugin) -- Companion skill for report-level review134- **`standardize-naming-conventions`** -- Naming audit and remediation135- **`lineage-analysis`** -- Downstream report discovery136- **`refresh-semantic-model`** -- Refresh monitoring and troubleshooting