Skip to content

Lab 02: Meet the baseline model

Time
About 30 minutes
Level
intro
Platforms
Windows 11, macOS (file mode, no Desktop)
Copilot surfaces
Power BI Desktop, VS Code, Copilot CLI
You'll use
pbip, tmdl, pbir, baseline
Starts from
lab02-start: The baseline model exactly as it ships on main.
Ends at
lab02-start: The baseline model exactly as it ships on main.
Last verified
Not yet run end to end on Windows 11

Works on macOS

Nobody has run this lab end to end on Windows 11 yet. The steps follow the current docs for each tool, but menu labels may differ. The verify command at the end is the source of truth, and feedback is welcome.

The baseline model is valid, but it is not friendly to people or AI tools. It uses source-system names, has weak relationships, leaves keys visible, and gives agents almost no definitions. You inspect those defects before asking Copilot to fix them later. Seeing the problems in both Desktop and text makes the rest of the lab feel concrete.

  • PBIP: a Power BI Project saved as files so Git and agents can review changes. See Architecture.
  • TMDL: the text format for the semantic model under fabric/ContosoPharmacy.SemanticModel/definition/.
  • PBIR: the report format under fabric/ContosoPharmacy.Report/definition/, with one visual.json per visual.
  • Relationship: the TMDL link between model tables. Missing or bidirectional relationships can make answers wrong.
  • DataFolderPath: the Power Query parameter that points Desktop at the synthetic CSV folder.
  • Finish Lab 01.
  • On Windows, Power BI Desktop is installed.
  • Close other Power BI Desktop files so you know which model the later checks find.
  • On macOS, use the “No Desktop” path in the steps.

Step 1. Link Desktop to the local data folder

Section titled “Step 1. Link Desktop to the local data folder”
Windows only

Power BI Desktop reads the CSVs through a fixed path, C:\ContosoPharmacyDemo\data\. The script creates that path as a directory junction to this clone’s data\generated folder.

