From 0d4165ef3d0273ed45affb75a3cd327085f08522 Mon Sep 17 00:00:00 2001 From: Chet Husk Date: Mon, 9 Feb 2026 12:34:23 -0600 Subject: [PATCH 1/4] add skill for triaging SDK build-related issues --- .claude/skills/investigate-sdk-issue/SKILL.md | 190 ++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 .claude/skills/investigate-sdk-issue/SKILL.md diff --git a/.claude/skills/investigate-sdk-issue/SKILL.md b/.claude/skills/investigate-sdk-issue/SKILL.md new file mode 100644 index 000000000000..8d3d5d440e26 --- /dev/null +++ b/.claude/skills/investigate-sdk-issue/SKILL.md @@ -0,0 +1,190 @@ +--- +name: investigate-sdk-issue +description: Investigate a GitHub issue filed against the .NET SDK (or related dotnet repos) by reproducing the problem, analyzing build logs, tracing through MSBuild targets, and producing a root cause analysis with links to the relevant source code and a suggested fix. Use this when pointed at a GitHub issue URL or when asked to investigate an SDK build/publish/pack behavior problem. +argument-hint: [issue-number] +--- + +# Investigate .NET SDK Issue + +You are investigating a GitHub issue to determine the root cause of unexpected .NET SDK behavior. Your goal is to produce a detailed root cause analysis in GitHub-flavored markdown, with links to the specific source code that causes the problem and a suggested fix. + +## Step 1: Read the issue + +Use `gh issue view --repo dotnet/sdk --json title,body,comments,labels` to fetch the issue details. + +Extract from the issue: +- **Symptom**: What the user observes (e.g., unexpected files in output, build error, wrong behavior). +- **Expected behavior**: What the user expected instead. +- **Reproduction steps**: How to reproduce the issue. +- **Attachments**: Look for linked binlog files (`.binlog` or `.zip` containing binlogs), reproduction projects (`.zip`, `.tar`), or inline project files. +- **Environment**: SDK version, OS, target framework, any special properties (`PublishAot`, `PublishSingleFile`, `SelfContained`, etc.). + +## Step 2: Obtain or create a reproduction + +### If the issue includes a binlog + +1. Download the binlog attachment using `gh` or `curl`. +2. If it is a `.zip` or `.tar`, extract it with `unzip` or `tar`. +3. Proceed to **Step 3**. + +### If the issue includes a reproduction project but no binlog + +1. Download and extract the reproduction project. +2. Restore and build/publish/pack (matching the scenario described in the issue) with a binary log: + ```bash + dotnet restore + dotnet publish -c Release /bl:1.binlog + ``` + Use the `binlog-generation` skill conventions: name binlogs with incrementing numbers (`1.binlog`, `2.binlog`, etc.). +3. If the build/publish succeeds, inspect the output directory to confirm the reported symptom. +4. Proceed to **Step 3**. + +### If the issue has only a description (no attachments) + +1. Create a minimal reproduction project in a temporary directory based on the issue description. +2. Build/publish/pack with a binary log as above. +3. Confirm the symptom is reproducible before proceeding. + +If you cannot reproduce the issue, state what you tried and what you observed, then stop. + +## Step 3: Analyze the binlog + +Load the binlog using the binlog MCP tools: + +``` +load_binlog with path: "" +``` + +### 3a: Get an overview + +Run these in parallel to get oriented: +- `list_projects` — identify the projects involved. +- `get_diagnostics` — check for errors/warnings that may be relevant. +- `get_project_target_list` for the main project — see the full target execution order. + +### 3b: Search for the symptom + +Use `search_binlog` to find traces of the problematic behavior. Search for: +- File names or paths mentioned in the issue (e.g., `resources.dll`, `appsettings.json`). +- Item group names that control the behavior (e.g., `ResolvedFileToPublish`, `IntermediateSatelliteAssembliesWithTargetPath`, `_ResolvedCopyLocalPublishAssets`). +- Target names related to the scenario (e.g., for publish issues search for `$target Publish`, `$target ComputeResolvedFilesToPublishList`, `$target CopyFilesToPublishDirectory`). +- Property names that gate behavior (e.g., `PublishAot`, `PublishSingleFile`, `SelfContained`). + +### 3c: Trace the data flow + +Once you find the problematic item or file, trace **how it got there**: +1. Find the target that first adds the item (use `search_binlog` with the item name). +2. Use `get_target_info_by_id` or `get_target_info_by_name` to understand each target's role and dependencies. +3. Use `list_tasks_in_target` to see what tasks run inside each target. +4. Use `get_task_info` to inspect specific task parameters and outputs. +5. Use `get_evaluation_items_by_name` and `get_evaluation_properties_by_name` to check how MSBuild properties and items are set during evaluation. + +Follow the chain: which target produces the item, which target consumes it, which target should have removed/filtered it but didn't. + +### 3d: Identify key properties and conditions + +Search for properties that should be gating the behavior: +``` +search_binlog with query: "PropertyName" +``` + +Check whether relevant conditions are being evaluated. For example, if the issue is about NativeAOT, check whether `PublishAot` is being tested in the targets that should be filtering the output. + +## Step 4: Read the MSBuild targets source code + +Once the binlog analysis points to specific targets, read the actual target definitions in the source repos to understand the logic. The targets may come from several repositories: + +### Repository locations + +| Repository | What it contains | Key target directories | +|---|---|---| +| **dotnet/sdk** | SDK publish, build, pack targets | `src/Tasks/Microsoft.NET.Build.Tasks/targets/` | +| **dotnet/msbuild** | Core MSBuild targets (Copy, Csc, RAR, etc.) | `src/Tasks/Microsoft.Build.Tasks/` | +| **dotnet/runtime** | NativeAOT build integration, runtime pack targets | `src/coreclr/nativeaot/BuildIntegration/`, `src/installer/managed/` | + +### Finding targets + +Use `Grep` to search for target names in the local clones of these repos. If a local clone is not available, use `gh api` or `WebFetch` to read files from GitHub directly. + +When reading targets, pay attention to: +- **`Condition` attributes** — is the target or item group conditioned on the right properties? +- **`BeforeTargets` / `AfterTargets` / `DependsOnTargets`** — how does this target fit into the pipeline? +- **`Include` / `Remove` on item groups** — what items are added or removed, and are there missing removals? +- **Comments** — the SDK targets often have comments explaining intent, which helps identify whether a gap is intentional or accidental. + +### Cross-referencing between repos + +The NativeAOT publish pipeline is a good example of cross-repo interaction: +- The SDK defines `ComputeResolvedFilesToPublishList` in `Microsoft.NET.Publish.targets`. +- The ILC (NativeAOT compiler) defines `ComputeLinkedFilesToPublish` in `Microsoft.NETCore.Native.Publish.targets` which hooks in via `BeforeTargets`. +- Both must agree on which item groups to clean up. + +When you find such cross-repo interactions, read the targets from **both** repos to understand the full picture. + +## Step 5: Search for prior art and existing patterns + +Before suggesting a fix, search the codebase for how similar problems have been solved: + +1. **Search for analogous conditions**: If the fix is to add a condition like `Condition="'$(PublishAot)' != 'true'"`, search the targets for existing uses of that pattern to confirm it's an established convention. +2. **Search git history**: Use `git log --all --oneline -S "SearchTerm" -- "*.targets"` to find commits that modified related targets. +3. **Search for related issues/PRs**: Use `gh search issues` or `gh search prs` in the relevant repo to find prior discussions. +4. **Check official documentation**: Use the `microsoft_docs_search` and `microsoft_docs_fetch` tools to find relevant documentation about the feature area (e.g., NativeAOT publishing, single-file deployment, satellite assembly handling). + +## Step 6: Write the root cause analysis + +Produce a markdown document with the following structure: + +```markdown +## Root Cause Analysis + +<1-2 sentence summary of why the bug happens.> + +### How flow through the pipeline + +**Step 1: ** + + + +**Step 2: ** + + + +**Step N: ** + + + +### Suggested fix + + +``` + +### Link format + +Always link to source code on GitHub using permanent URLs to the `main` branch of the appropriate repo: + +- dotnet/sdk: `https://github.com/dotnet/sdk/blob/main/src/Tasks/Microsoft.NET.Build.Tasks/targets/#L-L` +- dotnet/runtime: `https://github.com/dotnet/runtime/blob/main/src/coreclr/nativeaot/BuildIntegration/#L-L` +- dotnet/msbuild: `https://github.com/dotnet/msbuild/blob/main/src/#L-L` + +When linking, prefer linking to line ranges that show the full target or item group, not just a single line. + +### Quality checklist + +Before presenting the analysis, verify: +- [ ] The symptom described in the issue matches what you observe in the binlog. +- [ ] You have traced the full data flow from source to problematic output. +- [ ] You have identified the specific target/item group/condition that is missing or incorrect. +- [ ] All GitHub links point to the correct files and line ranges. +- [ ] The suggested fix follows existing patterns in the codebase. +- [ ] The analysis is written in GitHub-flavored markdown suitable for posting as an issue comment. + +## Tips + +- The binlog is the single source of truth. Always start there rather than guessing from target files alone. +- Use `search_binlog` liberally — it supports the full MSBuild Structured Log Viewer query language. Use `$target`, `$task`, `under()`, `not()`, and property matching to narrow results. +- When tracing item flow, search for the item group name (e.g., `IntermediateSatelliteAssembliesWithTargetPath`) rather than file paths — this shows you every target that adds or removes from that group. +- The SDK publish pipeline has several "compute" targets that run before "copy" targets. Issues often stem from a "compute" target that fails to filter items for a specific scenario (AOT, single-file, trimming, etc.). +- Cross-repo issues (e.g., between dotnet/sdk and dotnet/runtime) are common because the NativeAOT, ILLink, and single-file targets hook into the SDK pipeline via `BeforeTargets`/`AfterTargets` and must keep their item group manipulations in sync. +- Use `get_evaluation_properties_by_name` to verify that properties like `PublishAot` are actually set to the expected values during evaluation — misconfigured properties are a common root cause. +- When the build fails before the problematic stage (e.g., link failure prevents seeing publish output), the binlog still contains all the target/item setup — you can trace the data flow up to the point of failure and infer what would happen next by reading the target definitions. From 1eb4be96d6de972128c1ed1742b613343d9841e5 Mon Sep 17 00:00:00 2001 From: Chet Husk Date: Mon, 9 Feb 2026 12:43:33 -0600 Subject: [PATCH 2/4] Update .claude/skills/investigate-sdk-issue/SKILL.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .claude/skills/investigate-sdk-issue/SKILL.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.claude/skills/investigate-sdk-issue/SKILL.md b/.claude/skills/investigate-sdk-issue/SKILL.md index 8d3d5d440e26..4607ab8edd7b 100644 --- a/.claude/skills/investigate-sdk-issue/SKILL.md +++ b/.claude/skills/investigate-sdk-issue/SKILL.md @@ -161,13 +161,13 @@ If there are multiple viable approaches, list them with trade-offs.> ### Link format -Always link to source code on GitHub using permanent URLs to the `main` branch of the appropriate repo: +Always link to source code on GitHub using links to the `main` branch of the appropriate repo, or permalinks to a specific commit when you need a stable reference: - dotnet/sdk: `https://github.com/dotnet/sdk/blob/main/src/Tasks/Microsoft.NET.Build.Tasks/targets/#L-L` - dotnet/runtime: `https://github.com/dotnet/runtime/blob/main/src/coreclr/nativeaot/BuildIntegration/#L-L` - dotnet/msbuild: `https://github.com/dotnet/msbuild/blob/main/src/#L-L` -When linking, prefer linking to line ranges that show the full target or item group, not just a single line. +When linking, prefer linking to line ranges that show the full target or item group, not just a single line. For long-lived root-cause analyses that must remain stable as the repository evolves, use GitHub permalinks that include a specific commit SHA instead of `main`. ### Quality checklist From 68559db87203cedb67b30bc2ca5548ded931c194 Mon Sep 17 00:00:00 2001 From: Chet Husk Date: Mon, 9 Feb 2026 13:35:37 -0600 Subject: [PATCH 3/4] Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .claude/skills/investigate-sdk-issue/SKILL.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.claude/skills/investigate-sdk-issue/SKILL.md b/.claude/skills/investigate-sdk-issue/SKILL.md index 4607ab8edd7b..52c84bbe533c 100644 --- a/.claude/skills/investigate-sdk-issue/SKILL.md +++ b/.claude/skills/investigate-sdk-issue/SKILL.md @@ -10,8 +10,12 @@ You are investigating a GitHub issue to determine the root cause of unexpected . ## Step 1: Read the issue -Use `gh issue view --repo dotnet/sdk --json title,body,comments,labels` to fetch the issue details. +Use `gh issue view` to fetch the issue details: +- If you are given a full GitHub issue URL like `https://github.com/OWNER/REPO/issues/123`, extract `OWNER/REPO` and the issue number, then run: + `gh issue view 123 --repo OWNER/REPO --json title,body,comments,labels` +- If you are only given an issue number for the .NET SDK repo, assume `dotnet/sdk` as the default: + `gh issue view --repo dotnet/sdk --json title,body,comments,labels` Extract from the issue: - **Symptom**: What the user observes (e.g., unexpected files in output, build error, wrong behavior). - **Expected behavior**: What the user expected instead. @@ -104,7 +108,7 @@ Once the binlog analysis points to specific targets, read the actual target defi ### Finding targets -Use `Grep` to search for target names in the local clones of these repos. If a local clone is not available, use `gh api` or `WebFetch` to read files from GitHub directly. +Use `grep` to search for target names in the local clones of these repos. If a local clone is not available, use `gh api` or `WebFetch` to read files from GitHub directly. When reading targets, pay attention to: - **`Condition` attributes** — is the target or item group conditioned on the right properties? @@ -126,7 +130,7 @@ When you find such cross-repo interactions, read the targets from **both** repos Before suggesting a fix, search the codebase for how similar problems have been solved: 1. **Search for analogous conditions**: If the fix is to add a condition like `Condition="'$(PublishAot)' != 'true'"`, search the targets for existing uses of that pattern to confirm it's an established convention. -2. **Search git history**: Use `git log --all --oneline -S "SearchTerm" -- "*.targets"` to find commits that modified related targets. +2. **Search git history**: Use `git log --all --oneline -S "SearchTerm" -- "**/*.targets"` to find commits that modified related targets. 3. **Search for related issues/PRs**: Use `gh search issues` or `gh search prs` in the relevant repo to find prior discussions. 4. **Check official documentation**: Use the `microsoft_docs_search` and `microsoft_docs_fetch` tools to find relevant documentation about the feature area (e.g., NativeAOT publishing, single-file deployment, satellite assembly handling). From ffd9cc526e78caacee05026166218fb3a2959b6c Mon Sep 17 00:00:00 2001 From: Chet Husk Date: Mon, 9 Feb 2026 19:03:11 -0600 Subject: [PATCH 4/4] create subagents instead --- .claude/agents | 1 + .../agents/analyze-sdk-issue.agent.md | 62 ++----------- .github/agents/reproduce-sdk-issue.agent.md | 90 +++++++++++++++++++ 3 files changed, 100 insertions(+), 53 deletions(-) create mode 120000 .claude/agents rename .claude/skills/investigate-sdk-issue/SKILL.md => .github/agents/analyze-sdk-issue.agent.md (73%) create mode 100644 .github/agents/reproduce-sdk-issue.agent.md diff --git a/.claude/agents b/.claude/agents new file mode 120000 index 000000000000..fa084a095e6e --- /dev/null +++ b/.claude/agents @@ -0,0 +1 @@ +../.github/agents \ No newline at end of file diff --git a/.claude/skills/investigate-sdk-issue/SKILL.md b/.github/agents/analyze-sdk-issue.agent.md similarity index 73% rename from .claude/skills/investigate-sdk-issue/SKILL.md rename to .github/agents/analyze-sdk-issue.agent.md index 52c84bbe533c..5ec7777eb3b3 100644 --- a/.claude/skills/investigate-sdk-issue/SKILL.md +++ b/.github/agents/analyze-sdk-issue.agent.md @@ -1,57 +1,15 @@ --- -name: investigate-sdk-issue -description: Investigate a GitHub issue filed against the .NET SDK (or related dotnet repos) by reproducing the problem, analyzing build logs, tracing through MSBuild targets, and producing a root cause analysis with links to the relevant source code and a suggested fix. Use this when pointed at a GitHub issue URL or when asked to investigate an SDK build/publish/pack behavior problem. -argument-hint: [issue-number] +name: analyze-sdk-issue +description: Analyze a binary log (binlog) from a .NET SDK build to determine the root cause of a reported issue. Traces MSBuild targets, inspects item and property flow, reads SDK source code, and produces a structured root cause analysis with links to the relevant source and a suggested fix. Use this when you already have a binlog and need to understand why a build/publish/pack behaves incorrectly. --- -# Investigate .NET SDK Issue +# Analyze .NET SDK Issue from Binlog -You are investigating a GitHub issue to determine the root cause of unexpected .NET SDK behavior. Your goal is to produce a detailed root cause analysis in GitHub-flavored markdown, with links to the specific source code that causes the problem and a suggested fix. +You are analyzing a binary log (binlog) to determine the root cause of unexpected .NET SDK behavior. Your goal is to produce a detailed root cause analysis in GitHub-flavored markdown, with links to the specific source code that causes the problem and a suggested fix. -## Step 1: Read the issue +You should already have a binlog file available. If you do not have one, ask the user to provide a binlog or use the `reproduce-sdk-issue` agent to create one first. -Use `gh issue view` to fetch the issue details: - -- If you are given a full GitHub issue URL like `https://github.com/OWNER/REPO/issues/123`, extract `OWNER/REPO` and the issue number, then run: - `gh issue view 123 --repo OWNER/REPO --json title,body,comments,labels` -- If you are only given an issue number for the .NET SDK repo, assume `dotnet/sdk` as the default: - `gh issue view --repo dotnet/sdk --json title,body,comments,labels` -Extract from the issue: -- **Symptom**: What the user observes (e.g., unexpected files in output, build error, wrong behavior). -- **Expected behavior**: What the user expected instead. -- **Reproduction steps**: How to reproduce the issue. -- **Attachments**: Look for linked binlog files (`.binlog` or `.zip` containing binlogs), reproduction projects (`.zip`, `.tar`), or inline project files. -- **Environment**: SDK version, OS, target framework, any special properties (`PublishAot`, `PublishSingleFile`, `SelfContained`, etc.). - -## Step 2: Obtain or create a reproduction - -### If the issue includes a binlog - -1. Download the binlog attachment using `gh` or `curl`. -2. If it is a `.zip` or `.tar`, extract it with `unzip` or `tar`. -3. Proceed to **Step 3**. - -### If the issue includes a reproduction project but no binlog - -1. Download and extract the reproduction project. -2. Restore and build/publish/pack (matching the scenario described in the issue) with a binary log: - ```bash - dotnet restore - dotnet publish -c Release /bl:1.binlog - ``` - Use the `binlog-generation` skill conventions: name binlogs with incrementing numbers (`1.binlog`, `2.binlog`, etc.). -3. If the build/publish succeeds, inspect the output directory to confirm the reported symptom. -4. Proceed to **Step 3**. - -### If the issue has only a description (no attachments) - -1. Create a minimal reproduction project in a temporary directory based on the issue description. -2. Build/publish/pack with a binary log as above. -3. Confirm the symptom is reproducible before proceeding. - -If you cannot reproduce the issue, state what you tried and what you observed, then stop. - -## Step 3: Analyze the binlog +## Step 1: Load and orient Load the binlog using the binlog MCP tools: @@ -59,14 +17,12 @@ Load the binlog using the binlog MCP tools: load_binlog with path: "" ``` -### 3a: Get an overview - Run these in parallel to get oriented: - `list_projects` — identify the projects involved. - `get_diagnostics` — check for errors/warnings that may be relevant. - `get_project_target_list` for the main project — see the full target execution order. -### 3b: Search for the symptom +## Step 2: Search for the symptom Use `search_binlog` to find traces of the problematic behavior. Search for: - File names or paths mentioned in the issue (e.g., `resources.dll`, `appsettings.json`). @@ -74,7 +30,7 @@ Use `search_binlog` to find traces of the problematic behavior. Search for: - Target names related to the scenario (e.g., for publish issues search for `$target Publish`, `$target ComputeResolvedFilesToPublishList`, `$target CopyFilesToPublishDirectory`). - Property names that gate behavior (e.g., `PublishAot`, `PublishSingleFile`, `SelfContained`). -### 3c: Trace the data flow +## Step 3: Trace the data flow Once you find the problematic item or file, trace **how it got there**: 1. Find the target that first adds the item (use `search_binlog` with the item name). @@ -85,7 +41,7 @@ Once you find the problematic item or file, trace **how it got there**: Follow the chain: which target produces the item, which target consumes it, which target should have removed/filtered it but didn't. -### 3d: Identify key properties and conditions +### Identify key properties and conditions Search for properties that should be gating the behavior: ``` diff --git a/.github/agents/reproduce-sdk-issue.agent.md b/.github/agents/reproduce-sdk-issue.agent.md new file mode 100644 index 000000000000..dcd6175fef83 --- /dev/null +++ b/.github/agents/reproduce-sdk-issue.agent.md @@ -0,0 +1,90 @@ +--- +name: reproduce-sdk-issue +description: Reproduce a GitHub issue filed against the .NET SDK by reading the issue, downloading or creating a minimal reproduction project, and generating a binary log (binlog). Use this when you need to obtain a binlog for an SDK issue report that doesn't have one, or to verify that a reported problem is reproducible. +--- + +# Reproduce .NET SDK Issue + +You are reproducing a GitHub issue to obtain a binary log (binlog) that captures the problematic .NET SDK behavior. Your goal is to ensure a `.binlog` file (or `.zip` containing one) exists that can be used for root cause analysis. + +## Step 1: Read the issue + +Use `gh issue view` to fetch the issue details: + +- If you are given a full GitHub issue URL like `https://github.com/OWNER/REPO/issues/123`, extract `OWNER/REPO` and the issue number, then run: + `gh issue view 123 --repo OWNER/REPO --json title,body,comments,labels` +- If you are only given an issue number for the .NET SDK repo, assume `dotnet/sdk` as the default: + `gh issue view --repo dotnet/sdk --json title,body,comments,labels` + +Extract from the issue: +- **Symptom**: What the user observes (e.g., unexpected files in output, build error, wrong behavior). +- **Expected behavior**: What the user expected instead. +- **Reproduction steps**: How to reproduce the issue. +- **Attachments**: Look for linked binlog files (`.binlog` or `.zip` containing binlogs), reproduction projects (`.zip`, `.tar`), or inline project files. +- **Environment**: SDK version, OS, target framework, any special properties (`PublishAot`, `PublishSingleFile`, `SelfContained`, etc.). + +## Step 2: Obtain or create a reproduction + +### If the issue already includes a binlog + +1. Download the binlog attachment using `gh` or `curl`. +2. If it is a `.zip` or `.tar`, extract it. +3. Verify the binlog loads correctly (e.g., check file size is non-zero). +4. You are done — report the path to the binlog. + +### If the issue includes a reproduction project but no binlog + +1. Download and extract the reproduction project. +2. Restore and build/publish/pack (matching the scenario described in the issue) with a binary log: + ```bash + dotnet restore + dotnet publish -c Release /bl:1.binlog + ``` + Name binlogs with incrementing numbers (`1.binlog`, `2.binlog`, etc.) if multiple builds are needed. +3. If the build/publish succeeds, inspect the output directory to confirm the reported symptom is present. +4. If the symptom is confirmed, the binlog captures the problematic behavior. You are done. + +### If the issue has only a description (no attachments) + +1. Create a minimal reproduction project in a temporary directory based on the issue description: + - Use the simplest project type that reproduces the issue (e.g., `dotnet new console`, `dotnet new classlib`, `dotnet new webapi`). + - Add only the properties and packages mentioned in the issue (e.g., `true`, `true`). + - Keep the project as small as possible — the goal is a minimal reproduction, not a full application. +2. Build/publish/pack with a binary log: + ```bash + dotnet restore + dotnet publish -c Release /bl:1.binlog + ``` +3. Inspect the output to confirm the reported symptom is present. +4. If the symptom is confirmed, the binlog captures the problematic behavior. You are done. + +### If you cannot reproduce the issue + +State clearly: +- What project configuration you tried. +- What commands you ran. +- What you observed (and how it differs from the reported symptom). +- Any possible reasons the reproduction failed (SDK version mismatch, OS-specific behavior, missing configuration). + +Then stop — do not proceed to analysis without a confirmed reproduction. + +## Step 3: Package the output + +Once you have a binlog that captures the issue: + +1. Note the absolute path to the binlog file. +2. If the reproduction project was created from scratch, keep it alongside the binlog so it can be used for future testing. +3. Summarize what you produced: + - Path to binlog file(s). + - The command that was run to produce each binlog. + - Whether the reported symptom was confirmed. + - Any relevant observations (e.g., "build failed at link stage as expected", "extra files appear in publish output as reported"). + +## Tips + +- Match the user's environment as closely as possible: use the same SDK version, target framework, and build properties they reported. +- If the issue mentions a specific SDK version, check whether you have it installed. If not, note the version mismatch. +- Some issues only manifest during `publish`, not `build` — pay attention to which command the user ran. +- Some issues only manifest with specific configurations like `SelfContained`, `RuntimeIdentifier`, `PublishAot`, or `PublishSingleFile` — make sure these are set correctly in the reproduction project. +- If the issue involves multiple projects (e.g., a solution with several project references), reproduce the full structure rather than simplifying to a single project. +- When downloading attachments from GitHub issues, the URLs are typically in the issue body as markdown links. Use `curl -L` to follow redirects.