Fix dotnet-test plugin timeout + skill activation issues - #875
Conversation
Activation: - filter-syntax eval: both scenarios set expect_activation: false. The skill is a reference skill (disable-model-invocation/user-invocable false) loaded by run-tests/mtp-hot-reload; it can never self-activate — this was an eval mis-spec, not a skill bug. - writing-mstest-tests 'Fix swapped Assert.AreEqual arguments': expect_activation false. The rubric requires diagnosing the root cause unaided, so no invocation is expected (notActivated 11/11 both arms). - test-smell-detection: relax the over-restrictive 'INVOKE ONLY when explicitly asked for the testsmells.org catalog' guidance so nuanced named-smell reviews with justified severity also activate (both-arm notActivated gap). Funded within the 15k skill-menu budget by compressing redundant framework parentheticals to the compact style already used by sibling skills. Timeout: - run-tests 'Filter xUnit v3 tests by class pattern and trait using query filter language': raise 240 -> 360 (observed peak ~178s, closest to its cap). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
/evaluate |
There was a problem hiding this comment.
Pull request overview
This PR updates dotnet-test plugin evaluation specs and one skill description to address persistent eval timeout and skill-activation failures, aligning expectations with skills that cannot (or should not) self-activate and increasing a scenario timeout headroom.
Changes:
- Mark
filter-syntaxscenarios asexpect_activation: falsebecause the skill is non-invocable/reference-only. - Raise the
run-teststimeout for the xUnit v3 query-filter scenario from 240s to 360s. - Broaden
test-smell-detection’s invocation description to include suite audits that require named smell classification with research-backed severity.
Show a summary per file
| File | Description |
|---|---|
| tests/dotnet-test/writing-mstest-tests/eval.yaml | Adds an expect_activation override for one scenario (currently risks masking a real activation regression). |
| tests/dotnet-test/run-tests/eval.yaml | Increases timeout for a long-running query-filter scenario. |
| tests/dotnet-test/filter-syntax/eval.yaml | Updates scenarios to not expect activation for a reference/non-invocable skill. |
| plugins/dotnet-test/skills/test-smell-detection/SKILL.md | Adjusts description to allow activation for named-smell audit requests while keeping boundaries vs. pragmatic audits. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 4/4 changed files
- Comments generated: 1
|
👋 @Evangelink — this PR has 1 unresolved review thread(s). When you're ready, please address the feedback and push an update; the triage bot will pick up the next state automatically. (Add the |
Skill Validation Results
[1] Model: claude-opus-4.6 | Judge: claude-opus-4.6 🔍 Full Results - additional metrics and failure investigation steps
▶ Sessions Visualisation -- interactive replay of all evaluation sessions |
…lter-syntax eval Log-driven iteration on the eval results (run 29019511076): Priority 1 - regression fix: revert the test-smell-detection description broadening. results.json shows it reliably regressed 'Decline request to write new tests from scratch' (perRunScores [-0.19,-0.10,-0.22]; plugin overallJudgment -0.28, quality 5.0 baseline -> 4.3 skilled) while NOT fixing its target 'Distinguish reasoned skips' (isolated 5.0 vs 5.0 tie failing on judge position-bias, CV=114% - not description-fixable). Net-negative, so restore the pristine description. Priority 3 - remove the structurally-untestable filter-syntax eval. filter-syntax is disable-model-invocation/user-invocable:false, so it can never activate and can never show a skilled-vs-baseline delta - both scenarios fail by construction regardless of expect_activation. Peer reference skills (platform-detection, code-testing-extensions) have NO eval.yaml; filter-syntax was the lone exception. Its filter functionality is already covered by run-tests scenarios (which load filter-syntax as an additional_required_skill). Following precedent, remove the eval rather than leave two permanently-red cases. Kept from the prior commit: run-tests query-filter timeout 240->360 (harmless hard-cap headroom) and writing-mstest 'Fix swapped Assert.AreEqual' expect_activation:false (documents the unaided-by-design scenario and prevents a spurious hard activation failure). Not done - plugin-arm sibling deflections: results.json shows every failing plugin-arm scenario has detectedSkills=[] (NO sibling captured the turn), the rendered menu is under the 15k budget (descriptions are shown), and the verdict failures are dominated by high-variance efficiency noise (CV 60-3000%, several with quality improved). Per docs/InvestigatingResults.md there is no captor to deflect and description edits would not help; with zero budget headroom, adding speculative deflections is unjustified. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
/evaluate |
Skill Validation Results
[1] Model: claude-opus-4.6 | Judge: claude-opus-4.6 🔍 Full Results - additional metrics and failure investigation steps
▶ Sessions Visualisation -- interactive replay of all evaluation sessions |
Skill Coverage Report
Uncovered:
|
|
/evaluate |
Skill Validation Results
[1]
Model: claude-opus-4.6 | Judge: claude-opus-4.6 🔍 Full Results - additional metrics and failure investigation steps
▶ Sessions Visualisation -- interactive replay of all evaluation sessions |
|
👋 @Evangelink — this PR has 1 unresolved review thread(s). When you're ready, please address the feedback and push an update; the triage bot will pick up the next state automatically. (Add the |
…vation Root cause of run-tests plugin+isolated non-activation (skill_not_activated gate): every run-tests scenario is a 'show me the exact command' knowledge question, yet each carried expect_tools: [bash] — which is an ASSERTION that bash was used. That actively forced the model into empirical exploration (dotnet test --help, trial runs, web_fetch) instead of consulting the run-tests skill, and a clean knowledge-only answer would FAIL the assertion. Evidence from run 29253857976: run-tests failed to activate even in the ISOLATED arm (where it is the only skill loaded) on scenarios as easy as base=1.0 — proof the model was bypassing the skill via bash rather than not needing it. The forced bash use also drove the token/tool/ time overhead that produced the negative efficiency scores, and one scenario hit the 360s timeout doing web exploration. Fix: convert all 15 run-tests scenarios from expect_tools: [bash] to reject_tools: [bash, edit, create]. These scenarios only assert on the recommended command text (output_matches) — none run tests (no run_command_and_assert, no file assertions) — and the model can still inspect fixtures via view/glob. Forbidding bash makes them pure-knowledge comparisons, so the model must reason from knowledge and reaches for the run-tests skill (improving activation in both arms), while removing the tool-induced overhead and timeout risk. This is stricter, not weaker, gating and matches docs/InvestigatingResults.md sec.8. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
/evaluate |
Skill Validation Results
[1] (Plugin) Quality unchanged but weighted score is -8.0% due to: quality, tokens (25248 → 34688), time (10.9s → 14.4s) Model: claude-opus-4.6 | Judge: claude-opus-4.6 🔍 Full Results - additional metrics and failure investigation steps
▶ Sessions Visualisation -- interactive replay of all evaluation sessions |
The expect_tools->reject_tools flip was based on a wrong assumption: reject_tools is a POST-HOC scoring assertion only (AssertionEvaluator/BaselineStore), it does NOT remove bash from the agent toolset, so the agent kept using bash and skill activation was unchanged (12 activation-fail arms before AND after, runs 29253857976 vs 29256920057). Reverting to keep the PR minimal and avoid adding failing assertions that don't serve the activation goal. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Radical fix for run-tests' systemic activation-gate failures. Root cause from
artifact analysis: these are 'show me the exact dotnet test command' prompts, so
the model answers directly from its own knowledge without invoking run-tests —
even in the ISOLATED arm where run-tests is the only skill loaded (proving it is
prompt/description-trigger driven, not just plugin-menu competition). It often
answers WRONG on the subtle SDK 8/9 '--' separator vs SDK 10+ direct-args rule
(baseline 1.0-1.7) yet still does not reach for the skill. At ~70% per-run
activation the strict '.Any(3 runs) in BOTH arms' gate flakes red.
Two-pronged fix to raise per-run activation probability:
1. run-tests description: lead with an imperative trigger ('ALWAYS use when the
user asks ... wants the precise command, flags, or argument order') and name
the model's blind spot ('the right syntax depends on the platform and SDK
version and is easy to get wrong from memory'). This signals the model should
consult rather than guess, and is more trigger-matched for the plugin arm.
Kept under the 1024-char description limit and the 15000-char plugin skill-menu
budget (verified: skill-validator check passes).
2. The four currently-flaking scenario prompts now state the user needs the
command to be correct for THIS project's specific test platform and SDK
version (a natural need that raises the stakes) without naming the skill or
leaking the answer — the model must still detect the platform and know the
version-specific syntax.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
/evaluate |
Skill Validation Results
[1] Model: claude-opus-4.6 | Judge: claude-opus-4.6 🔍 Full Results - additional metrics and failure investigation steps
▶ Sessions Visualisation -- interactive replay of all evaluation sessions |
…skilled answer After the activation fix, run-tests activates on the Negative VSTest scenario in both arms (activation solved), but it still failed with completion_regression. Root cause: the assertion output_not_contains '--report-trx' is too naive. The skill-informed answer is strictly better — it recommends 'dotnet test --logger trx' AND educates 'use --logger trx, not --report-trx (which is MTP-only)'. That correct, more helpful contrast trips the substring ban, marking the better answer as a task-completion regression versus a bare baseline command. Fix: forbid --report-trx only when it appears as an actual dotnet test command (output_not_matches 'dotnet test[^\r\n]*--report-trx'), not when the answer names it to warn against it. Verified against the real failing outputs: both skilled runs' --report-trx mentions are in explanatory prose and now pass, while an actual 'dotnet test ... --report-trx' recommendation is still rejected. Stricter-but-correct. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
/evaluate |
Skill Validation Results
[1] Model: claude-opus-4.6 | Judge: claude-opus-4.6 🔍 Full Results - additional metrics and failure investigation steps
▶ Sessions Visualisation -- interactive replay of all evaluation sessions |
…y-only failure After the activation + assertion fixes, the Negative VSTest scenario activates in both arms and passes all assertions, but still failed on a -2.8% weighted score: the baseline is already perfect (5.0/5, correctly uses --logger trx), so the skill can add no quality — and expect_tools:[bash] forced the skilled arm to actually run the tests, inflating tokens (40k->88k) and tool calls (5->8) versus a leaner baseline. That efficiency delta was the entire failure (docs sec.8 baseline-already-good). This is a 'recommend the exact command' negative test: exit_success only checks the agent produced output, and the other assertions validate the recommended command text, so requiring bash execution over-specified the scenario. Dropping expect_tools lets both arms answer from knowledge, removing the forced-execution token/tool overhead while still fully validating that the answer uses --logger trx and never a 'dotnet test ... --report-trx' command. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
/evaluate |
Skill Validation Results
[1] (Plugin) Quality unchanged but weighted score is -9.0% due to: tokens (25470 → 63190), tool calls (2 → 4), time (14.0s → 22.3s) Model: claude-opus-4.6 | Judge: claude-opus-4.6 🔍 Full Results - additional metrics and failure investigation steps
▶ Sessions Visualisation -- interactive replay of all evaluation sessions |
|
✅ Evaluation passed for |
Summary
Fixes dotnet-test eval activation/quality issues, verified with artifact-level
/evaluateanalysis across multiple runs.Changes
run-tests— activation fix (SKILL.md description + scenario prompts): run-tests systemically failed theskill_not_activatedgate because "show me the exactdotnet testcommand" prompts let the model answer from its own knowledge without invoking the skill — even in the isolated arm, and often wrong on the SDK 8/9---separator vs SDK 10+ rule. Fix raises per-run activation probability:iso=True / plug=False— plugin-arm menu competition at RUNS=3, not a description gap.run-tests— "Negative test" (two fixes): after activation was fixed it still failed, first on a brittleoutput_not_contains: "--report-trx"assertion that penalized the better skilled answer (which correctly educates "use--logger trx, not--report-trx") — narrowed tooutput_not_matches: "dotnet test[^\r\n]*--report-trx"so only an actual wrong command is rejected; then on a pure efficiency penalty fromexpect_tools: ["bash"]forcing execution against an already-perfect baseline — dropped, since this is a command-recommendation test whose assertions validate text, not execution.writing-mstest-tests— "Fix swapped Assert.AreEqual": removed theexpect_activation: falsewaiver (per review) and made the scenario skill-dependent — prompt now asks which analyzer catches this and how to enable it, with aMSTEST0017assertion + rubric items (SKILL.md Step 8). Restores activation validation and adds a real quality edge over baseline.filter-syntax/eval.yaml— removed:disable-model-invocation/user-invocable:falsereference skill that can never activate or show a delta; peer reference skills have no eval and its coverage lives inrun-tests.Residual (structural, RUNS=3)
Remaining reds are uniformly
iso=True / plug=Falseplugin-arm menu-competition variance (footnote CVs up to ~1900%, harness advises--runs 5) plus efficiency penalties on runs where the baseline is already strong. The isolated-arm activation problem is fully solved; the plugin-arm residual needs a maintainer-level lever (PR-eval--runs 5, or reduced plugin-menu competition) that's out of scope for eval-file edits. All review threads addressed and resolved.