Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
20103ab
Improve GPT-focused dotnet-test evals
Evangelink Sep 4, 2026
63347b3
Merge origin/main into GPT eval optimization
Evangelink Sep 4, 2026
5880885
Clarify coverage risk routing
Evangelink Sep 4, 2026
60508a4
Fix coverage analysis dormancy routing
Evangelink Sep 4, 2026
16d7c2a
Make test audits discover workspace inputs
Evangelink Sep 4, 2026
7e48c56
Enforce local calendar migration semantics
Evangelink Sep 4, 2026
ddb7a52
Improve Codex workspace analysis reliability
Evangelink Sep 7, 2026
94b345c
Merge remote-tracking branch 'origin/main' into dev/amauryleve/optimi…
Evangelink Sep 7, 2026
f8914f7
Exclude comments from UTC call count
Evangelink Sep 7, 2026
b05616e
Allow migration evals enough execution time
Evangelink Sep 7, 2026
928ec92
Keep static detection scoped to C#
Evangelink Sep 7, 2026
85a5419
Give migration scenarios reliable headroom
Evangelink Sep 7, 2026
e062044
Make coverage dormancy prompt advisory
Evangelink Sep 7, 2026
c8975b4
Recover safely from workspace tool failures
Evangelink Sep 7, 2026
a4f09e3
Refine Codex migration and tagging recovery
Evangelink Sep 8, 2026
52a5569
Simplify Codex skill recovery paths
Evangelink Sep 8, 2026
6fdaf25
Correct local time eval semantics
Evangelink Sep 8, 2026
e4c74c7
Tighten dotnet-test skill activation
Evangelink Sep 8, 2026
c870df2
Clarify skill routing contracts
Evangelink Sep 8, 2026
adee7f9
Harden DateTime migration grader
Evangelink Sep 8, 2026
aab180f
Require explicit skill activation evidence
Evangelink Sep 8, 2026
cf3a78e
Require CSharp routing evidence
Evangelink Sep 8, 2026
cd53275
Harden static scan fallback safety
Evangelink Sep 8, 2026
53310db
Harden coverage reader fallback
Evangelink Sep 8, 2026
243bac5
Remove static detector routing trap
Evangelink Sep 8, 2026
efbf069
Stabilize routing dormancy evaluations
Evangelink Sep 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 10 additions & 14 deletions plugins/dotnet-test/skills/coverage-analysis/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
---
name: coverage-analysis
description: >
Interprets .NET Cobertura line, branch, and condition evidence and, when
explicitly requested, computes project-wide CRAP/refactoring-risk hotspots.
MUST USE for "why is branch coverage lower than line coverage?",
condition-coverage="50% (1/2)", a supplied coverage excerpt, partially covered
conditions, coverage plateaus, members blocking a target, project-wide CRAP,
refactoring safety, or coverage-backed risk priorities. A supplied report is
analyzed directly without rerunning tests, installing tools, generating a
report, or calculating CRAP unless the request asks for risk/CRAP/refactoring
safety. DO NOT USE FOR: CRAP or refactoring-safety analysis of only one named
method, class, or file (crap-score); test trait distributions (test-tagging);
static source-to-test pairing (find-untested-sources);
behavioral/pseudo-mutation gaps (test-gap-analysis); test-code audits
(test-anti-patterns); raw collection/percentage-only requests or just running
tests (run-tests); non-.NET coverage; or writing tests.
Interpret .NET Cobertura line, branch, and condition evidence. MUST USE for
"why is branch coverage lower than line coverage?", condition-coverage="50%
(1/2)", supplied coverage excerpts, partially covered conditions, plateaus,
members blocking a target, project-wide CRAP, refactoring safety, or
coverage-backed risk priorities. Analyze supplied reports directly without
rerunning tests, installing tools, generating reports, or calculating CRAP
unless risk was requested. DO NOT USE for named-target CRAP (crap-score),
Comment thread
Evangelink marked this conversation as resolved.
Outdated
traits (test-tagging), source-to-test pairing, behavioral gaps, test audits,
raw collection/percentage-only requests, test execution (run-tests),
non-.NET coverage, or writing tests.
license: MIT
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Scan a C# codebase for calls to hard-to-test static APIs and produce a ranked re

