Add per-skill "Skill Value" view to the evaluation dashboard - #1059
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a new Skill Value view to the evaluation dashboard, backed by newly emitted per-run entries.SkillValue data, to summarize per-skill token/time deltas and not-passed telemetry per (executor model, judge model) without blending model versions.
Changes:
- Add
eng/dashboard/skill-value.jsand wire a new Skill Value dashboard tab with filtering and trailing-window aggregation. - Extend
eng/dashboard/generate-benchmark-data.ps1to emit a newentries.SkillValueblock (and add-SkillValueOnlyto avoid duplicating Quality/Efficiency points in multi-judge scenarios). - Update
.github/workflows/evaluation.ymlto group scheduled benchmark merges by(model, judgeModel)and prevent double-counting Quality/Efficiency while still emitting SkillValue per judge.
Show a summary per file
| File | Description |
|---|---|
| eng/dashboard/skill-value.js | New client-side renderer/aggregator for Skill Value rows grouped Plugin → Skill → Model, with gating and drill-down. |
| eng/dashboard/generate-benchmark-data.ps1 | Emits new entries.SkillValue per scheduled run; adds -SkillValueOnly to dedupe Q/E when needed. |
| eng/dashboard/dashboard.js | Adds a Skill Value tab as the default landing view and hooks tab switching to initSkillValue(). |
| eng/dashboard/dashboard.html | Adds CSS for the Skill Value view and loads skill-value.js. |
| .github/workflows/evaluation.yml | Groups merged results by (model, judgeModel) and passes -SkillValueOnly for second+ judges per executor model. |
Review details
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
- Files reviewed: 5/5 changed files
- Comments generated: 1
- Review effort level: Lite
|
👋 @AbhitejJohn — this PR has 1 unresolved review thread(s),merge conflict. When you're ready, please address the feedback and push an update; the triage bot will pick up the next state automatically. (Add the |
3919e0d to
cc81406
Compare
Adds a Plugin -> Skill -> Model "Skill Value" tab that surfaces, per skill, the token and time a skill saves and how often scenarios pass without it. Reuses the existing publish-eval-data job by emitting an entries.SkillValue block from generate-benchmark-data.ps1 (no new job, no adapter change). Fixes in this change: - Quality/Efficiency stay one entry per executor model per run. The scheduled benchmark merge now groups by (model, judge) for Skill Value, but passes -SkillValueOnly for the second+ judge of a model so dual-judge runs no longer duplicate same-model Quality/Efficiency points. - Pass telemetry is labelled honestly. adapt.mjs notes the per-arm pass booleans may include LLM-grader results, so the field is hasPassData (not hasDeterministic), the column reads "Not-passed", and the claim reads "do not pass their checks" with a tooltip caveat rather than an objective failure gate. - Single-model groups show that model's real deltas; multi-model rollups read "N model/judge result(s) show measured value" instead of an ambiguous 0/m. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: e23e5efe-713f-4898-a158-8970f70fdcaf
- Load skill-value.js (and token-usage.js) before dashboard.js so window.initSkillValue exists when the default Skill Value tab renders on first load; previously the fallback activated the first plugin tab instead. - Aggregate key now includes the plugin, so two plugins that share a skill name no longer blend histories (the view is grouped Plugin -> Skill -> Model). - valueSentence distinguishes "not-passed rate still gathering data" (pass checks present but below the gate) from "No pass/fail data" (no boolean graders), and describes the unit as counted trials rather than scenarios. - Document that only the primary judge (vally-results-*) feeds benchmark data; the dual-judge re-score (vally-crossjudge-*) feeds only judge-comparison.json, so Skill Value and Quality/Efficiency both reflect the primary judge. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: e23e5efe-713f-4898-a158-8970f70fdcaf
cc81406 to
1daa976
Compare
There was a problem hiding this comment.
Review details
Suppressed comments (1)
eng/dashboard/skill-value.js:276
pctSigned()also formats a zero reduction as "+0%". For consistency with the leaf rows and to avoid implying direction when there’s no change, format 0 as "0%".
function pctSigned(r) { return r == null ? 'n/a' : `${r > 0 ? '−' : '+'}${Math.abs(r * 100).toFixed(0)}%`; }
- Files reviewed: 5/5 changed files
- Comments generated: 3
- Review effort level: Lite
|
❌ Evaluation did not complete successfully (the evaluate job reported 52 partial result file(s) were preserved for diagnosis but were not consolidated because the full matrix did not complete. |
- Drill-down paired-observation count now uses min(baseline.n, treatment.n), matching the table's paired-n, so inconsistent or legacy entries cannot overstate the paired sample size. - signedPct helper renders an exact-or-rounded zero reduction as "0%" with no sign, so "no change" no longer reads as a "+0%" regression (deltaCell and the rollup percent both use it). - When skill-value.js is present but there are no evaluation plugins, fall back to the Token Usage tab instead of leaving the page on the Skill Value panel's permanent "Loading...". Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: e23e5efe-713f-4898-a158-8970f70fdcaf
There was a problem hiding this comment.
Review details
Suppressed comments (2)
Previously missed (2) — in code that hasn't changed since the last review.
eng/dashboard/skill-value.js:208
- The inline comment about when
row.activationisnullis backwards/misleading.row.activationis set tonullwhenactivationExpected === 0, which means no scenarios were expected to activate the skill (e.g., all stimuli wereexpectActivation:false), not that no scenario declared the annotation. This can confuse future readers interpreting the gating logic.
// delta is diluted — so suppress the confident value claim. A null activation
// means NO scenario declared expect_activation, so we cannot confirm the skill
// fired at all; treat that as unverified rather than asserting value.
eng/dashboard/skill-value.js:258
metricCelltakes a third parameter (fmt) that is never used. This makes the call sites look like formatting affects the output when it doesn’t. If you want to keep the signature stable, prefix the unused parameter with_to make the intent clear.
function metricCell(base, treat, fmt) {
// Delta cell already shows both arms; this is the paired-n column.
const n = Math.min(base ? base.n : 0, treat ? treat.n : 0);
const cls = gated(n) ? 'neutral' : 'sv-insufficient';
return `<td class="num"><span class="${cls}">n=${n}</span></td>`;
- Files reviewed: 5/5 changed files
- Comments generated: 0 new
- Review effort level: Lite
|
❌ Evaluation did not complete successfully (the evaluate job reported 22 partial result file(s) were preserved for diagnosis but were not consolidated because the full matrix did not complete. |
|
/evaluate f71cddd |
📊 Skill Evaluation Results10 model/skill results across 5 skills and 2 models — ✅ 0 improved, ➖ 0 not proven improved, Measurement identity: evaluated commit Measurement health: 10 expected / 10 observed / 10 written; 0 missing, 0 unexpected, 10 invalid; 0 recovered comparison error slots and 0 unresolved comparison error slots. Objective completion gate: not enabled. Aggregate completion transitions are telemetry only, so this report does not claim that zero objective regressions were proven. A result passes only when the aggregate net win across distinct-stimulus votes is at least 20% and an exact one-sided sign-test result of
ℹ️ How to read this report
|
| Scenario | Net win | Δ Pref | Runs (W/T/L) |
|---|---|---|---|
| = Propagate trace context across a message queue | +0.0% | +0.0% | 0/1/0 |
| ▼ Set up OpenTelemetry tracing and metrics with custom spans in ASP.NET Core | -100.0% | -40.0% | 0/0/1 |
Illustrative judge evidence:
Propagate trace context across a message queue:Position-swap inconsistent (forward: A, reverse: B). Defaulting to tie.
This is one example, not the aggregate verdict. Open Full Results for every judgment.
⚠️ Underpowered — configuring-opentelemetry-dotnet (gpt-5.6-luna)
Why: Net win +100.0% (3W/0T/0L over 3 stimulus vote(s), sign test p=0.125), mean preference +40.0% across 3 paired run(s) — underpowered (3 counted stimulus vote(s); a credible verdict needs at least 5, and this eval won every one of them) — add distinct, discriminating stimuli; repeated runs do not increase task breadth
Next action: Predeclare more independent, discriminating stimuli; repeated runs do not add power.
State: INVALID_INCONCLUSIVE (underpowered)
Gate evidence: n=3; 3W/0T/0L; d=3; p=0.125; net +100.0%
Overfit: Low (score 0.15)
Repeated-run reliability (not used by the gate): 3 paired runs (3W/0T/0L).
⚠️ Underpowered — convert-blazor-server-to-webapp (claude-sonnet-4.6)
Why: Net win +100.0% (1W/0T/0L over 1 stimulus vote(s), sign test p=0.500), mean preference +100.0% across 1 paired run(s) — underpowered (1 counted stimulus vote(s); a credible verdict needs at least 5, and this eval won every one of them) — add distinct, discriminating stimuli; repeated runs do not increase task breadth
Next action: Predeclare more independent, discriminating stimuli; repeated runs do not add power.
State: INVALID_INCONCLUSIVE (underpowered)
Gate evidence: n=1; 1W/0T/0L; d=1; p=0.500; net +100.0%
Overfit: Low (score 0.07)
Repeated-run reliability (not used by the gate): 1 paired run (1W/0T/0L).
⚠️ Underpowered — convert-blazor-server-to-webapp (gpt-5.6-luna)
Why: Net win +100.0% (1W/0T/0L over 1 stimulus vote(s), sign test p=0.500), mean preference +100.0% across 1 paired run(s) — underpowered (1 counted stimulus vote(s); a credible verdict needs at least 5, and this eval won every one of them) — add distinct, discriminating stimuli; repeated runs do not increase task breadth
Next action: Predeclare more independent, discriminating stimuli; repeated runs do not add power.
State: INVALID_INCONCLUSIVE (underpowered)
Gate evidence: n=1; 1W/0T/0L; d=1; p=0.500; net +100.0%
Overfit: Low (score 0.06)
Repeated-run reliability (not used by the gate): 1 paired run (1W/0T/0L).
⚠️ Underpowered — dotnet-webapi (claude-sonnet-4.6)
Why: Net win +33.3% (2W/0T/1L over 3 stimulus vote(s), sign test p=0.500), mean preference +53.3% across 3 paired run(s) — underpowered (3 counted stimulus vote(s); a credible verdict needs at least 5) — add distinct, discriminating stimuli; repeated runs do not increase task breadth
Next action: Predeclare more independent, discriminating stimuli; repeated runs do not add power.
State: INVALID_INCONCLUSIVE (underpowered)
Gate evidence: n=3; 2W/0T/1L; d=3; p=0.500; net +33.3%
Overfit: High (score 0.66)
Repeated-run reliability (not used by the gate): 3 paired runs (2W/0T/1L).
Weak or warning scenarios:
| Scenario | Net win | Δ Pref | Runs (W/T/L) |
|---|---|---|---|
| ▼ Add error handling with ProblemDetails and IExceptionHandler | -100.0% | -40.0% | 0/0/1 |
Illustrative judge evidence:
Add error handling with ProblemDetails and IExceptionHandler:A is a complete, directly usable answer with the full handler and wiring, exact mappings, logging, and explicit 500 detail suppression. B's final response is only a summary of files it says it created, so the user cannot actually implement the solution from the answer; its sta...
This is one example, not the aggregate verdict. Open Full Results for every judgment.
⚠️ Underpowered — dotnet-webapi (gpt-5.6-luna)
Why: Net win +66.7% (2W/1T/0L over 3 stimulus vote(s), sign test p=0.250), mean preference +46.7% across 3 paired run(s) — underpowered (3 counted stimulus vote(s); a credible verdict needs at least 5) — add distinct, discriminating stimuli; repeated runs do not increase task breadth
Next action: Predeclare more independent, discriminating stimuli; repeated runs do not add power.
State: INVALID_INCONCLUSIVE (underpowered)
Gate evidence: n=3; 2W/1T/0L; d=2; p=0.250; net +66.7%
Overfit: Moderate (score 0.32)
Repeated-run reliability (not used by the gate): 3 paired runs (2W/1T/0L).
Weak or warning scenarios:
| Scenario | Net win | Δ Pref | Runs (W/T/L) |
|---|---|---|---|
| = Add a new API endpoint to an existing controller-based project | +0.0% | +0.0% | 0/1/0 |
Illustrative judge evidence:
Add a new API endpoint to an existing controller-based project:Both agents investigated the workspace, found it effectively empty (only a skill file in B's case), and declined to produce any code rather than fabricating a solution. Neither meets any rubric criterion since no controller, DTOs, or endpoints were written. Their behavior and ...
This is one example, not the aggregate verdict. Open Full Results for every judgment.
⚠️ Underpowered — minimal-api-file-upload (claude-sonnet-4.6)
Why: Net win +100.0% (3W/0T/0L over 3 stimulus vote(s), sign test p=0.125), mean preference +60.0% across 3 paired run(s) — underpowered (3 counted stimulus vote(s); a credible verdict needs at least 5, and this eval won every one of them) — add distinct, discriminating stimuli; repeated runs do not increase task breadth
Next action: Predeclare more independent, discriminating stimuli; repeated runs do not add power.
State: INVALID_INCONCLUSIVE (underpowered)
Gate evidence: n=3; 3W/0T/0L; d=3; p=0.125; net +100.0%
Overfit: Moderate (score 0.40)
Repeated-run reliability (not used by the gate): 3 paired runs (3W/0T/0L).
⚠️ Underpowered — minimal-api-file-upload (gpt-5.6-luna)
Why: Net win +66.7% (2W/1T/0L over 3 stimulus vote(s), sign test p=0.250), mean preference +26.7% across 3 paired run(s) — underpowered (3 counted stimulus vote(s); a credible verdict needs at least 5) — add distinct, discriminating stimuli; repeated runs do not increase task breadth
Next action: Predeclare more independent, discriminating stimuli; repeated runs do not add power.
State: INVALID_INCONCLUSIVE (underpowered)
Gate evidence: n=3; 2W/1T/0L; d=2; p=0.250; net +66.7%
Overfit: Low (score 0.10)
Repeated-run reliability (not used by the gate): 3 paired runs (2W/1T/0L).
Weak or warning scenarios:
| Scenario | Net win | Δ Pref | Runs (W/T/L) |
|---|---|---|---|
| = Stream very large file uploads without buffering | +0.0% | +0.0% | 0/1/0 |
Illustrative judge evidence:
Stream very large file uploads without buffering:Position-swap inconsistent (forward: A, reverse: B). Defaulting to tie.
This is one example, not the aggregate verdict. Open Full Results for every judgment.
⚠️ Underpowered — setup-local-sdk (claude-sonnet-4.6)
Why: Net win +100.0% (3W/0T/0L over 3 stimulus vote(s), sign test p=0.125), mean preference +80.0% across 3 paired run(s) — underpowered (3 counted stimulus vote(s); a credible verdict needs at least 5, and this eval won every one of them) — add distinct, discriminating stimuli; repeated runs do not increase task breadth
Next action: Predeclare more independent, discriminating stimuli; repeated runs do not add power.
State: INVALID_INCONCLUSIVE (underpowered)
Gate evidence: n=3; 3W/0T/0L; d=3; p=0.125; net +100.0%
Overfit: Moderate (score 0.26)
Repeated-run reliability (not used by the gate): 3 paired runs (3W/0T/0L).
⚠️ Underpowered — setup-local-sdk (gpt-5.6-luna)
Why: Net win +66.7% (2W/1T/0L over 3 stimulus vote(s), sign test p=0.250), mean preference +46.7% across 3 paired run(s) — underpowered (3 counted stimulus vote(s); a credible verdict needs at least 5) — add distinct, discriminating stimuli; repeated runs do not increase task breadth
Next action: Predeclare more independent, discriminating stimuli; repeated runs do not add power.
State: INVALID_INCONCLUSIVE (underpowered)
Gate evidence: n=3; 2W/1T/0L; d=2; p=0.250; net +66.7%
Overfit: Low (score 0.15)
Repeated-run reliability (not used by the gate): 3 paired runs (2W/1T/0L).
Weak or warning scenarios:
| Scenario | Net win | Δ Pref | Runs (W/T/L) |
|---|---|---|---|
| = Create team install scripts | +0.0% | +0.0% | 0/1/0 |
Illustrative judge evidence:
Create team install scripts:Position-swap inconsistent (forward: B, reverse: A). Defaulting to tie.
This is one example, not the aggregate verdict. Open Full Results for every judgment.
🔍 Full Results - all metrics and investigation details
To investigate non-passing or warning results, paste this to your AI coding agent:
For PR 1059 in dotnet/skills, download eval artifacts with
gh run download 33053413438 --repo dotnet/skills --pattern "vally-results-*" --dir ./eval-results, then fetch https://raw.githubusercontent.com/dotnet/skills/f71cddd4a77ee327b2d5ddb0411034107be8dbbc/eng/vally-adapter/InvestigatingResults.md and follow it. Classify each result as measurement-invalid, underpowered, not-proven, preference-loss, or passing-with-warning. Use stateReason, result accounting, weak scenarios, and judge evidence to give the cause and exact next fix.
▶ Sessions Visualisation -- interactive replay of all evaluation sessions
📊 Session Analytics (preview) -- aggregated metrics across evaluation sessions
Evangelink
left a comment
There was a problem hiding this comment.
Reviewed the full change set and found no actionable issues.
|
❌ Evaluation did not complete successfully (the evaluate job reported 34 partial result file(s) were preserved for diagnosis but were not consolidated because the full matrix did not complete. |
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 032f6f50-dd65-4805-b7af-78755f8bbc77
Skill Coverage Report
Uncovered:
|
|
/evaluate 09e5bab |
There was a problem hiding this comment.
Review details
Suppressed comments (1)
Previously missed (1) — in code that hasn't changed since the last review.
eng/dashboard/skill-value.js:235
- The N/A tooltip is too definitive:
hasPassDatais false when there were no counted (baselinePassed/treatmentPassed) booleans, which can happen not only when a skill has no boolean graders, but also when all trials errored or pass booleans were missing. Reword the tooltip so it describes the observed condition rather than asserting the cause.
function failureCell(row) {
if (!row.hasPass || row.passTotal === 0) return '<td class="num" title="No pass/fail data — skill has no boolean graders">N/A</td>';
if (!gated(row.passTotal)) return `<td class="num"><span class="sv-insufficient">n=${row.passTotal}</span></td>`;
- Files reviewed: 6/6 changed files
- Comments generated: 0 new
- Review effort level: Lite
Describe the observed absence of counted pass data without assuming that a skill has no boolean graders. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5b4ee7ec-7244-4668-a151-5abee0ef2c4a
|
/evaluate bce81f3 |
📊 Skill Evaluation Results2 model/skill results across 1 skill and 2 models — ✅ 2 improved, ➖ 0 not proven improved, Measurement identity: evaluated commit Measurement health: 2 expected / 2 observed / 2 written; 0 missing, 0 unexpected, 0 invalid; 0 recovered comparison error slots and 0 unresolved comparison error slots. Objective completion gate: not enabled. Aggregate completion transitions are telemetry only, so this report does not claim that zero objective regressions were proven. A result passes only when the aggregate net win across distinct-stimulus votes is at least 20% and an exact one-sided sign-test result of
ℹ️ How to read this report
✅ Improved — grade-tests (claude-sonnet-4.6)Why: Net win +100.0% (8W/0T/0L over 8 stimulus vote(s), sign test p=0.004), mean preference +86.7% across 24 paired run(s) — credibly better Next action: Review overfit evidence. State: Gate evidence: n=8; 8W/0T/0L; d=8; p=0.004; net +100.0% Overfit: High (score 0.59) Repeated-run reliability (not used by the gate): 24 paired runs (23W/0T/1L). ✅ Improved — grade-tests (gpt-5.6-luna)Why: Net win +100.0% (8W/0T/0L over 8 stimulus vote(s), sign test p=0.004), mean preference +68.3% across 24 paired run(s) — credibly better Next action: Review overfit evidence. State: Gate evidence: n=8; 8W/0T/0L; d=8; p=0.004; net +100.0% Overfit: Moderate (score 0.39) Repeated-run reliability (not used by the gate): 24 paired runs (23W/1T/0L). 🔍 Full Results - all metrics and investigation details ▶ Sessions Visualisation -- interactive replay of all evaluation sessions |
|
❌ Evaluation did not complete successfully (the evaluate job reported 12 partial result file(s) were preserved for diagnosis but were not consolidated because the full matrix did not complete. |
📊 Skill Evaluation Results2 model/skill results across 1 skill and 2 models — ✅ 2 improved, ➖ 0 not proven improved, Measurement identity: evaluated commit Measurement health: 2 expected / 2 observed / 2 written; 0 missing, 0 unexpected, 0 invalid; 0 recovered comparison error slots and 0 unresolved comparison error slots. Objective completion gate: not enabled. Aggregate completion transitions are telemetry only, so this report does not claim that zero objective regressions were proven. A result passes only when the aggregate net win across distinct-stimulus votes is at least 20% and an exact one-sided sign-test result of
ℹ️ How to read this report
✅ Improved — grade-tests (claude-sonnet-4.6)Why: Net win +100.0% (8W/0T/0L over 8 stimulus vote(s), sign test p=0.004), mean preference +81.7% across 24 paired run(s) — credibly better Next action: Review overfit evidence. State: Gate evidence: n=8; 8W/0T/0L; d=8; p=0.004; net +100.0% Overfit: Moderate (score 0.35) Repeated-run reliability (not used by the gate): 24 paired runs (23W/0T/1L). ✅ Improved — grade-tests (gpt-5.6-luna)Why: Net win +100.0% (8W/0T/0L over 8 stimulus vote(s), sign test p=0.004), mean preference +72.5% across 24 paired run(s) — credibly better Next action: Review overfit evidence. State: Gate evidence: n=8; 8W/0T/0L; d=8; p=0.004; net +100.0% Overfit: Moderate (score 0.44) Repeated-run reliability (not used by the gate): 24 paired runs (24W/0T/0L). 🔍 Full Results - all metrics and investigation details ▶ Sessions Visualisation -- interactive replay of all evaluation sessions |
|
❌ Evaluation did not complete successfully (the evaluate job reported 39 partial result file(s) were preserved for diagnosis but were not consolidated because the full matrix did not complete. |
Adds a Skill Value tab to the eval dashboard answering, per skill: "Add this skill and model X uses ~M% fewer tokens and ~Y% less time for typical scenarios; without it ~p% of those scenarios do not pass their checks." Rows are grouped Plugin -> Skill -> Model and filterable by executor and judge model, with a trailing average over the last 20 CI runs keyed by (skill, executor, judge) so model versions never blend.
Data
Reuses the existing
publish-eval-datajob by emitting a newentries.SkillValueblock fromgenerate-benchmark-data.ps1— no new job, no adapter change. Both arms (baseline = without skill, treatment = with skill) come straight from the verdict the adapter already produces.entries.SkillValueis scheduled-only.Guardrails
nalways visible; tokens headline = input+output (cache in drill-down).Correctness & integrity (this PR)
-SkillValueOnlyfor the second+ judge of an executor, so dual-judge runs keep exactly one Quality/Efficiency point per model per run (no duplicated/inflated trailing windows).hasDeterministic->hasPassData; the column reads "Not-passed"; the sentence reads "do not pass their checks" with a caveat tooltip — becauseadapt.mjsstates these pass booleans may include LLM-grader results.0/m; Skill Value is the first tab.Validation
node --checkclean on both JS, PowerShell parse clean on the generator,actionlint1.7.7 clean on the workflow. Rendered locally against a two-plugin fixture (gate, N/A, dilution, single-model rollup, and value cases).Known limitations (not fixed here)
Preview
Fixture-rendered preview using the production dashboard code and styles (sample data):
cc @AbhitejJohn