dotnet deploy optimize skill - #11
Conversation
Comprehensive deployment optimization skill for .NET 8+ apps covering: - Publish modes (framework-dependent, self-contained, single-file, R2R, Native AOT) - Publish setting compatibility matrix - Trimming and tree-shaking - Docker image optimization - CI/CD pipeline tuning - Configuration and secrets management - Health checks and readiness probes
Critical fixes: - Add missing ReadyToRun + SelfContained=false conflict row - Add Worker Service-specific health check guidance (Kestrel, publisher, TCP) - Broaden secrets check to all appsettings*.json files Moderate fixes: - Add dotnet publish CLI command example alongside XML properties - Short-circuit Step 3 (trimming) when AOT is chosen - Tighten Worker Service detection to require BackgroundService/IHostedService - Add AOT vs JIT tiered compilation trade-off for long-running workloads - Add skip guard on Step 7 for apps with no config files
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Users ask about fast startup and small binaries rather than technical terms like Native AOT and trimming. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds a new .NET deployment optimization skill intended to help users choose appropriate dotnet publish settings (trimming/AOT/single-file), plus an eval suite to validate recommendations across common app types.
Changes:
- Introduces
dotnet-deploy-optimizeskill documentation covering publish modes, trimming, Native AOT, Docker, CI/CD, config, and health checks. - Adds
dotnet-deploy-optimizeevaluation scenarios for a Web API, conflicting publish properties, and a Worker Service.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 7 comments.
| File | Description |
|---|---|
| src/dotnet/skills/dotnet-deploy-optimize/SKILL.md | New skill content describing a workflow for deployment/publish optimization and operational readiness. |
| src/dotnet/tests/dotnet-deploy-optimize/eval.yaml | New eval scenarios to validate the skill’s recommendations across project types and settings. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| 1. Option A — Add a minimal Kestrel endpoint for health checks: | ||
|
|
||
| ```csharp | ||
| builder.Services.AddHealthChecks() | ||
| .AddCheck("self", () => HealthCheckResult.Healthy()); | ||
|
|
||
| builder.WebHost.UseKestrel(o => o.ListenAnyIP(8080)); | ||
| var app = builder.Build(); | ||
| app.MapHealthChecks("/healthz"); | ||
| ``` |
There was a problem hiding this comment.
The Worker Service health-check snippet uses builder.WebHost.UseKestrel(...), builder.Build(), and app.MapHealthChecks(...) without showing where builder comes from. As written, it won’t compile in a typical Worker Service template (Host.CreateDefaultBuilder / HostApplicationBuilder) and may confuse users. Suggest providing a complete, self-contained example that matches the Worker template (or explicitly state this option switches to a WebApplicationBuilder-based minimal host alongside the worker).
| <PublishAot>true</PublishAot> | ||
| <PublishSingleFile>true</PublishSingleFile> | ||
| <ReadyToRun>true</ReadyToRun> | ||
| <SelfContained>false</SelfContained> | ||
| </PropertyGroup> |
There was a problem hiding this comment.
The eval fixture uses <ReadyToRun>true</ReadyToRun>, but the publish property name is PublishReadyToRun. Using the wrong property here makes the scenario less realistic and can cause the agent to learn/emit an invalid setting. Recommend switching the fixture (and rubric wording) to PublishReadyToRun.
| app.Run(); | ||
| assertions: | ||
| - type: "output_contains" | ||
| value: "conflict" |
There was a problem hiding this comment.
This scenario’s assertion only checks for the literal word "conflict", which doesn’t strongly validate the expected behavior (and may fail if the recommendation uses synonyms like "incompatible"). Consider asserting for the specific properties involved (e.g., PublishAot, PublishSingleFile, PublishReadyToRun, SelfContained) or using an output_matches regex that requires mentioning at least two of them.
| value: "conflict" | |
| value: "PublishAot" | |
| - type: "output_contains" | |
| value: "PublishSingleFile" | |
| - type: "output_contains" | |
| value: "ReadyToRun" | |
| - type: "output_contains" | |
| value: "SelfContained" |
| var builder = Host.CreateDefaultBuilder(args); | ||
| builder.ConfigureServices(services => | ||
| { | ||
| services.AddHostedService<Worker>(); | ||
| }); | ||
| var host = builder.Build(); |
There was a problem hiding this comment.
In the Worker Service fixture, Host.CreateDefaultBuilder(args) returns an IHostBuilder where ConfigureServices typically takes (HostBuilderContext, IServiceCollection) rather than a single services parameter. As written, the snippet won’t compile; consider adjusting the fixture to a valid Worker template so the scenario reflects real-world code.
| var builder = Host.CreateDefaultBuilder(args); | |
| builder.ConfigureServices(services => | |
| { | |
| services.AddHostedService<Worker>(); | |
| }); | |
| var host = builder.Build(); | |
| using Microsoft.Extensions.Hosting; | |
| var host = Host.CreateDefaultBuilder(args) | |
| .ConfigureServices((context, services) => | |
| { | |
| services.AddHostedService<Worker>(); | |
| }) | |
| .Build(); |
|
|
||
| 1. Read the project file(s) and identify the target framework, output type, and any existing publish settings. | ||
| 2. Check for a `Properties/launchSettings.json`, `appsettings.json`, and `appsettings.*.json` files. | ||
| 3. Note any existing `PublishTrimmed`, `PublishAot`, `PublishSingleFile`, `ReadyToRun`, or `SelfContained` properties. |
There was a problem hiding this comment.
The skill refers to the publish setting as ReadyToRun, but in .NET/MSBuild the publish property is PublishReadyToRun (see other skills in this repo). Using ReadyToRun here will mislead readers and the later compatibility matrix/rubric. Recommend renaming to PublishReadyToRun throughout (including the eval fixtures).
| 3. Note any existing `PublishTrimmed`, `PublishAot`, `PublishSingleFile`, `ReadyToRun`, or `SelfContained` properties. | |
| 3. Note any existing `PublishTrimmed`, `PublishAot`, `PublishSingleFile`, `PublishReadyToRun`, or `SelfContained` properties. |
| | Setting A | Setting B | Outcome | Explanation | | ||
| |-----------|-----------|---------|-------------| | ||
| | `PublishAot` | `PublishSingleFile` | **Conflict** | AOT produces a single native binary by default; `PublishSingleFile` is for IL-based apps and is ignored with AOT | | ||
| | `PublishAot` | `ReadyToRun` | **Conflict** | ReadyToRun pre-compiles IL to native via crossgen; AOT replaces the IL pipeline entirely, making R2R meaningless | | ||
| | `PublishAot` | `SelfContained=false` | **Conflict** | AOT output is always self-contained; setting `SelfContained` to false is contradictory and will cause a build error | |
There was a problem hiding this comment.
In the compatibility matrix, the outcome is marked Conflict but the explanation says the setting is "ignored"/"meaningless". That reads like a redundant/no-op combination rather than a hard conflict (build error). Consider changing the outcome wording (e.g., "Redundant/ignored") so the guidance is unambiguous.
| - Heavy use of `System.Reflection` and using string representations of types, strongly typed reflection is not problematic | ||
| - Dynamic assembly loading | ||
| - `System.Text.Json` source generators not configured | ||
| - COM interop | ||
| - Check trim-compatibility of dependencies, including from nuget |
There was a problem hiding this comment.
The trimming bullet is a run-on sentence and hard to parse ("Heavy use of ... , strongly typed reflection..."). Also, "nuget" should be capitalized as "NuGet" here (and again in the AOT section). Recommend rewriting this bullet into clearer sub-bullets and fixing capitalization.
| - Heavy use of `System.Reflection` and using string representations of types, strongly typed reflection is not problematic | |
| - Dynamic assembly loading | |
| - `System.Text.Json` source generators not configured | |
| - COM interop | |
| - Check trim-compatibility of dependencies, including from nuget | |
| - Reflection usage: | |
| - Heavy use of `System.Reflection` APIs that rely on string-based type or member names (for example, `Type.GetType("Namespace.TypeName")`) | |
| - Strongly typed reflection (such as `typeof`, `nameof`, or expression-based access) is generally trim-safe | |
| - Dynamic assembly loading | |
| - `System.Text.Json` source generators not configured | |
| - COM interop | |
| - Check trim-compatibility of dependencies, including from NuGet |
The model already scores 5/5 on conflict detection without guidance. The compatibility table added ~300 tokens without improving results, and the skill was flagged as approaching the 'comprehensive' range where gains diminish. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add prominent warning against defaulting to AOT for long-running services; explain JIT tiered compilation and dynamic PGO benefits - Add workload lifetime decision point before recommending AOT - Reorder worker health check options from lightest to heaviest - Add trade-off callout for adding Kestrel to worker services - Present file-based and TCP probes as lighter alternatives Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
AOT, R2R, and tiered JIT are orthogonal trade-offs (startup, binary size, dependencies, steady-state throughput). Present a comparison table so the user can choose based on what they value, rather than prescribing based on long-running vs short-lived. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
well, this was my first attempt and I do not think it has the right fitness. but parts may be interesting
|
|
the highest value of this proposed skill was the health check, which another proposed skill covers |
…date+cleanup step Restore content lost when orchestrator was rewritten as pure dispatcher, plus add preventative guidance addressing the three regressions found in run 25504147640 (resolution dropped from 39%->17% vs run 25497220848). orchestrator (code-testing-generator.agent.md): - Step 1: reference unit-test-generation.prompt.md and pre-pipeline git stash - Step 4: implementer dispatch prompt now embeds test-strength rubric (concrete-value assertions, N>=3 collection inputs, full-equality, no toBeTruthy-only) and file-location rules - Step 8: restore Coverage Gap Iteration (re-research/plan/implement narrowed scope when rubric items remain uncovered) - Step 9 NEW: Validate-and-cleanup dispatch to code-testing-builder which has terminal/edit access. Removes .testagent/, runs git diff --name-only, reverts SUSPICIOUS files (env/cfg/toml/source-outside-test). Addresses 6/12 manifest_fail cases caused by .testagent/ leaking into the patch. - Rules: add dotnet#10 (cleanup mandatory) and dotnet#11 (test strength belongs in implementer prompt, not tester post-hoc check) implementer (code-testing-implementer.agent.md): - Step 4a NEW: Test strength requirements with concrete bad/good examples, reserved-name keys for property iteratees, mutation-resistance check - Step 4b NEW: File-location and side-effect rules with naming decision tree - Rules: add dotnet#6 (test strength non-negotiable) and dotnet#7 (stay inside test dirs) planner (code-testing-planner.agent.md): - Step 4: Add allowed/forbidden file targets, naming decision tree, and scenario depth requirement (N>=3 elements with concrete expected values) Diagnosis from run 25504147640: - 10/41 patches contained .testagent/research.md or plan.md (no cleanup) - mutation_fail jumped from 18 to 24 (single-element collection inputs, type-only assertions allowed weaker tests through) - app-2ad2720a modified tests/test.env DB port (no rule against config edits) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…otnet - Startup-style config, NHibernate/MassTransit/Serilog notes
Proposing a skill for offering recommendation on how to optimize a .NET Core application during publish