| Input | Required | Description |
|-------|----------|-------------|
| Target path | Yes | A file, directory, project (.csproj), or solution (.sln) to scan |
| Target path | No | A file, directory, project (.csproj), or solution (.sln) to scan. Defaults to the current workspace. |
| Exclusion patterns | No | Glob patterns to skip (e.g., `**/obj/**`, `**/Migrations/**`) |
| Category filter | No | Limit to specific categories: `time`, `filesystem`, `environment`, `network`, `console`, `process` |

Expand All @@ -50,6 +50,8 @@ Scan a C# codebase for calls to hard-to-test static APIs and produce a ranked re
### Step 1: Determine scan scope

Resolve the target to a set of `.cs` files:
- If omitted, scan every eligible `.cs` file under the current workspace; do not
pick one project and silently omit its siblings.
- If a `.cs` file, scan that single file.
- If a directory, scan all `.cs` files recursively (excluding `obj/`, `bin/`).
- If a `.csproj`, find its directory and scan `.cs` files within.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ Before modifying any code:

### Step 2: Plan the migration for each file

**Migrate exactly what was asked — nothing adjacent.** If the user named a member (`DateTime.UtcNow`), migrate only that member and leave siblings such as `DateTime.Now` untouched. If the user named files, do not touch other files. Never migrate a call site whose comment or name marks it as deliberate (e.g. `// intentional local time`). List everything you deliberately left alone under "Remaining (out of scope)" so the user can ask for it in a follow-up; suggesting is fine, silently widening the scope is not.
**Migrate exactly what was asked — nothing adjacent.** If the user named a member (`DateTime.UtcNow`), migrate only that member and leave siblings such as `DateTime.Now` untouched. If the user named files, do not touch other files. Preserve a call site whose comment or name marks it as deliberate (e.g. `// intentional local time`) unless the user explicitly names that site and requests a semantics-preserving migration. List everything you deliberately left alone under "Remaining (out of scope)" so the user can ask for it in a follow-up; suggesting is fine, silently widening the scope is not.

For each file containing the static pattern, determine:

Expand Down Expand Up @@ -271,7 +271,8 @@ Summarize what was done:
- [ ] A before/after exact-member search proves the in-scope occurrence count
reached zero
- [ ] No call site outside the requested member/file scope was modified
- [ ] Call sites documented as intentional (e.g. local time) were left untouched and reported
- [ ] Call sites documented as intentional were left untouched and reported unless
the user explicitly named them for semantics-preserving migration
- [ ] Constructor injection added to all affected classes
- [ ] Field naming follows existing class conventions
- [ ] Required `using` directives added
Expand Down
19 changes: 12 additions & 7 deletions plugins/dotnet-test/skills/test-anti-patterns/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,14 +128,15 @@ sound. In particular:

Before reporting, re-check each finding against these severity rules:

