Skip to content

Adding a web api skill#493

Open
sayedihashimi wants to merge 20 commits intodotnet:mainfrom
sayedihashimi:sayedha/addwebapi-skill
Open

Adding a web api skill#493
sayedihashimi wants to merge 20 commits intodotnet:mainfrom
sayedihashimi:sayedha/addwebapi-skill

Conversation

@sayedihashimi
Copy link
Copy Markdown
Member

@sayedihashimi sayedihashimi commented Apr 1, 2026

Summary

Adds the dotnet-webapi skill to the dotnet-aspnet plugin. This skill guides the creation and modification of ASP.NET Core Web API endpoints with correct HTTP semantics, OpenAPI metadata, and error handling.

Here is a sample project created with this skill https://github.com/sayedihashimi/sample-projects/tree/2026.04.01.FitnessStudioApi

What's included

New skill: plugins/dotnet-aspnet/skills/dotnet-webapi/SKILL.md

A comprehensive skill covering the following areas:

  • API style detection — Scans existing projects to determine whether to use controllers or minimal APIs; defaults to minimal APIs for new projects and never mixes styles.
  • Request/response types — Enforces sealed record DTOs with proper naming conventions (CreateXxxRequest, XxxResponse), XML doc comments, and DateTimeOffset for timestamps.
  • Minimal API endpoints — Guides use of TypedResults with explicit Results<T1, T2> return types, CancellationToken forwarding, and OpenAPI endpoint metadata (WithName, WithSummary, WithDescription).
  • Controller-based endpoints — Follows [ApiController] conventions with ActionResult<T> return types and ProducesResponseType attributes.
  • HTTP semantics — Ensures correct status codes (201 Created with Location header for POST, 204 No Content for DELETE, etc.).
  • OpenAPI/Swagger — Uses the built-in .NET 9+ AddOpenApi()/MapOpenApi() instead of Swashbuckle; includes XML doc comment integration and JsonStringEnumConverter for enum serialization.
  • Error handling — Implements IExceptionHandler with RFC 7807 ProblemDetails, exception-to-status-code mapping, and a sealed handler class in a Middleware/ folder.
  • .http test files — Generates test files for verifying endpoints directly from the IDE.

New tests: tests/dotnet-aspnet/dotnet-webapi/eval.yaml

Three evaluation scenarios with assertions and rubrics:

Scenario Focus
Create a CRUD Web API with minimal APIs Minimal APIs, TypedResults, OpenAPI, sealed record DTOs, JsonStringEnumConverter, no Swashbuckle
Add error handling with ProblemDetails IExceptionHandler, ProblemDetails, exception mapping, sealed handler class
Add endpoint to existing controller project Controller pattern matching, CancellationToken, CreatedAtAction, sealed record DTOs

Skill validator results

  • Score: +47.1% improvement over baseline (95% CI: [+26.5%, +48.2%], significant)
  • Hedges' g: +79.5% (large effect size)
  • Overfitting: 0.32 (moderate 🟡)
  • Result: 1/1 skills passed validation
  • Model: claude-opus-4.6, judge-mode: Pairwise, 5 runs per scenario

Skill validator results

dotnet run --project .\eng\skill-validator\src\SkillValidator.csproj -p:RunArguments="" -- evaluate --runs 5 --results-dir "C:\temp\skills\validator-output\" --tests-dir "./tests/dotnet-aspnet/" "./plugins/dotnet-aspnet/skills/dotnet-webapi"                                                                                                                     
Using model: claude-opus-4.6, judge-mode: Pairwise                                                                                                                                                                                                                                                                                                                      
Found 1 skill(s)                                                                                                                                                                                                                                                                                                                                                        
                                                                                                                                                                                                                                                                                                                                                                        
