Lab 06: Skills and the read-only assessor
At a glance
Section titled “At a glance”Why this matters
Section titled “Why this matters”Instructions are always on. Skills are loaded only when their description matches the task. That keeps the normal chat context smaller, while still giving agents deep guidance when they assess or change the model. In this lab the assessor loads the repo conventions, writes a structured assessment, and offers a handoff without making the fixes itself.
Concepts
Section titled “Concepts”- Skill: a folder with
SKILL.mdand optional references. Copilot reads the description first, then loads the body and references when needed. See Skills. - APM: Agent Package Manager. This repo uses it to install Microsoft’s Skills for Fabric
semantic-model-authoringskill into.agents/skills/. - Read-only by instruction: the assessor has an
edittool so it can writeout/assessment.md, but its agent instructions restrict edits to that file. - Deterministic convention check:
scripts/Test-ModelConventions.ps1readsrules/*.yamland reports rule-coded findings. The agent explains and prioritizes those findings. - Handoff: the assessor shows Fix these findings, but you do not click it until Lab 07.
Before you begin
Section titled “Before you begin”- You finished Lab 05 and
evaluation/runs/local-baseline.jsonexists. - You have VS Code open at the repo root.
- Power BI Desktop is optional here. The assessor can read TMDL files directly.
- If you skipped Lab 05, restore the checkpoint below.
Step 1. Read the repo conventions skill
Section titled “Step 1. Read the repo conventions skill”Open the skill and the data dictionary:
---name: pharmacy-model-conventionsdescription: House conventions for the Contoso Pharmacy semantic model, covering business names, descriptions, hidden keys, summarization, display folders, required relationships and measures, and the AI-readiness checklist. Use when you assess, review, or change model names, descriptions, measures, relationships, or the date table, or when you need the standard business name for a source column.---# Contoso Pharmacy model conventions
These conventions make the model easy for people and for AI tools (Power BI Copilot, Fabric data agents, and coding agents) to read. They are checked by rules C01 to C15.
The rules themselves are data, not prose. Read them from:
- `rules/naming-conventions.yaml`: name pattern, forbidden abbreviations, description length, hidden-column patterns, additive columns, raw-code columns, display folders.- `rules/required-model-objects.yaml`: required tables, relationships, date table settings, the twelve required measures by display folder, default labels, and the AI prep requirements.
## Get the current findings
Run the checker instead of reviewing by eye. It's deterministic and it's the same code the lab checks use.
```powershellpwsh ./scripts/Test-ModelConventions.ps1 # table of findingspwsh ./scripts/Test-ModelConventions.ps1 -Json # for agentspwsh ./scripts/Test-ModelConventions.ps1 -Rule C07,C08```
On macOS or Linux, `pwsh` runs the same scripts. Every finding has a rule, severity, object, finding, and fix.
## Rules
| Rule | Title | What good looks like ||---|---|---|| C01 | Business-friendly names | Title Case words with spaces. No underscores or abbreviations like `rx`, `dt`, `nm`, `qty`. Use the names in [the data dictionary](references/data-dictionary.md). || C02 | Descriptions present | Every table, visible column, and measure has a `///` description. || C03 | Description length | 20 to 200 characters. Say what it is, its grain or unit, and when to use it. || C04 | Keys and helpers hidden | Surrogate keys, foreign keys, `Fill ID`, and sort-by number columns are hidden. || C05 | Default summarization | `summarizeBy: none` everywhere except `Quantity` and `Days Supply` (sum) and `Processing Time (min)` (average). || C06 | Raw codes decoded | `Fill Type Code` (N or R) is hidden, and a visible `Fill Type` column shows New or Refill. || C07 | Required relationships | Prescription Fill to Date, Store, and Medication, many-to-one. || C08 | Single-direction filters | No bidirectional relationships. || C09 | Marked date table | `Date` has `dataCategory: Time`, and its `Date` column has `isKey`. || C10 | Auto date/time off | No `LocalDateTable` tables; `__PBI_TimeIntelligenceEnabled = 0`. || C11 | Sort-by columns | Month, Year Month, and Day of Week sort by their number columns. || C12 | Required measures | The twelve measures in `rules/required-model-objects.yaml`, with those exact names. || C13 | Measure format strings and folders | Every measure has `formatString` and a `displayFolder` from Volume, Refills, Processing, or Time Comparison. || C14 | Default labels | `Store Name` and `Medication Name` are the default labels of their tables. || C15 | Q&A and AI prep drafts | Q&A is enabled and `fabric/ai-prep/` has the five draft files. See the `prep-data-for-ai` skill. |
## Writing descriptions
A good description answers "what is this, and when do I use it?" in one or two short sentences.
- Tables: the grain and what it's for. "One row per prescription fill (new or refill) at a store."- Columns: meaning, values or unit, and anything surprising. "Minutes from intake to ready for pickup."- Measures: what it counts or computes, and the business words people use for it. Mention how it differs from similar measures.- Don't restate the name ("The store name column"). Don't mention patients; this data has none.- Stay under 200 characters. Power BI Copilot reads only the first 200.
More examples are in [references/examples.md](references/examples.md). The full AI-readiness checklist is in [references/ai-readiness-checklist.md](references/ai-readiness-checklist.md).
## Measures
- One measure, one idea. Build on base measures: `[Refills]` is `CALCULATE([Prescriptions Filled], ...)`, not a second `COUNTROWS`.- Use `DIVIDE()` for ratios so empty periods return blank instead of an error.View .github/skills/pharmacy-model-conventions/SKILL.md on GitHub
# Data dictionary
Standard business names for every source column. Rename the model object to the business name and keep `sourceColumn` set to the source name.
## Tables
| Source table | Business name | Grain ||---|---|---|| `dim_date` | Date | One row per calendar day, 2024-01-01 to 2025-12-31 || `dim_store` | Store | One row per store (12 stores, 4 regions) || `dim_med` | Medication | One row per medication product || `fact_rx_fill` | Prescription Fill | One row per prescription fill, new or refill |
## Date
| Source | Business name | Notes ||---|---|---|| `cal_dt` | Date | Key of the marked date table || `yr` | Year | Don't summarize || `qtr` | Quarter | Q1 to Q4 || `yr_qtr` | Year Quarter | For example 2025-Q4 |View .github/skills/pharmacy-model-conventions/references/data-dictionary.md on GitHub
The skill description is what gets it loaded. The references provide the details only after the skill is active.
You should see: rules C01 to C15, the command for the deterministic checker, and the standard business names: Date, Store, Medication, and Prescription Fill.
Step 2. Install the Skills for Fabric semantic-model-authoring skill
Section titled “Step 2. Install the Skills for Fabric semantic-model-authoring skill”The lab check for this step is optional, but installing the skill shows how a third-party package reaches Copilot without copying files into .github/skills/.
python -m pip install --user apm-cli==0.31.0apm --versionapm install --only apm --target copilotIf the installer asks you to confirm the package plan, read it first. It should deploy only the APM skill dependency from this repo’s apm.yml, then answer y.
/plugin marketplace add microsoft/skills-for-fabric/plugin install powerbi-authoring@fabric-collectionRun those slash commands inside GitHub Copilot CLI. The Skills for Fabric README currently recommends the powerbi-authoring bundle for semantic models, Power BI reports, and PBIP workflows.
The repo manifest pins the APM install:
# APM (Agent Package Manager) manifest for the Contoso Pharmacy lab.## Consume: installs the third-party Skills for Fabric skill this lab uses, pinned to a release.# apm install --only apm --target copilot# --only apm skips the MCP servers that Skills for Fabric declares; this repo configures its own# in .vscode/mcp.json. See Lab 06.## Publish: this lab's skills live in .github/skills (the folder the lab teaches), which APM treats# as build output, so this manifest does not export them as a package. Other repos install one# skill at a time by subdirectory instead, for example:# apm install sabajamalian/fabric-powerbi-ai-devops-demo/.github/skills/pharmacy-model-conventions# See Lab 14.name: fabric-powerbi-ai-devops-demoversion: 1.0.0description: Copilot skills, agents, and prompts for making a Power BI semantic model AI-ready, from the Contoso Pharmacy lab. Synthetic data only.license: MITrepository: https://github.com/sabajamalian/fabric-powerbi-ai-devops-demokeywords: [power-bi, tmdl, semantic-model, copilot, skills]
targets: - copilot
dependencies: apm: - git: https://github.com/microsoft/skills-for-fabric.git ref: v0.3.17lockfile_version: '1'apm_version: 0.31.0dependencies:- repo_url: microsoft/skills-for-fabric name: skills-for-fabric host: github.com resolved_commit: 65bfb5eb2c488cd03183df88f76ac3de65dcb910 resolved_ref: v0.3.17 version: 0.3.17 package_type: skill_bundle deployed_files: - .agents/skills/semantic-model-authoring - .agents/skills/semantic-model-authoring/SKILL.md - .agents/skills/semantic-model-authoring/apm.yml - .agents/skills/semantic-model-authoring/references/connection-binding.md - .agents/skills/semantic-model-authoring/references/dax-guidelines.md - .agents/skills/semantic-model-authoring/references/dax-perf-decision-guide.md - .agents/skills/semantic-model-authoring/references/dax-perf-patterns.md - .agents/skills/semantic-model-authoring/references/direct-lake-guidelines.md - .agents/skills/semantic-model-authoring/references/field-parameters.md - .agents/skills/semantic-model-authoring/references/metadata-discovery.md - .agents/skills/semantic-model-authoring/references/modeling-guidelines.md - .agents/skills/semantic-model-authoring/references/naming-conventions.md - .agents/skills/semantic-model-authoring/references/pbip.mdThen run the optional check:
pwsh ./scripts/lab/Test-LabProgress.ps1 -Lab 06 -Only L06-fabric-skillpwsh ./scripts/lab/Test-LabProgress.ps1 -Lab 06 -Only L06-fabric-skillYou should see: either PASS L06-fabric-skill with a path such as .agents/skills/semantic-model-authoring/SKILL.md, or a warning if you skipped this optional install. apm install --only apm --target copilot should not overwrite .vscode/mcp.json.
Step 3. Run the model-assessor prompt
Section titled “Step 3. Run the model-assessor prompt”- Open Copilot Chat: Ctrl+Alt+I (macOS: Ctrl+Cmd+I), or View > Chat.
- Switch to Agent mode.
- Pick model-assessor from the agent dropdown.
- Type
/assess-modeland press Enter. If VS Code asks for the optionalfocus, leave it blank. - Approve terminal commands after you read them.
The prompt is short because the agent file carries the method and output contract:
---name: assess-modeldescription: Assess the semantic model against the team conventions and AI-readiness checklist and write out/assessment.md.agent: model-assessorargument-hint: Optional focus area---Assess the Contoso Pharmacy semantic model in `fabric/ContosoPharmacy.SemanticModel/`.
${input:focus:Optional focus, or leave blank for the whole model}
1. Run `pwsh ./scripts/Test-ModelConventions.ps1 -Markdown` for the deterministic findings.2. Inspect the model through Power BI Modeling MCP if it's connected, otherwise read the TMDL files.3. Write `out/assessment.md` in the format your instructions define, with at least 8 findings.4. In chat, list the three fixes that would most improve AI answers to the business questions.## Method
1. Load the `pharmacy-model-conventions` skill. It defines rules C01 to C15 and the AI-readiness checklist.2. Run the deterministic check for the baseline list of findings: ```powershell pwsh ./scripts/Test-ModelConventions.ps1 -Markdown ```3. Look at the model yourself. If Power BI Modeling MCP is connected, use it to list tables, columns, measures, and relationships; otherwise read the `.tmdl` files. Look for problems the script can't judge: - Names that are technically valid but unclear to a business user. - Columns an AI tool would misuse, for example a minutes column it might sum. - Business questions the model can't answer without an explicit measure (month-over-month change, refill index against the chain). - Terms that need a definition in AI instructions ("latest month", "previous period", "unusually high").4. Group related findings. Forty "no description" rows are one finding per table, not forty.
## Output: out/assessment.md
```markdown# Model assessment: <date>
<Two or three sentences: overall state and the three changes that matter most.>
| # | Rule | Severity | Object | Finding | Fix ||---|---|---|---|---|---|| 1 | C01 | high | table fact_rx_fill | Raw source name; users and AI won't recognize it. | Rename to Prescription Fill. |```
- Keep the columns exactly: `#`, `Rule`, `Severity`, `Object`, `Finding`, `Fix`. The lab check reads them.- Severity is `high`, `medium`, or `low`. Sort high first.- Use `AI` in the Rule column for a finding that isn't one of C01 to C15.- Aim for 10 to 25 rows.
End your chat reply with the top three fixes and suggest the **Fix these findings** handoff.You should see: the assessor runs pwsh ./scripts/Test-ModelConventions.ps1 -Markdown, reads the model through MCP or TMDL files, and writes out/assessment.md.
Step 4. Inspect the assessment file
Section titled “Step 4. Inspect the assessment file”Open out/assessment.md in VS Code. The lab check looks for a Markdown table with at least eight findings and these columns: Rule, Severity, Object, Finding, and Fix.
Run the check:
pwsh ./scripts/lab/Test-LabProgress.ps1 -Lab 06 -Only L06-assessmentpwsh ./scripts/lab/Test-LabProgress.ps1 -Lab 06 -Only L06-assessmentThe deterministic rule set behind the assessment lives here:
# Objects the AI-ready model must contain. Read by conventions.py and the lab checks.version: 1
tables: [Date, Store, Medication, Prescription Fill]
date_table: table: Date key_column: Date data_category: Time auto_date_time: false sort_by: Month: Month Number Year Month: Year Month Number Day of Week: Day of Week Number hierarchy: name: Calendar levels: [Year, Year Quarter, Year Month, Date]
relationships: - from: ["Prescription Fill", "Fill Date"] to: ["Date", "Date"] - from: ["Prescription Fill", "Store Key"] to: ["Store", "Store Key"] - from: ["Prescription Fill", "Medication Key"] to: ["Medication", "Medication Key"]single_direction_only: true
measures: table: Prescription Fill required: Volume: [Prescriptions Filled, New Prescriptions] Refills: [Refills, Refill Rate, Refill Rate Index vs Chain, High Refill Activity Flag] Processing: [Avg Processing Time (min)] Time Comparison: [Prescriptions Filled PM, MoM Change, MoM %, Prescriptions Filled PY, YoY %]
default_labels: Store: Store Name Medication: Medication Name#Requires -Version 7.2<#.SYNOPSIS Lists where the semantic model breaks the team conventions in rules/*.yaml..DESCRIPTION Rules C01 to C15 cover names, descriptions, hidden keys, summarization, relationships, the date table, measures, display folders, and AI metadata flags. The baseline model breaks most of them on purpose. This is the deterministic check behind the model-assessor agent and Labs 07 to 09. By default it reports findings and exits 0; use -Strict to exit 1 when there are findings..PARAMETER Rule Only report these rule IDs, comma-separated, for example C01,C02..PARAMETER Json Print findings as JSON..PARAMETER Markdown Print findings as a Markdown table (Rule, Severity, Object, Finding, Fix)..PARAMETER OutFile Also write the Markdown table to this file..PARAMETER Strict Exit 1 when there are findings..EXAMPLE pwsh ./scripts/Test-ModelConventions.ps1 -Rule C01#>[CmdletBinding(PositionalBinding = $false)]param( [string[]] $Rule, [switch] $Json, [switch] $Markdown, [string] $OutFile, [switch] $Strict)
. (Join-Path $PSScriptRoot '_Common.ps1')
$Rule = @($Rule | ForEach-Object { $_ -split ',' } | ForEach-Object { $_.Trim().ToUpperInvariant() } | Where-Object { $_ })$bad = @($Rule | Where-Object { $_ -notmatch '^C\d{2}$' })You should see: PASS L06-assessment and at least eight findings in out/assessment.md. The highest-severity items should include raw names, missing descriptions, relationship/date-table problems, and missing measures.
Step 5. Ask the assessor to fix one finding
Section titled “Step 5. Ask the assessor to fix one finding”In the same model-assessor chat, type:
Fix the highest-severity finding now.The correct behavior is refusal plus a handoff. The assessor has edit, but its instructions say the only file it creates or edits is out/assessment.md:
---name: model-assessordescription: Reviews the Contoso Pharmacy semantic model against the team conventions and AI-readiness checklist, without changing it, and writes prioritized findings to out/assessment.md. Use before improving the model or to explain why AI answers are weak.argument-hint: Optional focus, for example "names only" or "measures and time intelligence"tools: ['read', 'search', 'execute', 'edit', 'todo', 'powerbi-modeling-mcp/*']handoffs: - label: Fix these findings agent: model-improver prompt: Fix the findings in out/assessment.md, highest severity first. Start with names and descriptions, and rebind the report after any rename. send: false---# Model assessor
You review the semantic model in `fabric/ContosoPharmacy.SemanticModel/` and report what makes it hard for people and AI tools to use. You don't fix anything.
## Boundaries
- The only file you create or edit is `out/assessment.md`. Never edit TMDL, PBIR, data, or evaluation files.- Don't read `evaluation/expected/` or `evaluation/questions.yaml`.- All data is synthetic. Don't speculate about real pharmacies or patients.This is an instruction boundary, not a hard tool permission. Lab 11 adds hooks that make some rules deterministic by denying forbidden edits and logging post-edit lint.
You should see: the assessor explains that it cannot edit TMDL or PBIR, summarizes what should be fixed, and points you to Fix these findings instead of changing the model.
Step 6. Leave the handoff visible for Lab 07
Section titled “Step 6. Leave the handoff visible for Lab 07”Do not click Fix these findings yet. You need the button visible because Lab 07 starts by clicking it.
If you do not see the button:
- Keep the model-assessor chat open.
- Make sure the latest assessor response finished.
- If needed, open chat history from the clock icon at the top of the Chat view and select this conversation later.
You should see: a completed model-assessor answer with the Fix these findings handoff button under it, plus out/assessment.md in the repo.
Verify your work
Section titled “Verify your work”Run this from the repo root in a PowerShell 7 terminal (Terminal > New Terminal in VS Code):
pwsh ./scripts/lab/Test-LabProgress.ps1 -Lab 06pwsh ./scripts/lab/Test-LabProgress.ps1 -Lab 06Checks marked Windows only print SKIP on macOS. SKIP doesn't count as a failure.
When everything is done you should see:
PASS L06-assessment out/assessment.md has at least 8 findings with rule, severity, object, finding, and fixPASS L06-fabric-skill Skills for Fabric semantic-model-authoring skill is installed
Lab 06: 2 of 2 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.
| Check | What it looks at | If it fails |
|---|---|---|
L06-assessment | out/assessment.md has at least 8 findings with rule, severity, object, finding, and fix | Run /assess-model with the model-assessor agent. It writes out/assessment.md. Go to step 4 |
L06-fabric-skill (optional) | Skills for Fabric semantic-model-authoring skill is installed | Run apm install (see the lab) or /plugin install powerbi-authoring@fabric-collection in Copilot CLI. Go to step 2 |
Optional checks can FAIL without failing the lab.
Troubleshooting
Section titled “Troubleshooting”apm is not recognized after pip install
pip install --user puts apm in your Python user Scripts folder, which often isn’t on PATH (pip prints a warning naming the folder). Add it for this terminal session, then run apm --version again:
$scripts = python -c "import sysconfig; print(sysconfig.get_path('scripts', sysconfig.get_preferred_scheme('user')))"$env:PATH = $scripts + [IO.Path]::PathSeparator + $env:PATHapm --versionTo make it permanent on Windows, add that folder under Settings > System > About > Advanced system settings > Environment Variables > Path for your user, then open a new terminal.
The semantic-model-authoring skill check fails
This check is optional. If you want it to pass, rerun apm install --only apm --target copilot from the repo root and check for .agents/skills/semantic-model-authoring/SKILL.md. If APM installed globally, the check also looks under your home directory.
APM changed .vscode/mcp.json
You likely missed --only apm. Restore the workspace MCP config with git restore .vscode/mcp.json, then rerun apm install --only apm --target copilot. This repo manages MCP servers itself.
The assessor writes fewer than eight findings
Ask it to rerun pwsh ./scripts/Test-ModelConventions.ps1 -Markdown and rewrite out/assessment.md with one row per grouped finding. The check reads the table shape and count, not the chat answer.
The skill does not appear to load
Ask the agent, “Which skills did you use?” Then expand the chat references. If pharmacy-model-conventions is missing, restart the chat and ask specifically to assess names, descriptions, relationships, date table, and measures against the Contoso Pharmacy conventions.
The assessor starts editing TMDL
Reject the edit. Remind it: “You are model-assessor. Your only editable file is out/assessment.md.” The restriction is in the agent instructions. Hook-enforced edit denials are covered in Lab 11.
Knowledge check
Section titled “Knowledge check”Recap and next
Section titled “Recap and next”You read a repo skill, installed the third-party Skills for Fabric authoring skill, ran a read-only assessor, and produced out/assessment.md. You also saw the assessor offer a handoff without taking edit ownership of the model. Next you click that handoff and let the improver handle names, descriptions, and report bindings.
Go further
Section titled “Go further”- Run
pwsh ./scripts/Test-ModelConventions.ps1 -Jsonand compare the machine-readable findings with the Markdown assessment. - Ask the assessor to focus only on measures, then compare the shorter assessment with the full one.
- Read
.github/skills/pharmacy-model-conventions/references/ai-readiness-checklist.mdand mark which findings affect AI answers most.
Something wrong or unclear on this page? Open a lab feedback issue. The form is prefilled with this page's name. Nothing is sent until you submit it, and please don't include screenshots of real accounts.