Terminal window
pwsh ./scripts/Set-LocalDataLink.ps1
scripts/Set-LocalDataLink.ps1 (lines 2-19)
<#
.SYNOPSIS
Points C:\ContosoPharmacyDemo\data at this clone's data\generated folder (Windows only).
.DESCRIPTION
The semantic model reads the CSV files from the DataFolderPath parameter, which defaults to
C:\ContosoPharmacyDemo\data\. This script creates that path as a directory junction to
data\generated in your clone, so the model works wherever you cloned the repo, including paths
with spaces. Junctions don't need administrator rights or Developer Mode.
If the path already exists as a junction it's replaced. If it's a real folder with files in it,
the script stops and changes nothing.
.PARAMETER Path
Where to create the link. Default: C:\ContosoPharmacyDemo\data. If you change it, also change
DataFolderPath in Power BI Desktop (Transform data > Edit parameters).
.PARAMETER Remove
Remove the junction (and the parent folder if it's empty). Your data isn't touched.
.EXAMPLE
pwsh ./scripts/Set-LocalDataLink.ps1

You should see: Linked C:\ContosoPharmacyDemo\data -> <your clone>\data\generated on Windows. On macOS, you should see that the script has nothing to do.

Open fabric/ContosoPharmacy.SemanticModel/definition/expressions.tmdl in VS Code:

  • Keyboard: Ctrl+P (macOS: Cmd+P), type the file name, press Enter.
  • Command Palette: Ctrl+Shift+P (macOS: Cmd+Shift+P), run File: Open File, then pick the file.
  • Menu: File > Open File.
fabric/ContosoPharmacy.SemanticModel/definition/expressions.tmdl
/// Folder that holds the synthetic CSV files. Created by scripts/Set-LocalDataLink.ps1.
expression DataFolderPath = "C:\ContosoPharmacyDemo\data\" meta [IsParameterQuery = true, Type = "Text", IsParameterQueryRequired = true]

That parameter is why the junction exists. It also keeps personal user paths out of the semantic model.

You should see: DataFolderPath defaults to C:\ContosoPharmacyDemo\data\ and is marked as a required text parameter.

Windows only
  1. In File Explorer, open fabric\ContosoPharmacy.pbip.
  2. If Power BI Desktop asks whether to trust the project, select the safe option to open it from your local clone.
  3. If Desktop offers to upgrade or save the report format, don’t save yet. You only inspect in this lab.
  4. On the Home ribbon, select Refresh.
  5. Open Model view from the left rail.
fabric/README.md (lines 10-27)
| `ai-prep/` | Markdown and YAML | Drafts of AI instructions, synonyms, and verified answers (added in Lab 09). |
## Open it
Power BI Desktop runs on Windows only. On Windows 11:
1. Run `pwsh ./scripts/Set-LocalDataLink.ps1` once so `C:\ContosoPharmacyDemo\data\` points at `data/generated/`.
2. In Power BI Desktop, turn on the preview features **Power BI Project (.pbip) save option** and **Store semantic model using TMDL format** (File > Options and settings > Options > Preview features), then restart Desktop.
3. Open `fabric/ContosoPharmacy.pbip` and select **Refresh**.
On macOS you can still read and edit the TMDL and PBIR files, run every validator, and do the Copilot labs. You just can't open the model in Desktop or run the DAX tests.
## The baseline is rough on purpose
The model on `main` is the starting point for the labs. It has problems a real team would recognize:
- Tables and columns use source codes (`fact_rx_fill`, `rgn`, `proc_mins`) instead of business names.
- No descriptions, and keys are visible and summarized.

You should see: an Overview report page, then a model with dim_date, dim_store, dim_med, and fact_rx_fill after refresh.

Step 4. Find the baseline defects in the model

Section titled “Step 4. Find the baseline defects in the model”

In Desktop Model view, look for these issues. Then match each one to a repo file.

  1. Tables and columns use source names such as fact_rx_fill, dim_store, rgn, and proc_mins.
  2. fact_rx_fill has a relationship to Date and Store, but not to Medication.
  3. The Store relationship is bidirectional.
  4. Auto date/time is enabled.
  5. Numeric keys and helper columns summarize by sum.
  6. There are no descriptions or measures.

The text files show the same defects:

fabric/ContosoPharmacy.SemanticModel/definition/model.tmdl (lines 9-14)
annotation __PBI_TimeIntelligenceEnabled = 1
ref table dim_date
ref table dim_store
ref table dim_med
ref table fact_rx_fill
fabric/ContosoPharmacy.SemanticModel/definition/relationships.tmdl
relationship 'fact_rx_fill to dim_date'
joinOnDateBehavior: datePartOnly
fromColumn: fact_rx_fill.fill_dt
toColumn: dim_date.cal_dt
relationship 'fact_rx_fill to dim_store'
crossFilteringBehavior: bothDirections
fromColumn: fact_rx_fill.store_key
toColumn: dim_store.store_key
fabric/ContosoPharmacy.SemanticModel/definition/tables/fact_rx_fill.tmdl (lines 1-78)
table fact_rx_fill
column fill_id
dataType: int64
formatString: 0
summarizeBy: sum
sourceColumn: fill_id
annotation SummarizationSetBy = User
column fill_dt
dataType: dateTime
formatString: Long Date
summarizeBy: none
sourceColumn: fill_dt
annotation SummarizationSetBy = User
annotation UnderlyingDateTimeDataType = Date
column store_key
dataType: int64
formatString: 0
summarizeBy: sum
sourceColumn: store_key
annotation SummarizationSetBy = User
column med_key
dataType: int64
formatString: 0
summarizeBy: sum
sourceColumn: med_key
annotation SummarizationSetBy = User
column fill_typ
dataType: string
summarizeBy: none
sourceColumn: fill_typ
annotation SummarizationSetBy = User
column refill_no
dataType: int64
formatString: 0
summarizeBy: sum
sourceColumn: refill_no
annotation SummarizationSetBy = User
column qty
dataType: int64
formatString: 0
summarizeBy: sum
sourceColumn: qty
annotation SummarizationSetBy = User
column days_sply
dataType: int64
formatString: 0
summarizeBy: sum
sourceColumn: days_sply
annotation SummarizationSetBy = User
column payer_typ
dataType: string
summarizeBy: none
sourceColumn: payer_typ
annotation SummarizationSetBy = User
column proc_mins
dataType: double
summarizeBy: sum
sourceColumn: proc_mins

You should see: the missing Medication relationship, crossFilteringBehavior: bothDirections, annotation __PBI_TimeIntelligenceEnabled = 1, raw source names, and sum summarization on IDs and keys.

Step 5. Confirm Desktop left fabric/ clean

Section titled “Step 5. Confirm Desktop left fabric/ clean”

Opening a PBIP can create local cache files. Those are ignored. It should not rewrite the model or report just because you opened it.

Terminal window
git status --short fabric

You should see: no output. If you see changed files under fabric/, don’t commit them yet. Read troubleshooting first.

Step 6. Inspect the baseline report bindings

Section titled “Step 6. Inspect the baseline report bindings”

The report already tells a useful story, but the visuals bind to the raw model names. Open the visual.json files under fabric/ContosoPharmacy.Report/definition/pages/73b4ba6b5ea8b192ee63/visuals/.

fabric/ContosoPharmacy.Report/definition/pages/73b4ba6b5ea8b192ee63/visuals/5b930478ed94db246824/visual.json (lines 21-53)
"Expression": {
"SourceRef": {
"Entity": "dim_store"
}
},
"Property": "rgn"
}
},
"queryRef": "dim_store.rgn",
"nativeQueryRef": "rgn"
}
]
},
"Y": {
"projections": [
{
"field": {
"Aggregation": {
"Expression": {
"Column": {
"Expression": {
"SourceRef": {
"Entity": "fact_rx_fill"
}
},
"Property": "fill_id"
}
},
"Function": 5
}
},
"queryRef": "CountNonNull(fact_rx_fill.fill_id)",
"nativeQueryRef": "Count of fill_id"
fabric/ContosoPharmacy.Report/definition/pages/73b4ba6b5ea8b192ee63/visuals/94338098659bdb0fd362/visual.json (lines 21-49)
"Expression": {
"SourceRef": {
"Entity": "dim_store"
}
},
"Property": "store_nm"
}
},
"queryRef": "dim_store.store_nm",
"nativeQueryRef": "store_nm"
},
{
"field": {
"Aggregation": {
"Expression": {
"Column": {
"Expression": {
"SourceRef": {
"Entity": "fact_rx_fill"
}
},
"Property": "proc_mins"
}
},
"Function": 0
}
},
"queryRef": "Sum(fact_rx_fill.proc_mins)",
"nativeQueryRef": "Sum of proc_mins"

You should see: visuals refer to dim_store.rgn, fact_rx_fill.fill_id, and Sum(fact_rx_fill.proc_mins). Later, when agents rename fields, these PBIR references must change too.

Create a short note outside the repo, or use a scratch note in your editor that you don’t save into the repository. Capture at least five defects you saw. Use this list later when the model-assessor runs in Lab 06.

A good list includes:

  • Raw table and column names.
  • No descriptions.
  • Missing relationship to Medication.
  • Bidirectional Store relationship.
  • Auto date/time enabled.
  • Keys visible or summarized.
  • Processing minutes summed in the report.

You should see: your own defect list. You don’t need to commit anything.

Run this from the repo root in a PowerShell 7 terminal (Terminal > New Terminal in VS Code):

Terminal window
pwsh ./scripts/lab/Test-LabProgress.ps1 -Lab 02

When everything is done you should see:

Expected output
PASS L02-data-link C:\ContosoPharmacyDemo\data points at this repo's data\generated
PASS L02-desktop Power BI Desktop has a model open
PASS L02-clean-tree Opening the project in Desktop left no unexpected changes under fabric/
Lab 02: 3 of 3 checks passed.

Each FAIL line prints a hint and a link back to the step on this page that fixes it. The command exits with code 0 when every required check passes.

CheckWhat it looks atIf it fails
L02-data-link (Windows only)C:\ContosoPharmacyDemo\data points at this repo's data\generatedRun pwsh ./scripts/Set-LocalDataLink.ps1 Go to step 1
L02-desktop (Windows only)Power BI Desktop has a model openOpen fabric\ContosoPharmacy.pbip in Power BI Desktop and wait for the refresh to finish. Go to step 3
L02-clean-treeOpening the project in Desktop left no unexpected changes under fabric/Run git status fabric. If Desktop rewrote files, see the troubleshooting entry. Go to step 5
Refresh says the folder or CSV files can’t be found

Run pwsh ./scripts/Set-LocalDataLink.ps1 again and confirm it links C:\ContosoPharmacyDemo\data to this clone’s data\generated. If you changed the model parameter, use Home > Transform data > Edit parameters and set it back.

Power BI Desktop asks about privacy levels

Choose settings that let Desktop read local files from your machine. The data is synthetic and local. Don’t sign in to a Fabric workspace or publish anything for this lab.

Desktop rewrote files under fabric/

Close Desktop. If you only inspected the model, run git restore fabric to discard the rewrite. Later labs tell you when to keep Desktop-generated changes.

The model opens as a single model file instead of TMDL

Check File > Options and settings > Options > Preview features and enable the PBIP and TMDL options if they appear. Restart Desktop and open fabric\ContosoPharmacy.pbip again.

On macOS, the Desktop check skips or fails

That’s expected. Power BI Desktop is Windows only. The file-mode checks still let you read the model and continue with labs that don’t need Desktop.

Where is the missing Medication relationship visible in source control?

Show the answer

In relationships.tmdl, which has Date and Store relationships but no Medication relationship.

Relationships live in relationships.tmdl. The baseline has Date and Store links only, and the Store link is bidirectional.

Why is editing TMDL while Desktop is open risky?

Show the answer

Desktop keeps a model in memory and can write it back over external file edits when you save or close.

Use MCP when Desktop is open, or close Desktop before editing the files directly. Otherwise Desktop can overwrite the agent's edits.

What does PBIR store for a visual field binding?

Show the answer

Table and field references such as Entity, Property, queryRef, and nativeQueryRef.

PBIR visual.json files refer to model objects by name. Renames must update those references or the visual breaks.

You opened or inspected the baseline PBIP, mapped the weak model to TMDL, saw report visuals bound to raw names, and confirmed that fabric/ stayed clean. Next you learn how repository and path instructions shape Copilot’s answers before any custom agent runs.

Next: Lab 03: Repository and path instructions

  • Run pwsh ./scripts/Test-ModelConventions.ps1 and compare the findings with your five defects.
  • Open Expected results and look at which business questions the baseline misses. Don’t worry about memorizing answers.