[dotnet-webapi] 🔍 Evaluating...                                                                                                                                                                                                                                                                                                                                        
[dotnet-webapi] 🔍 Running overfitting check (parallel)...                                                                                                                                                                                                                                                                                                              
[dotnet-webapi/Create a CRUD Web API with minimal APIs, OpenAPI, and proper HTTP semantics] 📋 Starting scenario                                                                                                                                                                                                                                                        
[dotnet-webapi/Add error handling with ProblemDetails and IExceptionHandler] 📋 Starting scenario                                                                                                                                                                                                                                                                       
[dotnet-webapi/Add a new API endpoint to an existing controller-based project] 📋 Starting scenario                                                                                                                                                                                                                                                                     
[dotnet-webapi/Add error handling with ProblemDetails and IExceptionHandler/3] 🔌 Skill activated (isolated): skills=dotnet-webapi                                                                                                                                                                                                                                      
[dotnet-webapi/Add error handling with ProblemDetails and IExceptionHandler/3] 🔌 Skill activated (plugin): skills=dotnet-webapi                                                                                                                                                                                                                                        
[dotnet-webapi/Add a new API endpoint to an existing controller-based project/3] 🔌 Skill activated (isolated): skills=dotnet-webapi                                                                                                                                                                                                                                    
[dotnet-webapi/Add a new API endpoint to an existing controller-based project/3] 🔌 Skill activated (plugin): skills=dotnet-webapi                                                                                                                                                                                                                                      
[dotnet-webapi/Add error handling with ProblemDetails and IExceptionHandler/1] 🔌 Skill activated (isolated): skills=dotnet-webapi                                                                                                                                                                                                                                      
[dotnet-webapi/Add error handling with ProblemDetails and IExceptionHandler/1] 🔌 Skill activated (plugin): skills=dotnet-webapi                                                                                                                                                                                                                                        
[dotnet-webapi/Add error handling with ProblemDetails and IExceptionHandler/2] 🔌 Skill activated (isolated): skills=dotnet-webapi                                                                                                                                                                                                                                      
[dotnet-webapi/Add error handling with ProblemDetails and IExceptionHandler/2] 🔌 Skill activated (plugin): skills=dotnet-webapi                                                                                                                                                                                                                                        
⠸ Evaluating 1 target(s)...      ⚠️  Judge for "Create a CRUD Web API with minimal APIs, OpenAPI, and proper HTTP semantics": attempt 1 failed: The given key was not present in the dictionary.                                                                                                                                                                         
      🔄 Judge for "Create a CRUD Web API with minimal APIs, OpenAPI, and proper HTTP semantics": retry 1/2 (waiting 3s)                                                                                                                                                                                                                                                
⠴ Evaluating 1 target(s)...      ⚠️  Judge for "Create a CRUD Web API with minimal APIs, OpenAPI, and proper HTTP semantics": attempt 1 failed: The given key was not present in the dictionary.                                                                                                                                                                         
      🔄 Judge for "Create a CRUD Web API with minimal APIs, OpenAPI, and proper HTTP semantics": retry 1/2 (waiting 5s)                                                                                                                                                                                                                                                
⠹ Evaluating 1 target(s)...      ⚠️  Judge for "Create a CRUD Web API with minimal APIs, OpenAPI, and proper HTTP semantics": attempt 1 failed: The given key was not present in the dictionary.                                                                                                                                                                         
      🔄 Judge for "Create a CRUD Web API with minimal APIs, OpenAPI, and proper HTTP semantics": retry 1/2 (waiting 3s)                                                                                                                                                                                                                                                
⠴ Evaluating 1 target(s)...      ⚠️  Judge for "Create a CRUD Web API with minimal APIs, OpenAPI, and proper HTTP semantics": attempt 1 failed: The given key was not present in the dictionary.                                                                                                                                                                         
      🔄 Judge for "Create a CRUD Web API with minimal APIs, OpenAPI, and proper HTTP semantics": retry 1/2 (waiting 4s)                                                                                                                                                                                                                                                
⠹ Evaluating 1 target(s)...      ⚠️  Judge for "Create a CRUD Web API with minimal APIs, OpenAPI, and proper HTTP semantics": attempt 2 failed: The given key was not present in the dictionary.                                                                                                                                                                         
      🔄 Judge for "Create a CRUD Web API with minimal APIs, OpenAPI, and proper HTTP semantics": retry 2/2 (waiting 11s)                                                                                                                                                                                                                                               
⠋ Evaluating 1 target(s)...      ⚠️  Judge for "Create a CRUD Web API with minimal APIs, OpenAPI, and proper HTTP semantics": attempt 2 failed: The given key was not present in the dictionary.                                                                                                                                                                         
      🔄 Judge for "Create a CRUD Web API with minimal APIs, OpenAPI, and proper HTTP semantics": retry 2/2 (waiting 9s)                                                                                                                                                                                                                                                
