Lab 10: question-tester, after
At a glance
Section titled “At a glance”Why this matters
Section titled “Why this matters”You improved names, relationships, measures, and AI metadata. Now you measure whether those changes helped. The question-tester agent answers the same five questions from Lab 05, writes another run file, and lets the grader score it the same way. This is still an agent run, so wording and sometimes a point can vary, but the AI-ready model should score clearly higher than the baseline.
Concepts
Section titled “Concepts”- After run: a second graded question run against the AI-ready model. The label in this lab is
local-ai-ready. - Rubric: deterministic scoring against expected rows. It checks answer data, not explanation style. See Evaluation methodology.
- Run variance: agent answers can differ between runs. The comparison is useful because the same grader and same questions are used before and after.
- Deterministic DAX tests: the Lab 08 DAX tests exist because agent runs vary. They run fixed DAX queries against Desktop and don’t rely on agent judgment.
Before you begin
Section titled “Before you begin”- You finished Lab 09, or restored
lab09-complete. - Power BI Desktop is open with
fabric\ContosoPharmacy.pbipand the model is refreshed. - The Power BI Modeling MCP server is running in VS Code.
evaluation/runs/local-baseline.jsonexists from Lab 05 and has agradeblock.
Step 1. Read the tester and comparison prompts
Section titled “Step 1. Read the tester and comparison prompts”Open the two prompt files so you know what the agent is allowed to do.
- Open Quick Open: Ctrl+P, or Go > Go to File.
- Open
.github/prompts/answer-business-questions.prompt.md. - Open
.github/prompts/compare-question-runs.prompt.md. - Open
evaluation/rubric.md.
The answer prompt requires Desktop and MCP, and it tells the agent not to make up numbers:
Answer the Contoso Pharmacy business questions against the model open in Power BI Desktop.
Run label: `${input:label:local-baseline or local-ai-ready}`
1. List the questions with `pwsh ./scripts/Get-BusinessQuestions.ps1`.2. Answer each one with a DAX query through Power BI Modeling MCP. Record your assumptions.3. Save `evaluation/runs/${input:label}.json` in the format from the `business-question-evaluation` skill.4. Grade it with `pwsh ./scripts/Grade-QuestionRun.ps1 -Run ${input:label}`.5. Report the score per question.
If Power BI Desktop or the MCP server isn't available, stop and tell me. Don't make up numbers.View .github/prompts/answer-business-questions.prompt.md on GitHub
The comparison prompt has no paraphrase flag. It compares two graded run files:
Compare two question runs.
- Before: `${input:before:local-baseline}`- After: `${input:after:local-ai-ready}`
1. Run `pwsh ./scripts/Compare-QuestionRuns.ps1 -Before ${input:before} -After ${input:after}`.2. Read `out/question-comparison.md` and both run files.3. For each question whose score changed, name the model change that most likely caused it (a measure, a description, an AI instruction, a relationship). Point to the file.4. For any question still below 2, suggest the next change to try.
Agent answers vary between runs, so say when a one-point change could be noise.View .github/prompts/compare-question-runs.prompt.md on GitHub
You should see: the prompt saves evaluation/runs/<label>.json, then runs Grade-QuestionRun.ps1.
Step 2. Run question-tester on the AI-ready model
Section titled “Step 2. Run question-tester on the AI-ready model”- In Power BI Desktop, select Home > Refresh and wait for refresh to finish.
- In VS Code, open Copilot Chat: Ctrl+Alt+I, or View > Chat.
- Pick question-tester from the agent dropdown.
- Type
/answer-business-questions label=local-ai-readyand press Enter. - Approve DAX query tool calls after you read them.
- If the agent asks to read
evaluation/expected/orevaluation/questions.yaml, deny it and remind it to usepwsh ./scripts/Get-BusinessQuestions.ps1.
The evaluation skill explains the honest path:
## Rules that keep the test honest
- Get the questions only from `pwsh ./scripts/Get-BusinessQuestions.ps1` (add `-Json` for machine output). It prints the ID, the question, paraphrases, and the `answer_columns` you must use.- Never read `evaluation/expected/`, `evaluation/questions.yaml`, `tools/python/pharmacy_demo/modelgen/`, or `tools/python/pharmacy_demo/samples.py`, and never run `pharmacy_demo dax-queries`. They contain the answers. The repo's hooks deny these.- Answer from the model as it is now. On the baseline model, use the names you find (for example `fact_rx_fill`), and don't fix the model first. A low baseline score is the expected result.- Don't write the `grade` block. Only the grader writes it.
## Step 1. Answer each question
For each question:
1. Decide the interpretation. If the question is ambiguous (which month is "latest", what "unusually high" means), write your choice in `assumptions`.2. Write one DAX query that returns exactly the `answer_columns`, one row per expected key. Use `EVALUATE` with `SUMMARIZECOLUMNS` or `ADDCOLUMNS`, and add `ORDER BY`.3. Run it with Power BI Modeling MCP (`dax_query_operations`) against the model open in Power BI Desktop.4. Copy the result rows into the run file. Rename the keys to the `answer_columns` names.
If Power BI Desktop isn't available (macOS, Linux, or the cloud agent), stop and say so. Don't invent numbers. The learner can use the sample runs in `evaluation/runs/sample-*.json` instead.View .github/skills/business-question-evaluation/SKILL.md on GitHub
You should see: evaluation/runs/local-ai-ready.json with five answers, DAX, assumptions, rows, and a grade block. The agent reports a score per question after running pwsh ./scripts/Grade-QuestionRun.ps1 -Run local-ai-ready.
Step 3. Compare baseline and AI-ready runs
Section titled “Step 3. Compare baseline and AI-ready runs”Run the comparison prompt or the script directly. The lab check looks for both a higher AI-ready score and out/question-comparison.md.
pwsh ./scripts/Compare-QuestionRuns.ps1 -Before local-baseline -After local-ai-readyThe script writes to out/question-comparison.md by default:
#Requires -Version 7.2<#.SYNOPSIS Compares two graded question runs and writes a Markdown before-and-after table..PARAMETER Before Run label or path for the earlier run, for example local-baseline..PARAMETER After Run label or path for the later run, for example local-ai-ready..PARAMETER OutFile Where to write the table. Default: out/question-comparison.md..EXAMPLE pwsh ./scripts/Compare-QuestionRuns.ps1 -Before local-baseline -After local-ai-ready.EXAMPLE pwsh ./scripts/Compare-QuestionRuns.ps1 -Before sample-baseline -After sample-ai-ready#>[CmdletBinding(PositionalBinding = $false)]param( [Parameter(Mandatory)] [string] $Before, [Parameter(Mandatory)] [string] $After, [string] $OutFile)
. (Join-Path $PSScriptRoot '_Common.ps1')if (-not $OutFile) { $OutFile = Join-Path (Get-RepoRoot) 'out' 'question-comparison.md' }$target = [System.IO.Path]::GetFullPath($OutFile, (Get-Location).Path)exit (Invoke-PharmacyDemo compare --before $Before --after $After --out $target)You should see: out/question-comparison.md with a before and after table. The total score for local-ai-ready should be higher than local-baseline. Q02, Q04, and Q05 should show the clearest improvement.
Step 4. Read the score, not just the prose
Section titled “Step 4. Read the score, not just the prose”Open the comparison and both run files.
- Open
out/question-comparison.md. - Open
evaluation/runs/local-baseline.json. - Open
evaluation/runs/local-ai-ready.json. - Compare the
grade.by_questionblocks before you compare answer text.
The rubric is strict about rows and values:
# Answer quality rubric
Each question in `questions.yaml` is scored 0, 1, or 2 by `scripts/Grade-QuestionRun.ps1`. A run's total is the sum across questions (10 points for the five questions).
| Score | Meaning | How the grader decides ||---|---|---|| 2 | Correct | Every expected row is present, keys match exactly (case and spacing ignored), every value is within the question's tolerance, and there are no extra rows. For `ranking` questions the order also matches. || 1 | Partially correct | The full check fails, but the question's `partial` rule passes (see below). || 0 | Wrong or missing | Neither check passes, or the answer is missing. |
## Partial credit rules
| Rule | Passes when ||---|---|| `row_fraction` | At least `min` of the expected rows are present with correct values. || `top_key` | The first row's key matches the expected first row (for example, the right slowest store). || `any_key` | At least one expected key is present and no more than one unexpected key is returned. || `column_match` | The named column matches the expected value (for example, the right December total with the wrong comparison). |
## Matching rules
- Column names are matched after lowercasing and replacing spaces and punctuation with `_`. The agent should still use the `answer_columns` names.- Percent and rate columns (`*_pct`, `*_rate`, `*_index`) accept either a fraction (0.25) or a percentage (25). The grader normalizes.- Numbers within tolerance count as equal. Tolerances live in `questions.yaml`.
## Human override
A reviewer can add `grade_override: { score, reason }` to an answer in a run file when the grader is too strict or too lenient, for example when the agent stated a reasonable alternative interpretation. The grader reports overrides separately so they're visible in the comparison table.
## What this rubric doesn't measure
It measures whether the answer matches the default interpretation in the question set. It doesn't score explanation quality, DAX style, or speed. Agent output varies between runs, so compare at least two runs per model state before drawing conclusions.The committed sample results show the pattern you should expect:
| Question | Typical baseline | Typical AI-ready |
|---|---|---|
| Q01 | 2 | 2 |
| Q02 | 0 | 2 |
| Q03 | 1 | 2 |
| Q04 | 0 | 2 |
| Q05 | 0 | 2 |
You should see: Q02 improves after the Medication relationship and time-comparison measures, Q03 improves after average processing time, Q04 improves after the refill index definition, and Q05 improves after previous period is defined.
Step 5. Account for run variance
Section titled “Step 5. Account for run variance”Run variance is expected because the agent chooses DAX and interpretations. Don’t overreact to a one-point wobble.
- Ask question-tester:
Explain any question in local-ai-ready that scored below 2. Point to the model change that would help. - If one score looks surprising, run the after test a second time with a different local label.
# Optional second run. The prompt supports labels, not a paraphrase flag.# In chat: /answer-business-questions label=local-ai-ready-2pwsh ./scripts/Grade-QuestionRun.ps1 -Run local-ai-ready-2pwsh ./scripts/Compare-QuestionRuns.ps1 -Before local-ai-ready -After local-ai-ready-2 -OutFile out/question-variance.mdYou should see: two AI-ready runs that are close. If they differ, the assumptions field usually explains why. The deterministic proof still comes from the Lab 08 DAX tests, not from repeated agent runs.
Step 6. Keep the local outputs local
Section titled “Step 6. Keep the local outputs local”The files this lab creates are for your machine. Don’t commit them unless a maintainer asks for a sample.
git status --short evaluation/runs outYou should see: local-ai-ready.json and out/question-comparison.md may appear as ignored or untracked local output, depending on your Git settings. Your model files should be unchanged after this lab.
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 10pwsh ./scripts/lab/Test-LabProgress.ps1 -Lab 10Checks marked Windows only print SKIP on macOS. SKIP doesn't count as a failure.
When everything is done you should see:
PASS L10-after-run evaluation/runs/local-ai-ready.json exists and is gradedPASS L10-improved local-ai-ready scores higher than local-baselinePASS L10-comparison out/question-comparison.md exists
Lab 10: 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.
| Check | What it looks at | If it fails |
|---|---|---|
L10-after-run | evaluation/runs/local-ai-ready.json exists and is graded | Run question-tester with label local-ai-ready, then Grade-QuestionRun.ps1. Go to step 2 |
L10-improved | local-ai-ready scores higher than local-baseline | Compare the runs with pwsh ./scripts/Compare-QuestionRuns.ps1 and review the failed questions. Go to step 3 |
L10-comparison | out/question-comparison.md exists | Run pwsh ./scripts/Compare-QuestionRuns.ps1 -Before local-baseline -After local-ai-ready. Go to step 3 |
Troubleshooting
Section titled “Troubleshooting”The agent says Desktop or MCP isn’t available
Open fabric\ContosoPharmacy.pbip in Power BI Desktop, refresh it, and start the Power BI Modeling MCP server from Ctrl+Shift+P > MCP: List Servers. Then rerun /answer-business-questions label=local-ai-ready.
The run file has no grade block
Run pwsh ./scripts/Grade-QuestionRun.ps1 -Run local-ai-ready. The evaluation instructions say the grader writes the grade block, not the agent by hand.
The comparison says AI-ready did not improve
Open both run files and check labels first. If the labels are right, read each failed question’s assumptions. A wrong latest month, summed processing minutes, or missing refill threshold means the agent didn’t use the AI-ready metadata. Ask it to answer again and cite the measure or instruction it used.
I want to test paraphrases
Each question in evaluation/questions.yaml lists paraphrases (see Business questions). Ask the question-tester one of them in chat, for example “Which categories grew or shrank the most last month?”, and compare its DAX with the graded run. The grader and the Lab 10 check only score the main wording, so treat this as exploration.
Knowledge check
Section titled “Knowledge check”Recap and next
Section titled “Recap and next”You reran the same business questions against the AI-ready model, graded the after run, and compared it with the Lab 05 baseline. You also saw why deterministic tests and agent-based evaluation answer different questions. Next you run the same customization stack in Copilot CLI and watch hooks enforce guardrails.
Go further
Section titled “Go further”- Run one exploratory after test with paraphrased prompts, then compare its assumptions with
local-ai-ready. - Ask model-reviewer to explain any remaining score below 2 and classify it as a model gap, instruction gap, or agent variance.
- Open Expected results and compare your score pattern with the committed sample.
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.