- **Critical/High**: Only for issues that cause tests to give false confidence or be unreliable. A test that always passes regardless of correctness is Critical. Flaky shared state is High. Missing-await on async assertions is Critical (silent pass).
- **Critical/High**: Only for issues that cause tests to give false confidence or be unreliable. A test that always passes regardless of correctness is Critical. A demonstrated shared-state order dependency that changes pass/fail outcomes is also Critical; shared state that is only a prospective flakiness risk is High. Missing-await on async assertions is Critical (silent pass).
- **Medium**: Only for issues that actively harm maintainability -- 5+ nearly-identical tests, truly meaningless names like `Test1` / `test` / `it1`.
- **Low**: Cosmetic naming mismatches, minor style preferences, assertion messages that could be better. When in doubt, rate Low.
- **Use the caller's severity vocabulary consistently.** If the caller asks for
Critical / Warning / Info, map reliability risks to Warning and
maintenance/cosmetic concerns to Info rather than silently collapsing every
item into Critical. Severity describes the demonstrated failure mode, not how
much prose a finding receives.
Critical / Warning / Info, map demonstrated false-confidence defects and
reproduced order-dependent failures to Critical, prospective reliability
risks to Warning, and maintenance/cosmetic concerns to Info. Severity
describes the demonstrated failure mode, not how much prose a finding
receives.
- **Separate a systemic finding from its instances.** Coverage touching across a
facade is one Critical systemic finding whose evidence lists every affected
test. All assertion-free instances, including the last facade method, retain
Expand All @@ -155,8 +156,12 @@ Before reporting, re-check each finding against these severity rules:
- Explicit per-test setup instead of `[TestInitialize]` / `beforeEach` (this *improves* isolation).
- Tests that are short and clear but could theoretically be consolidated.
- Round-trip or serialization equality with non-trivial input. It is valid
metamorphic evidence; suggest an independent representation assertion when
two implementations could share the same bug.
metamorphic evidence, not a self-comparison; still recommend one independent
representation when producer and consumer could share a defect.
- A transformation tested only with an already-transformed input. Keep it out
of the tautology count, but report the weak oracle when removing the
transformation would still pass. Use an input that must change and pin its
independently expected output.
- Clone value equality. Keep it, and add distinct-reference or mutation-
independence evidence when the contract promises a deep copy.
- A validator or accessor returning the original value when pass-through is the
Expand Down
14 changes: 13 additions & 1 deletion plugins/dotnet-test/skills/test-tagging/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,14 +259,26 @@ Include observations such as:
case still counts as `positive`; a rejected boundary still counts as `negative`.
Derive the positive/negative distribution after applying this rule.

### Step 6: Verify source edits

Whenever trait attributes or other source metadata were changed, run the
narrowest repository command that proves the edited tests still compile and are
discoverable without executing arbitrary tests. For .NET, build the test project
and use the configured runner's non-executing list/discovery mode when available;
use the loaded extension's collection or test-compile command for other
frameworks. Execute tests only when the user requested it or repository policy
already requires that command. Report successful commands and any discovered
count; otherwise report the exact blocker.

## Validation

- [ ] Every test method has at least one trait classification (`positive` or `negative` at minimum) — in the report for `report-only` frameworks, or as an attribute for `auto-edit` frameworks
- [ ] The total equals the per-test inventory count, and displayed trait counts were derived from that inventory
- [ ] No invented trait values outside the taxonomy table
- [ ] Existing trait attributes were preserved, not duplicated
- [ ] The trait summary table was generated
- [ ] For `auto-edit` frameworks, the project still builds / tests still discover after changes (`dotnet build` / `pytest --collect-only` / `mvn test-compile` / `go vet ./...` / `cargo check --tests` / `npm run test:list` / `Invoke-Pester -PassThru -Skip` / equivalent)
- [ ] For `auto-edit` frameworks, the project still builds / tests still discover without executing unrequested tests (`dotnet build` plus list mode / `pytest --collect-only` / `mvn test-compile` / `go vet ./...` / `cargo check --tests` / `npm run test:list` / equivalent)
- [ ] The final summary cites successful validation commands and the discovered test count when a discovery command is available
- [ ] For `report-only` frameworks, no source files were modified
- [ ] For `convention-based` frameworks, edits were applied ONLY when a project convention was confirmed

Expand Down
56 changes: 56 additions & 0 deletions tests/dotnet-test/migrate-static-to-wrapper/eval.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ name: migrate-static-to-wrapper
executionShard: c
description: Evaluates the dotnet-test/migrate-static-to-wrapper skill
type: capability
# The prior GPT-family run produced 4W/5T/0L: positive but one discordant
# stimulus short of the sign-test floor. This predeclared scenario adds distinct
# local-calendar semantics breadth instead of repeating a UTC migration.
config:
timeout: 3m
stimuli:
Expand Down Expand Up @@ -110,6 +113,59 @@ stimuli:
- Restricted the change to the DateTime.UtcNow call sites the user named, leaving the intentional local-time
call untouched