[dotnet-webapi/Add a new API endpoint to an existing controller-based project/2] 🔌 Skill activated (isolated): skills=dotnet-webapi                                                                                                                                                                                                                                    
[dotnet-webapi/Add a new API endpoint to an existing controller-based project/2] 🔌 Skill activated (plugin): skills=dotnet-webapi                                                                                                                                                                                                                                      
[dotnet-webapi/Add error handling with ProblemDetails and IExceptionHandler/4] 🔌 Skill activated (isolated): skills=dotnet-webapi                                                                                                                                                                                                                                      
[dotnet-webapi/Add error handling with ProblemDetails and IExceptionHandler/4] 🔌 Skill activated (plugin): skills=dotnet-webapi                                                                                                                                                                                                                                        
[dotnet-webapi/Create a CRUD Web API with minimal APIs, OpenAPI, and proper HTTP semantics/3] 🔌 Skill activated (isolated): skills=dotnet-webapi                                                                                                                                                                                                                       
[dotnet-webapi/Create a CRUD Web API with minimal APIs, OpenAPI, and proper HTTP semantics/3] 🔌 Skill activated (plugin): skills=dotnet-webapi                                                                                                                                                                                                                         
⠼ Evaluating 1 target(s)...      ⚠️  Judge for "Create a CRUD Web API with minimal APIs, OpenAPI, and proper HTTP semantics": attempt 2 failed: Failed to parse judge response JSON. Original error: '/' is an invalid start of a property name. Expected a '"'. LineNumber: 1 | BytePositionInLine: 36.. JSON snippet: {                                                
  "category": "Electronics",                                                                                                                                                                                                                                                                                                                                            
      🔄 Judge for "Create a CRUD Web API with minimal APIs, OpenAPI, and proper HTTP semantics": retry 2/2 (waiting 8s)                                                                                                                                                                                                                                                
[dotnet-webapi/Add error handling with ProblemDetails and IExceptionHandler/5] 🔌 Skill activated (isolated): skills=dotnet-webapi                                                                                                                                                                                                                                      
[dotnet-webapi/Add error handling with ProblemDetails and IExceptionHandler/5] 🔌 Skill activated (plugin): skills=dotnet-webapi                                                                                                                                                                                                                                        
[dotnet-webapi/Add error handling with ProblemDetails and IExceptionHandler] ✓ All 5 run(s) complete                                                                                                                                                                                                                                                                    
⠏ Evaluating 1 target(s)...      ⚠️  Judge for "Create a CRUD Web API with minimal APIs, OpenAPI, and proper HTTP semantics": attempt 3 failed: The given key was not present in the dictionary.                                                                                                                                                                         
[dotnet-webapi/Create a CRUD Web API with minimal APIs, OpenAPI, and proper HTTP semantics/2] ⚠️  Judge (plugin) failed, using fallback scores: Judge for "Create a CRUD Web API with minimal APIs, OpenAPI, and proper HTTP semantics": all attempts failed after 361s: The given key was not present…                                                                  
⠦ Evaluating 1 target(s)...      ⚠️  Judge for "Add a new API endpoint to an existing controller-based project": attempt 1 failed: Judge response contained no JSON. Raw response:                                                                                                                                                                                       
Based on the session timeline, I can reconstruct the file contents from the truncated `create` tool calls and the agent's descriptions. Let me evaluate                                                                                                                                                                                                                 
      🔄 Judge for "Add a new API endpoint to an existing controller-based project": retry 1/2 (waiting 6s)                                                                                                                                                                                                                                                             
[dotnet-webapi/Create a CRUD Web API with minimal APIs, OpenAPI, and proper HTTP semantics/2] 🔌 Skill activated (isolated): skills=dotnet-webapi                                                                                                                                                                                                                       
[dotnet-webapi/Create a CRUD Web API with minimal APIs, OpenAPI, and proper HTTP semantics/2] 🔌 Skill activated (plugin): skills=dotnet-webapi                                                                                                                                                                                                                         
[dotnet-webapi/Create a CRUD Web API with minimal APIs, OpenAPI, and proper HTTP semantics/1] 🔌 Skill activated (isolated): skills=dotnet-webapi                                                                                                                                                                                                                       
[dotnet-webapi/Create a CRUD Web API with minimal APIs, OpenAPI, and proper HTTP semantics/1] 🔌 Skill activated (plugin): skills=dotnet-webapi                                                                                                                                                                                                                         
⠼ Evaluating 1 target(s)...      ⚠️  Judge for "Add a new API endpoint to an existing controller-based project": attempt 2 failed: Judge response contained no JSON. Raw response:                                                                                                                                                                                       
I can't access the files directly (the session environment seems to be gone), but I have enough information from the session timeline — including the tr                                                                                                                                                                                                                
      🔄 Judge for "Add a new API endpoint to an existing controller-based project": retry 2/2 (waiting 11s)                                                                                                                                                                                                                                                            
[dotnet-webapi/Add a new API endpoint to an existing controller-based project/5] 🔌 Skill activated (isolated): skills=dotnet-webapi                                                                                                                                                                                                                                    
[dotnet-webapi/Add a new API endpoint to an existing controller-based project/5] 🔌 Skill activated (plugin): skills=dotnet-webapi                                                                                                                                                                                                                                      
[dotnet-webapi/Add a new API endpoint to an existing controller-based project/5] 🤖 Subagents invoked (plugin): explore                                                                                                                                                                                                                                                 
⠴ Evaluating 1 target(s)...      ⚠️  Judge for "Add a new API endpoint to an existing controller-based project": attempt 1 failed: Judge response contained no JSON. Raw response:                                                                                                                                                                                       
Based on the session timeline, let me now evaluate each criterion using the evidence available from the tool call parameters and results.                                                                                                                                                                                                                               
                                                                                                                                                                                                                                                                                                                                                                        
From the time                                                                                                                                                                                                                                                                                                                                                           
      🔄 Judge for "Add a new API endpoint to an existing controller-based project": retry 1/2 (waiting 4s)                                                                                                                                                                                                                                                             
⠼ Evaluating 1 target(s)...      ⚠️  Judge for "Add a new API endpoint to an existing controller-based project": attempt 2 failed: Judge response contained no JSON. Raw response:                                                                                                                                                                                       
Based on the session timeline, I can extract the key information about the created files from the create tool calls and their results. Let me evaluate a                                                                                                                                                                                                                
      🔄 Judge for "Add a new API endpoint to an existing controller-based project": retry 2/2 (waiting 11s)                                                                                                                                                                                                                                                            
[dotnet-webapi/Create a CRUD Web API with minimal APIs, OpenAPI, and proper HTTP semantics/4] 🔌 Skill activated (isolated): skills=dotnet-webapi                                                                                                                                                                                                                       
[dotnet-webapi/Create a CRUD Web API with minimal APIs, OpenAPI, and proper HTTP semantics/4] 🔌 Skill activated (plugin): skills=dotnet-webapi                                                                                                                                                                                                                         
[dotnet-webapi/Add a new API endpoint to an existing controller-based project/1] 🔌 Skill activated (isolated): skills=dotnet-webapi                                                                                                                                                                                                                                    
[dotnet-webapi/Add a new API endpoint to an existing controller-based project/1] 🔌 Skill activated (plugin): skills=dotnet-webapi                                                                                                                                                                                                                                      
[dotnet-webapi/Add a new API endpoint to an existing controller-based project/4] 🔌 Skill activated (isolated): skills=dotnet-webapi                                                                                                                                                                                                                                    
[dotnet-webapi/Add a new API endpoint to an existing controller-based project/4] 🔌 Skill activated (plugin): skills=dotnet-webapi                                                                                                                                                                                                                                      
[dotnet-webapi/Add a new API endpoint to an existing controller-based project] ✓ All 5 run(s) complete                                                                                                                                                                                                                                                                  
[dotnet-webapi/Create a CRUD Web API with minimal APIs, OpenAPI, and proper HTTP semantics/5] 🔌 Skill activated (isolated): skills=dotnet-webapi                                                                                                                                                                                                                       
[dotnet-webapi/Create a CRUD Web API with minimal APIs, OpenAPI, and proper HTTP semantics/5] 🔌 Skill activated (plugin): skills=dotnet-webapi                                                                                                                                                                                                                         
[dotnet-webapi/Create a CRUD Web API with minimal APIs, OpenAPI, and proper HTTP semantics] ✓ All 5 run(s) complete                                                                                                                                                                                                                                                     
[dotnet-webapi] 🔍 Overfitting: 0.32 (Moderate)                                                                                                                                                                                                                                                                                                                         
[dotnet-webapi] ✅ Done (score: 47.1%)                                                                                                                                                                                                                                                                                                                                  
{Ansi.ClearLine}arget(s)...                                                                                                                                                                                                                                                                                                                                             
═══ Skill Validation Results ═══                                                                                                                                                                                                                                                                                                                                        
                                                                                                                                                                                                                                                                                                                                                                        
✓ dotnet-webapi  +47.1%  [+26.5%, +48.2%] significant  (g=+79.5%)                                                                                                                                                                                                                                                                                                       
  Improvement score 47.1% meets threshold of 10.0% [high variance in: Create a CRUD Web API with minimal APIs, OpenAPI, and proper HTTP semantics, Add error handling with ProblemDetails and IExceptionHandler]                                                                                                                                                        
                                                                                                                                                                                                                                                                                                                                                                        
  🔍 Overfitting: 0.32 (moderate) 🟡                                                                                                                                                                                                                                                                                                                                    
    • [vocabulary] "Exception handler is placed in a Middleware/ folder"                                                                                                                                                                                                                                                                                                
      — This is a purely organizational choice dictated by the skill. A developer might place the handler in Handlers/, Infrastructure/, Exceptions/, or the project root. The folder name has zero effect on functionality.                                                                                                                                            
    • [technique] "Uses TypedResults with explicit Results<T1, T2> return types for compile-time type safety"                                                                                                                                                                                                                                                           
      — A developer could validly use the Results factory (returning IResult) or even produce correct OpenAPI metadata via .Produces<T>() annotations instead. TypedResults with explicit union return types is the skill's preferred technique.                                                                                                                        
    • [technique] "Exception handler class is sealed"                                                                                                                                                                                                                                                                                                                   
      — Requiring 'sealed' on the exception handler class is a skill-specific convention (CA1852). An unsealed class that implements IExceptionHandler correctly works identically.                                                                                                                                                                                     
    • [narrow] output_matches: Middleware                                                                                                                                                                                                                                                                                                                               
      — Tests for the skill's specific folder naming convention. A developer might place exception handlers in Handlers/, Infrastructure/, Exceptions/, or other folders. The folder name is purely a skill convention.                                                                                                                                                 
    • [narrow] output_matches: sealed                                                                                                                                                                                                                                                                                                                                   
      — Tests for the skill's specific convention of sealing DTOs. Many developers use regular records or classes without 'sealed'. The word 'sealed' could appear in other contexts but this clearly tests the DTO convention.
The agent created an OrdersController inheriting from ControllerBase with [ApiController] and [Route("api/[controller]")] attributes, exactly matching the CustomersController pattern. No minimal APIs were introduced.
        1/5  Includes CancellationToken in all endpoint signatures
              The agent's summary explicitly describes the interface methods as `GetAllAsync()` and `CreateAsync(CreateOrderRequest)` with no CancellationToken parameters. At 735 chars for the controller, there's no indication CancellationToken was included in endpoint signatures. This best practice was entirely omitted.
        4.4/5  POST create returns CreatedAtAction with 201 status, not Ok with 200
              The agent's summary explicitly states 'POST api/orders (create, returns 201 Created)'. This strongly suggests CreatedAtAction or Created was used rather than Ok(). The agent clearly intended 201 status. Without seeing full code I give 4 rather than 5.
        1.8/5  Uses sealed record DTOs with proper naming (CreateOrderRequest, OrderResponse)
              The naming convention is correct (CreateOrderRequest, OrderResponse). However, the visible file contents clearly show `public class OrderResponse` and `public class CreateOrderRequest` — these are plain classes, not sealed records. The naming half is met but the sealed record requirement is not.
        1.4/5  Date/time properties use DateTimeOffset, not DateTime
              The OrderResponse is only 270 chars total, which is very compact. Given the agent didn't mention DateTimeOffset anywhere in its output or summary, and the typical default for most developers is DateTime, it most likely used DateTime for PlacedAt. The agent showed no awareness of the DateTimeOffset best practice.
        1/5  All request and response DTOs include XML doc summary comments
              At 153 chars for CreateOrderRequest and 270 chars for OrderResponse, there is virtually no room for XML doc comments alongside the namespace declarations, class declarations, and property definitions. These files are far too small to contain any documentation. No XML doc comments were included.

      ─── With-Skill Judge (Isolated) 4.8/5 ───
      The agent produced a comprehensive, well-structured solution with zero errors in an efficient 15-tool-call session. It correctly identified the controller pattern, created all necessary files (enum, DTOs, service interface, controller, test file) in parallel, and followed ASP.NET Core best practices including CancellationToken, CreatedAtAction, sealed records, DateTimeOffset, validation attributes, and XML documentation. The summary output was clear and included helpful integration instructions for DI registration and JSON serialization configuration. The addition of a GetById endpoint and an .http test file shows thoughtful beyond-the-minimum design.

        5/5 (was 5/5)  Continues with the controller pattern since the existing project uses controllers (does not mix minimal APIs)
              The agent created Controllers/OrdersController.cs using Microsoft.AspNetCore.Mvc, clearly following the existing controller-based pattern from the CustomersController example. The file structure mirrors the existing project with a Controllers directory and proper attribute routing. No minimal API patterns were introduced.
        4.8/5 (was 1/5)  Includes CancellationToken in all endpoint signatures
              The agent explicitly states 'All endpoints accept CancellationToken' in its summary. This is a specific technical claim that aligns with best practices. The file size of 1708 chars for the controller is consistent with having CancellationToken parameters across multiple endpoints. Score is 4 rather than 5 because I cannot directly verify the file contents, but the specific claim gives high confidence.
        5/5 (was 4.4/5)  POST create returns CreatedAtAction with 201 status, not Ok with 200
              The agent explicitly calls this out: 'POST returns 201 Created with a Location header via CreatedAtAction'. It also mentions including a GetById action specifically so CreatedAtAction can generate the Location header, which shows deep understanding of the pattern. This is a very specific and correct claim that would be hard to fabricate.       
        5/5 (was 1.8/5)  Uses sealed record DTOs with proper naming (CreateOrderRequest, OrderResponse)
              The agent explicitly describes OrderResponse as a 'Sealed positional record DTO' and CreateOrderRequest as a 'Sealed record with validation'. The naming convention (CreateOrderRequest, OrderResponse) matches the prompt's requirement and follows the existing pattern of CustomerResponse. File sizes are consistent with record types.
        5/5 (was 1.4/5)  Date/time properties use DateTimeOffset, not DateTime
              The agent explicitly states 'DateTimeOffset used for PlacedAt'. This is a specific, correct technical choice for a Web API timestamp field (PlacedAt), avoiding the timezone ambiguity of DateTime.
        4.6/5 (was 1/5)  All request and response DTOs include XML doc summary comments
              The truncated content for OrderResponse.cs shows '/// <summary>Represents an order returned b...' and OrderStatus.cs shows '/// ...' indicating XML doc comments. The CreateOrderRequest at 553 chars has room for both validation attributes and doc comments. Score is 4 rather than 5 because I can only partially verify the comments exist on some DTOs; I cannot confirm they are on ALL properties and types.

      ─── With-Skill Judge (Plugin) 4.4/5 ───
      The agent produced well-structured, convention-following code that addresses all requirements: an OrdersController with GET and POST endpoints, proper OrderStatus enum, sealed record DTOs, service interface for DI, and appropriate ASP.NET Core patterns (CreatedAtAction, CancellationToken, DateTimeOffset). It went above the minimum by adding a GetById endpoint (necessary for CreatedAtAction), validation attributes, and an .http test file. The code quality appears high based on available evidence. However, the process was notably inefficient — the agent spent ~30 of 40 tool calls and considerable time searching the filesystem for existing projects when the working directory was empty. It should have recognized sooner that it just needed to create files based on the provided controller pattern. The inability to fully verify file contents (due to the environment being unavailable) introduces slight uncertainty on some criteria, but the agent's explicit claims and consistent patterns provide strong confidence.

        5/5 (was 5/5)  Continues with the controller pattern since the existing project uses controllers (does not mix minimal APIs)
              The agent created an OrdersController inheriting from ControllerBase with [ApiController] and [Route("api/[controller]")] attributes, exactly matching the pattern of the existing CustomersController. No minimal APIs were introduced.
        4.6/5 (was 1/5)  Includes CancellationToken in all endpoint signatures
              The agent explicitly states 'All endpoints accept CancellationToken and forward it to the service' and the IOrderService interface visible in the timeline confirms CancellationToken parameters on GetAllAsync and other methods.
        5/5 (was 4.4/5)  POST create returns CreatedAtAction with 201 status, not Ok with 200
              The agent explicitly states 'POST returns 201 Created with a Location header via CreatedAtAction' and included a GetById endpoint specifically to serve as the CreatedAtAction target, which is best practice.
        5/5 (was 1.8/5)  Uses sealed record DTOs with proper naming (CreateOrderRequest, OrderResponse)
              From the create tool calls: 'public sealed record OrderResponse(' and 'public sealed record CreateOrderRequest' are visible. Both use 'sealed record' and follow the exact naming convention specified (CreateOrderRequest, OrderResponse).
        4.8/5 (was 1.4/5)  Date/time properties use DateTimeOffset, not DateTime
              The OrderResponse file content clearly shows 'DateTimeOffset P...' (truncated but clearly PlacedAt). The agent's summary confirms 'Sealed positional record DTO with DateTimeOffset PlacedAt'.
        4.2/5 (was 1/5)  All request and response DTOs include XML doc summary comments
              The visible file contents show XML doc summary comments on all DTO classes: OrderStatus ('Represents the lifecycle status of an order'), OrderResponse ('Represents an order returned by the API'), CreateOrderRequest ('Payload for creating a new order'). However, given the small file sizes (OrderResponse is 245 chars total including all properties), it's unlikely individual properties within the positional record have their own XML doc comments. The class-level docs are present but property-level docs may be missing.

      ─── Pairwise Comparison ✓ consistent ───
      Winner: skill (MuchBetter)
      Response B is clearly superior across nearly every rubric criterion. It uses sealed records instead of plain classes, includes CancellationToken in all endpoints, properly implements CreatedAtAction with a supporting GetById action, uses DateTimeOffset for timestamps, includes XML doc comments, adds validation attributes, and even provides an .http test file. Response B also accomplished all this far more efficiently (14 tool calls vs 65+), quickly recognizing the empty directory and proceeding to create files, while Response A spent enormous effort searching for non-existent project files before creating the same basic structure. The quality gap in the final output is significant — Response B follows modern C# conventions and REST best practices throughout.

        tie      (Equal)  Continues with the controller pattern since the existing project uses controllers (does not mix minimal APIs)
              Both responses create a proper OrdersController inheriting from ControllerBase with [ApiController] and [Route("api/[controller]")] attributes, following the same pattern as the existing CustomersController. Neither mixes in minimal APIs.
        skill    (MuchBetter)  Includes CancellationToken in all endpoint signatures
              Response B explicitly states 'All endpoints accept CancellationToken' and the controller is 1708 chars (plenty of room for CancellationToken params). Response A's controller is only 735 chars and never mentions CancellationToken — the compact size and silence on this topic strongly suggest it was omitted. The IOrderService interface (202 chars for A vs 368 chars for B) also suggests A's service methods don't accept CancellationToken either.
        skill    (SlightlyBetter)  POST create returns CreatedAtAction with 201 status, not Ok with 200
              Both claim 201 status on POST. However, Response B explicitly uses CreatedAtAction and includes a GetById action to support it ('A GetById action is included so CreatedAtAction can generate the Location header'). Response A mentions '201 Created' but with only 2 endpoints (no GetById) and 735 chars, it likely uses Created() or a simpler approach rather than proper CreatedAtAction with a named action reference. Response B's approach is the correct REST pattern.
        skill    (MuchBetter)  Uses sealed record DTOs with proper naming (CreateOrderRequest, OrderResponse)
              Response B explicitly uses sealed records (output says 'Sealed positional record DTO' and 'Sealed record with validation'). Response A uses plain classes — the truncated file_text clearly shows 'public class OrderResponse' and 'public class CreateOrderRequest'. Both use proper naming conventions, but the sealed record requirement is only met by Response B.
        skill    (MuchBetter)  Date/time properties use DateTimeOffset, not DateTime
              Response B explicitly states 'DateTimeOffset used for PlacedAt' in its output summary. Response A never mentions DateTimeOffset and given the compact file sizes, likely uses DateTime. This is an important distinction for proper timezone handling in APIs.
        skill    (MuchBetter)  All request and response DTOs include XML doc summary comments
              Response B's file_text clearly shows XML doc comments (e.g., OrderResponse starts with '/// <summary>Represents an order returned b...' and OrderStatus starts with '/// ...'). The larger file sizes (294 vs 134 for OrderStatus, 553 vs 153 for CreateOrderRequest) further confirm extensive documentation. Response A's compact file sizes leave no room for XML doc comments, and none are visible in the truncated file_text.


1/1 skills passed validation

JSON results written to C:\temp\skills\validator-output\20260401-025451\results.json
Markdown summary written to C:\temp\skills\validator-output\20260401-025451\summary.md                                                                                                                                                                                                                                                                                  
{Ansi.ClearLine}                                                                        

@mikekistler

sayedihashimi and others added 12 commits April 1, 2026 00:24
- Create dotnet-aspnet plugin (reserved name for ASP.NET Core skills)
- Add dotnet-webapi skill for Web API endpoint creation with proper
  HTTP semantics, OpenAPI metadata, error handling, and EF Core wiring
- Add eval.yaml with 5 scenarios: CRUD API, EF migration usage,
  error handling, OpenAPI setup, and controller-based projects
- Update marketplace.json (both copies), CODEOWNERS, and README.md

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Reduce prompt scope in the two slowest scenarios to lower agent
execution time (the dominant cost in eval runs):

Scenario 1 - CRUD Minimal API (600s -> 240s):
- Reduce from 5 endpoints to 3 (GET list, GET by ID, POST)
- Remove Category entity and EF Core/SQLite, use in-memory service
- Remove OpenAPI requirements (already tested in dedicated scenario)
- Trim assertions from 6 to 3, rubric items from 12 to 7

Scenario 2 - Controller-based endpoint (360s -> 240s):
- Remove OrderItems sub-entity, keep Order -> Customer relationship
- Reduce from full CRUD to 3 endpoints (list, get, create)
- Trim rubric items from 8 to 6

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Trim SKILL.md from 497 to 415 lines by removing guidance that belongs
in other skills:

- Remove standalone 'Seal all types by default' section (general C#)
- Gut Step 6 'Wire up data access' to keep only the service layer
  pattern; remove DbContext, migrations, HasData, Fluent API, and
  AsNoTracking guidance (belongs in optimizing-ef-core-queries skill)
- Remove EF Core items from Validation checklist and Common Pitfalls
- Remove EF Core Migrations link from More Info
- Update frontmatter to remove 'data access wiring' from USE FOR
- Update eval rubric to remove DbContext reference

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Swashbuckle restriction now applies only to .NET 9+ projects;
  projects targeting .NET 8 or earlier can still use Swashbuckle
- Remove pagination section from Step 3 (PaginatedResponse record,
  page size defaults) and all related references in validation
  checklist, common pitfalls, frontmatter, service layer example,
  .http sample, and eval.yaml scenarios

SKILL.md: 415 -> 374 lines

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Reduce from 3 endpoints to 2 (GET list + POST create), drop service
layer and customer relationship from requirements, trim rubric from
5 to 4 items, and lower timeout from 240s to 180s.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Merge the OpenAPI scenario into the CRUD scenario to reduce from 4 to 3
test cases. Add assertions and rubric items for DateTimeOffset, XML doc
comments, enum string serialization, Middleware folder placement, and
OpenAPI metadata across all scenarios. Enrich prompts with date/time and
enum fields to naturally exercise the new requirements.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 1, 2026 14:19
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a new dotnet-webapi skill under the dotnet-aspnet plugin, along with evaluation scenarios to validate the skill’s guidance for ASP.NET Core Web APIs (minimal APIs + controller-based extensions, OpenAPI metadata, and ProblemDetails-based error handling).

Changes:

  • Added a new dotnet-webapi skill document describing recommended patterns for DTOs, HTTP semantics, OpenAPI setup, and global error handling.
  • Added a new dotnet-webapi skill-validator eval suite covering minimal API CRUD + OpenAPI, ProblemDetails/IExceptionHandler error handling, and extending a controller-based project.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

File Description
tests/dotnet-aspnet/dotnet-webapi/eval.yaml New eval scenarios and assertions for validating the dotnet-webapi skill behavior.
plugins/dotnet-aspnet/skills/dotnet-webapi/SKILL.md New skill guidance for ASP.NET Core Web API endpoint creation/modification, OpenAPI, and global error handling.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Co-authored-by: Mike Kistler <mikekistler@microsoft.com>
Copilot AI review requested due to automatic review settings April 6, 2026 22:28
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
sayedihashimi and others added 3 commits April 6, 2026 18:29
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 9 comments.

Comments suppressed due to low confidence (1)

tests/dotnet-aspnet/dotnet-webapi/eval.yaml:134

  • Scenario 3’s rubric requires POST to return CreatedAtAction, but the assertions don’t check for it. Adding an output_contains: "CreatedAtAction" (or similar) assertion would prevent regressions when the judge fails or is unavailable.
        value: "ControllerBase"
      - type: "output_contains"
        value: "[ApiController]"
      - type: "output_contains"
        value: "CancellationToken"
      - type: "output_not_matches"
        pattern: "app\\.(MapGet|MapPost|MapPut|MapDelete|MapPatch)|\\b(MapGet|MapPost|MapPut|MapDelete|MapPatch)\\b"
      - type: "output_contains"
        value: "DateTimeOffset"
      - type: "output_matches"
        pattern: "/// <summary>"
    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"
    timeout: 600


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- Remove non-existent dotnet-csharp skill reference from frontmatter
- Fix escaped code fences in JSON serialization section
- Scope strict JSON serialization guidance to new projects only
- Use enum type in DTO examples for consistency with enum guidance
- Avoid leaking exception.Message in ProblemDetails.Detail
- Add CancellationToken assertion to eval scenario 1
- Update .http file example to use enum string value

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@sayedihashimi
Copy link
Copy Markdown
Member Author

@mikekistler the PR is ready for your review

Copy link
Copy Markdown

@mikekistler mikekistler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! 👍

I suggested one more minor improvement that gave better results in my local tests.

Co-authored-by: Mike Kistler <mikekistler@microsoft.com>
Copilot AI review requested due to automatic review settings April 8, 2026 04:15
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 8, 2026 04:28
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +343 to +351
await httpContext.Response.WriteAsJsonAsync(new ProblemDetails
{
Status = statusCode,
Title = title,
// Do not use exception.Message here — it may leak sensitive internal details.
// Use a safe, user-facing message instead.
Detail = title,
Instance = httpContext.Request.Path
}, cancellationToken);
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the custom IExceptionHandler example, WriteAsJsonAsync(new ProblemDetails { ... }) will default the response content-type to application/json. For RFC 7807 interoperability, set the content type to application/problem+json (e.g., via the contentType parameter on WriteAsJsonAsync, or by setting httpContext.Response.ContentType before writing).

Suggested change
await httpContext.Response.WriteAsJsonAsync(new ProblemDetails
{
Status = statusCode,
Title = title,
// Do not use exception.Message here — it may leak sensitive internal details.
// Use a safe, user-facing message instead.
Detail = title,
Instance = httpContext.Request.Path
}, cancellationToken);
await httpContext.Response.WriteAsJsonAsync(
new ProblemDetails
{
Status = statusCode,
Title = title,
// Do not use exception.Message here — it may leak sensitive internal details.
// Use a safe, user-facing message instead.
Detail = title,
Instance = httpContext.Request.Path
},
contentType: "application/problem+json",
cancellationToken: cancellationToken);

Copilot uses AI. Check for mistakes.
Comment on lines +8 to +12
The API should have these endpoints:
- GET /api/products (list all)
- GET /api/products/{id} (get by ID)
- POST /api/products (create a product)

Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This scenario’s endpoint list only includes GET (list), GET (by ID), and POST (create), but the scenario name says “CRUD”. Either rename the scenario to match the three endpoints, or add update/delete endpoints so it is actually CRUD (and can validate the corresponding HTTP semantics).

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants