mirror of
https://github.com/dotnet/skills.git
synced 2026-09-20 09:49:54 +08:00
78054c1161
* Make Vally the sole LLM eval engine, retiring skill-validator evaluate Collapses the parallel skill-validator + Vally eval pipeline into a single Vally-only path while preserving every capability skill-validator provided: PR gate, PR comment, dotnet/skills-data historical push, and the dashboard. The skill-validator `check` linter is retained (skill-check.yml) pending microsoft/vally #463. - evaluation.yml: delete build-validator and the skill-validator `evaluate` job; single `evaluate:` job now uses vally-evaluation.yml. Forward the COPILOT_PAT_0..9 pool onto it (from #911) so the reusable workflow's token gate is satisfied. Rewire comment-on-pr / report-status / publish-* / deploy-dashboard onto `evaluate` and vally-results-* artifacts. - vally-evaluation.yml: pin @microsoft/vally-cli@0.9.0; keep the #911 prepare guard; write the generated per-plugin experiment to $GITHUB_WORKSPACE so relative eval globs resolve. - adapt.mjs: reconcile #887's runCompareWithRetry + conclusive/unmatched hardening with the consolidation helpers (nonActivation, compareByStim, roleToDashboard, etc.). Add consolidate.mjs and gen-experiment.mjs. - build-replay-sessions.ps1: read Vally executor-session-logs/events.jsonl instead of skill-validator session output. - Rename all tests/*/*/eval.vally.yaml to eval.yaml (Vally format is now the only eval format); author Vally evals for the four skills that lacked one. - CONTRIBUTING.md + InvestigatingResults: point contributors at the Vally harness; drop non-public links. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix setup-local-sdk eval for Vally schema The hand-authored setup-local-sdk eval used skill-validator grader/environment schema that Vally rejects at validation (no stimuli executed): - file-contains/file-not-contains graders require 'value:' not 'substring:' (output-contains correctly keeps 'substring:'). - environment.files entries require 'src:'/'dest:' (copy a fixture) rather than inline 'path:'/'content:'. Moved the global.json body into fixtures/global.json. Verified with 'vally lint --eval-spec' (0 errors) across all 97 eval.yaml. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix markdownlint violations in migration docs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR review feedback on eval migration - Consolidate run-vally-evals.sh into a single neutral entrypoint eng/run-skill-evals.sh (deletes the thin wrapper; adapt.mjs stays in eng/vally-adapter/ since CI invokes it directly) - Rename reusable workflow vally-evaluation.yml -> evaluation-run.yml and update all references/self-trigger regexes - Rename local output dir vally-results -> eval-results - Bake prerequisite preflight (Node 20+, GITHUB_TOKEN/gh) into the runner - Simplify CONTRIBUTING "Running tests locally" prerequisites - Scrub harness name from consumer-facing surfaces Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Reinstate overfitting detection under the Vally harness Overfitting detection previously ran inside skill-validator's `evaluate` command, which the Vally migration replaced, so it silently stopped running. Reinstate it as a standalone step wired into the Vally pipeline: - Add `skill-validator overfitting` command that discovers skills, parses each eval.yaml, runs the existing OverfittingJudge, and emits [{plugin, skill, overfittingResult}] JSON (per-skill failures non-fatal, bounded parallelism). - Add a Vally-format parser bridge (ParseEvalConfigFlexible) so the judge handles the current stimuli/graders eval.yaml format; the legacy scenarios-only parser rejected all 98 evals, so the judge never ran. - adapt.mjs: merge overfitting results onto each verdict via --overfitting <file> (keyed by plugin/skill); output is byte-identical when the flag is absent. - evaluation-run.yml: build skill-validator (shared cache with check), run the judge per leg reading GITHUB_TOKEN, and pass --overfitting to adapt.mjs so the dashboard/skills-data consume it unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Reconcile #919 Vally eval configs into the sole eval.yaml convention PR #919 landed on main adding fresh Vally specs for three coverage-gap skills (setup-local-sdk, convert-blazor-server-to-webapp, dotnet-webapi) under the interim eval.vally.yaml filename. This branch collapses to a single Vally spec named eval.yaml, so the merge left each skill with both my migrated eval.yaml and #919's newer eval.vally.yaml (a git-clean but semantic duplicate the pipeline would not discover). Adopt #919's reviewed Vally content as the canonical eval.yaml for all three skills and drop the redundant eval.vally.yaml files, preserving the 'sole eval.yaml, zero eval.vally.yaml' invariant. Content is byte-identical to #919's blobs (b14121c6/47d43823/18a9362f), which already passed vally-evaluate on main. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
163 lines
6.2 KiB
YAML
163 lines
6.2 KiB
YAML
name: dotnet-webapi
|
|
description: Evaluates the dotnet-aspnetcore/dotnet-webapi skill
|
|
type: capability
|
|
config:
|
|
timeout: 15m
|
|
stimuli:
|
|
- name: Create a CRUD Web API with minimal APIs, OpenAPI, and proper HTTP semantics
|
|
prompt: |
|
|
Create an ASP.NET Core Web API (.NET 10) project for managing products.
|
|
Each product has a name, price, category (an enum: Electronics, Clothing,
|
|
Food, Books), and a createdAt timestamp.
|
|
|
|
The API should have these endpoints:
|
|
- GET /api/products (list all)
|
|
- GET /api/products/{id} (get by ID)
|
|
- POST /api/products (create a product)
|
|
|
|
Use an in-memory service behind an interface for data storage.
|
|
Add OpenAPI documentation with rich metadata on each endpoint.
|
|
graders:
|
|
- type: output-matches
|
|
config:
|
|
pattern: (MapGet|MapPost)
|
|
- type: output-matches
|
|
config:
|
|
pattern: (TypedResults|Results<)
|
|
- type: output-matches
|
|
config:
|
|
pattern: sealed
|
|
- type: output-contains
|
|
config:
|
|
substring: DateTimeOffset
|
|
- type: output-matches
|
|
config:
|
|
pattern: '/// <summary>'
|
|
- type: output-contains
|
|
config:
|
|
substring: AddOpenApi
|
|
- type: output-contains
|
|
config:
|
|
substring: MapOpenApi
|
|
- type: output-matches
|
|
config:
|
|
pattern: (WithName|WithSummary|WithDescription)
|
|
- type: output-not-contains
|
|
config:
|
|
substring: Swashbuckle
|
|
- type: output-not-matches
|
|
config:
|
|
pattern: (UseSwagger|UseSwaggerUI)
|
|
- type: output-contains
|
|
config:
|
|
substring: JsonStringEnumConverter
|
|
- type: output-contains
|
|
config:
|
|
substring: CancellationToken
|
|
- type: prompt
|
|
rubric:
|
|
- Uses minimal APIs (MapGet, MapPost, etc.) rather than controllers for new projects
|
|
- POST endpoint returns 201 Created with a Location header, not 200 OK
|
|
- Uses TypedResults with explicit Results<T1, T2> return types for compile-time type safety
|
|
- DTOs are sealed records, not mutable classes
|
|
- Uses a service layer with interfaces instead of injecting a data store directly into endpoints
|
|
- CancellationToken is accepted in endpoint signatures and forwarded through all async calls
|
|
- Date/time properties use DateTimeOffset, not DateTime
|
|
- All request and response DTOs include XML doc summary comments
|
|
- Enum properties serialize as strings by default using JsonStringEnumConverter
|
|
- Uses builder.Services.AddOpenApi() and app.MapOpenApi() (built-in .NET 9+ support)
|
|
- Does NOT add any Swashbuckle NuGet packages
|
|
- Chains .WithName(), .WithSummary(), and .WithDescription() on endpoints for OpenAPI metadata
|
|
|
|
- name: Add error handling with ProblemDetails and IExceptionHandler
|
|
prompt: |
|
|
I have an existing ASP.NET Core minimal API project. I need to add
|
|
global error handling so that:
|
|
- All error responses use RFC 7807 Problem Details format
|
|
- KeyNotFoundException maps to 404
|
|
- ArgumentException maps to 400
|
|
- InvalidOperationException maps to 409
|
|
- Unhandled exceptions return 500 with no sensitive details
|
|
|
|
Show me how to implement this without adding try-catch blocks in
|
|
every endpoint.
|
|
graders:
|
|
- type: output-contains
|
|
config:
|
|
substring: IExceptionHandler
|
|
- type: output-contains
|
|
config:
|
|
substring: ProblemDetails
|
|
- type: output-contains
|
|
config:
|
|
substring: AddProblemDetails
|
|
- type: output-contains
|
|
config:
|
|
substring: UseExceptionHandler
|
|
- type: prompt
|
|
rubric:
|
|
- Implements IExceptionHandler (the modern .NET 8+ approach) rather than convention-based middleware
|
|
- Returns ProblemDetails for all error responses (RFC 7807)
|
|
- Maps exception types to appropriate HTTP status codes (404, 400, 409)
|
|
- Does not expose internal exception details in production error responses
|
|
- Registers the handler with AddExceptionHandler<T>() and AddProblemDetails()
|
|
- Exception handler class is sealed
|
|
- Exception handler is placed in a Middleware/ folder
|
|
|
|
- name: Add a new API endpoint to an existing controller-based project
|
|
prompt: |
|
|
I have an existing ASP.NET Core Web API that uses controllers. Here is
|
|
one of the existing controllers:
|
|
|
|
```csharp
|
|
[ApiController]
|
|
[Route("api/[controller]")]
|
|
public class CustomersController : ControllerBase
|
|
{
|
|
private readonly ICustomerService _service;
|
|
|
|
public CustomersController(ICustomerService service)
|
|
{
|
|
_service = service;
|
|
}
|
|
|
|
[HttpGet]
|
|
public async Task<ActionResult<List<CustomerResponse>>> GetAll()
|
|
{
|
|
return Ok(await _service.GetAllAsync());
|
|
}
|
|
}
|
|
```
|
|
|
|
Add a new OrdersController with a GET endpoint to list orders and a
|
|
POST endpoint to create an order. Each order has a customer ID, a
|
|
placedAt timestamp, a total amount, and an OrderStatus (Pending,
|
|
Processing, Shipped, Delivered, Cancelled).
|
|
graders:
|
|
- type: output-contains
|
|
config:
|
|
substring: ControllerBase
|
|
- type: output-contains
|
|
config:
|
|
substring: '[ApiController]'
|
|
- type: output-contains
|
|
config:
|
|
substring: CancellationToken
|
|
- type: output-not-matches
|
|
config:
|
|
pattern: 'app\.(MapGet|MapPost|MapPut|MapDelete|MapPatch)|\b(MapGet|MapPost|MapPut|MapDelete|MapPatch)\b'
|
|
- type: output-contains
|
|
config:
|
|
substring: DateTimeOffset
|
|
- type: output-matches
|
|
config:
|
|
pattern: '/// <summary>'
|
|
- type: prompt
|
|
rubric:
|
|
- Continues with the controller pattern since the existing project uses controllers (does not mix minimal APIs)
|
|
- Includes CancellationToken in all endpoint signatures
|
|
- POST create returns CreatedAtAction with 201 status, not Ok with 200
|
|
- Uses sealed record DTOs with proper naming (CreateOrderRequest, OrderResponse)
|
|
- Date/time properties use DateTimeOffset, not DateTime
|
|
- All request and response DTOs include XML doc summary comments
|