- name: Preserve local calendar semantics when migrating DateTime.Now
prompt: >
CouponService.IsRedeemableToday intentionally compares against the local
calendar day with DateTime.Now. TimeProvider is already registered in DI.
Migrate only that DateTime.Now read to TimeProvider without changing its
DateTime type or local DateTimeKind semantics. Leave every DateTime.UtcNow
call in the file untouched.
environment:
files:
- src: ./fixtures/ready-to-migrate
dest: ReadyToMigrate
graders:
- type: file-contains
config:
path: "**/CouponService.cs"
value: GetLocalNow()
- type: file-contains
config:
path: "**/CouponService.cs"
value: LocalDateTime
- type: file-contains
config:
path: "**/CouponService.cs"
value: DateTime.UtcNow
- type: run-command
Comment thread
Evangelink marked this conversation as resolved.
config:
command: >-
sh -c 'grep -vE "^[[:space:]]*//" ReadyToMigrate/Services/CouponService.cs
> .eval-csharp-lines && ! grep -q "DateTime.Now" .eval-csharp-lines'
Comment thread
Evangelink marked this conversation as resolved.
Outdated
expected_exit_code: 0
timeout: 1m
- type: run-command
config:
command: sh -c "test $(grep -o 'DateTime.UtcNow' ReadyToMigrate/Services/CouponService.cs | wc -l) -eq 4"
Comment thread
Evangelink marked this conversation as resolved.
Outdated
expected_exit_code: 0
timeout: 1m
- type: run-command
config:
command: dotnet build ReadyToMigrate/ReadyToMigrate.csproj
expected_exit_code: 0
timeout: 3m
- type: exit-success
- type: output-matches
config:
pattern: (?i)(build succeeded|built successfully|0 errors?)
- type: prompt
rubric:
- Replaced only the DateTime.Now read in IsRedeemableToday with TimeProvider
- Used GetLocalNow().LocalDateTime.Date so the replacement remains a local DateTime rather than UTC or Unspecified
Comment thread
Evangelink marked this conversation as resolved.
Outdated
- Left all four DateTime.UtcNow reads untouched because they were outside the requested scope
- Injected the already-registered TimeProvider without changing Coupon date property types or unrelated files
- Built the affected project successfully and reported the observed result

- name: Preserve DateTimeOffset values during TimeProvider migration
prompt: >
SubscriptionWindow.cs uses DateTimeOffset.UtcNow and stores
Expand Down
23 changes: 23 additions & 0 deletions tests/dotnet-test/test-tagging/eval.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,26 @@ stimuli:
config:
path: TaskManager.Tests/TaskServiceTests.cs
value: "[Category("
- type: run-command
config:
command: dotnet build TaskManager.Tests/TaskManager.Tests.csproj
expected_exit_code: 0
timeout: 3m
- type: run-command
config:
command: dotnet test TaskManager.Tests/TaskManager.Tests.csproj --no-build --list-tests
expected_exit_code: 0
stdout_matches: DeleteTask_Success
timeout: 3m
- type: output-matches
config:
pattern: (?i)dotnet build
- type: output-matches
config:
pattern: (?i)(--list-tests|list tests|test discovery)
- type: output-matches
config:
pattern: (?i)(build succeeded|0 errors?|[1-9]\d* tests? (?:listed|discovered))
- type: prompt
rubric:
- Classified DeleteTask_Success as negative (and/or security) because the body asserts UnauthorizedAccessException,
Expand All @@ -228,6 +248,9 @@ stimuli:
- Classified DeleteTask_Validation as positive and security because the body verifies admin authorization succeeds
- Used NUnit [Category("...")] attribute syntax, not MSTest or xUnit syntax
- Every test method received at least one trait attribute
- Built the NUnit test project after editing and, when supported, used non-executing discovery rather than
running arbitrary tests
- Reported successful validation and any discovered test count without claiming success after a failed command
- name: Tag MSTest tests and verify the project still builds
prompt: I need you to tag all the tests in my OrderService.Tests/ MSTest project with appropriate category attributes.
After adding the tags, please verify the project still compiles by running dotnet build.
Expand Down