MSBuild Release Checklist 18.11
- Dominant language
- C#
- Stars
- 5.5k
- Forks
- 1.5k
- Avg merge
- 1d 8h
- Merged PRs (30d)
- 141
Description
# MSBuild Release Checklist 18.11
> **Phase 0 complete.** Inputs resolved from `eng/Versions.props` on `main` (`VersionPrefix` = `18.11.0`), `darc get-channels`, and the DevDiv wiki ([Dev18.11 Schedule](https://dev.azure.com/devdiv/DevDiv/_wiki/wikis/DevDiv.wiki?pagePath=%2FProduct%20Lifecycle%20and%20Release%2FDev18%20Release%2FDev18.11%20Schedule), [VS Dates](https://dev.azure.com/devdiv/DevDiv/_wiki/wikis/DevDiv.wiki/49807/VS-Dates)).
>
> Verified at instantiation: `vs18.11` does **not** exist on `origin`; DARC channels `VS 18.11` (10800) and `VS 18.12` (10894) both already exist.
>
> ⚠️ **Schedule is very tight.** The Dev18.11 schedule page flags *"Snap moved up a week"* — VS snaps `main` → `rel/insiders` on **Friday 2026-08-28**, only 2 days after branch snap (2026-08-26). Phase 4's "7 days before insiders snap" trigger therefore **cannot** be met; Phases 1–4 must run back-to-back. (Same shape as 18.9 and 18.10.)
## Release Output
Artifacts produced over the course of the release. Record each URL here as the corresponding phase completes so this issue serves as the single index back into every PR / build / tag that defines `{{THIS_RELEASE_EXACT_VERSION}}`.
| Artifact | URL |
|---|---|
| Phase 1.1 — `vs18.11` branch | https://github.com/dotnet/msbuild/tree/vs18.11 (created at `9353559c2c450f8b10cc8d531c7828d38c7063c1`) |
| Phase 1.2d — maestro-configuration PR (channels for `18.11` / `18.12`) | https://dev.azure.com/dnceng/internal/_git/maestro-configuration/pullrequest/64466 |
| Phase 2.3j — maestro-configuration PR (`main`-targeting subs + VMR backflow retargeted, retired-branch cleanup) | https://dev.azure.com/dnceng/internal/_git/maestro-configuration/pullrequest/64468 |
| Phase 3.5 — `main` next-version main-bump PR | https://github.com/dotnet/msbuild/pull/14841 |
| Follow-up — branch retirement + missing `vs18.11` backflow (maestro-configuration) | https://dev.azure.com/dnceng/internal/_git/maestro-configuration/pullrequest/64686 |
| Follow-up — checklist 1.3 retirement audit fix | https://github.com/dotnet/msbuild/pull/14911 |
| Follow-up — remove spurious `vs18.11` backflow (VS-only release) | https://dev.azure.com/dnceng/internal/_git/maestro-configuration/pullrequest/64688 |
| Phase 4.4 — VS insertion PR | _TBD_ |
| Phase 5.1b — official build that produced `{{THIS_RELEASE_EXACT_VERSION}}` | _TBD_ |
| Phase 4.7 — Change Waves Learn page sync PR (visualstudio-docs-pr) | _TBD_ |
| Phase 5.3 — GitHub release tag | https://github.com/dotnet/msbuild/releases/tag/v{{THIS_RELEASE_EXACT_VERSION}} |
---
## Inputs
Fill in these values before starting. Version increments are irregular — they must be specified explicitly.
| Placeholder | Description | Value |
|---|---|---|
| `PREVIOUS_RELEASE_VERSION` | Version being replaced as latest | `18.10` |
| `PREVIOUS_RELEASE_EXACT_VERSION` | The `VersionPrefix` the **previous** release actually shipped as — used by Phase 5.3a to look up its tag. Read it from the previous release's tracking issue, or from `git tag --list 'v18.10.*'`. | _TBD — 18.10 has not GA'd yet (18.10.0 ships 2026-09-08); no `v18.10.*` tag exists. Track in #14562._ |
| `THIS_RELEASE_VERSION` | Version being released now | `18.11` |
| `THIS_RELEASE_EXACT_VERSION` | The `VersionPrefix` that **actually shipped** to customers — determined in Phase 5.1a, **not** assumed. It is usually `18.11.0`, but servicing insertions routinely ship a higher patch. **Not known when first instantiating this checklist — leave blank until Phase 5.1a confirms it.** | _TBD — resolved in Phase 5.1a_ |
| `NEXT_VERSION` | Version that main will be bumped to | `18.12` |
| `BRANCH_SNAP_DATE` | Date we create `vs18.11` from `main`. | `2026-08-26` (Wed) |
| `INSIDERS_SNAP_DATE` | Date VS snaps `main` → `rel/insiders`. Final-branded MSBuild must be in VS `main` **before** this date. From [VS-Dates wiki](https://dev.azure.com/devdiv/DevDiv/_wiki/wikis/DevDiv.wiki/49807/VS-Dates) | `2026-08-28` (Fri) — ⚠️ moved up a week |
| `STABLE_SNAP_DATE` | Date VS snaps `rel/insiders` → `rel/stable`. From [VS-Dates wiki](https://dev.azure.com/devdiv/DevDiv/_wiki/wikis/DevDiv.wiki/49807/VS-Dates) | `2026-09-29` (Tue) |
| `VS_SHIP_DATE` | Date VS ships publicly (GA). Post-GA tasks (nuget.org, docs) happen after this. | `2026-10-13` (Tue) — 18.11.0 Feature Update |
| `PACKAGE_VALIDATION_BASELINE_VERSION` | Latest `18.11.0-..` MSBuild build reachable from `vs18.11` (`` = `PreReleaseVersionLabel`, currently `1`). Used as the ApiCompat baseline for the bumped `main`. **How to determine it:** see the [release skill](https://github.com/dotnet/msbuild/blob/main/.github/skills/release/SKILL.md#how-to-determine-package_validation_baseline_version). | **`18.11.0-1.26426.2`** — official build `20260826.2` at branch point `9353559c2c`, verified on the dotnet-tools feed |
**Derived values** (do not edit — computed from inputs):
- Release branch: `vs18.11`
- DARC channel: `VS 18.11`
- Next DARC channel: `VS 18.12`
- VS insertion target: VS `main` (VS snaps main → insiders → stable on its own schedule)
## Phase 0: Instantiate Release
> **Trigger**: User decides to start a release. Do this first.
- [x] Validate inputs:
- [x] Confirm `eng/Versions.props` on `main` has `VersionPrefix` = `18.11.0` — if not, the inputs are wrong
- [x] Confirm branch `vs18.11` does **not** already exist — if it does, this release was already started
- [x] Confirm DARC channel `VS 18.11` exists: \
`darc get-channels`\
If missing, it should have been created during the previous release (Phase 1.2b "create next channel" step). Create it now: `darc add-channel --name "VS 18.11"`
- [x] Create this tracking issue in dotnet/msbuild with all `{{PLACEHOLDERS}}` replaced
- [ ] As phases complete, record artifact URLs in the **Release Output** table at the top of this checklist.
---
## Phase 1: Branch & Prepare
> **Trigger**: `2026-08-26` reached.
Steps are **sequential** — complete in order.
- [x] **1.0** **Pre-snap team check.** Before snapping the branch, ping the MSBuild team to confirm there is nothing they still need to merge into `main` that should ship in `18.11`. Anything that lands in `main` after Phase 1.1 will go into `18.12` instead.
- [x] **1.1** Create branch `vs18.11` from HEAD of `main` (**requires repo admin rights** — `git push` to `refs/heads/vs*` is restricted; if you don't have permission, ask a repo admin with `vs*` push rights to do it): \
`git push upstream HEAD:refs/heads/vs18.11`
- _If branched too early_ (main has commits that shouldn't be in the release): fast-forward the branch to the correct commit (the one currently inserted into VS main): \
`git push upstream :refs/heads/vs18.11`
> ✅ Pushed `2026-08-26` at `9353559c2c450f8b10cc8d531c7828d38c7063c1` — *"[main] Update dependencies from dotnet/arcade (#14835)"*, the then-HEAD of `origin/main`.
- [x] **1.2** DARC configuration — batch all channel/mapping changes into **one PR** on the [maestro-configuration](https://dev.azure.com/dnceng/internal/_git/maestro-configuration) repo. \
Use `--configuration-branch msbuild-18.11` on every command and `--no-pr` on all but the last:
- [x] **1.2a** Ensure branch-to-channel association exists: \
First check: `darc get-default-channels --channel "VS 18.11" --branch vs18.11 --source-repo https://github.com/dotnet/msbuild` \
If `No matching channels were found.`: \
`darc add-default-channel --channel "VS 18.11" --branch vs18.11 --repo https://github.com/dotnet/msbuild --configuration-branch msbuild-18.11 --no-pr`
> ✅ **No-op** — `(7075) dotnet/msbuild @ vs18.11 -> VS 18.11` already existed, pre-created by the 18.10 release's Phase 1.2c.
- [x] **1.2b** Create DARC channel for **next** release: \
`darc add-channel --name "VS 18.12" --configuration-branch msbuild-18.11 --no-pr` \
_(If channel already exists, this is a no-op.)_
> ✅ **No-op** — channel `VS 18.12` (10894) already existed.
- [x] **1.2c** Pre-create default channel mapping for the **next** release branch (**last command — omit `--no-pr` to create the PR**). The `vs18.12` branch does not exist yet, so pass `-q` (non-interactive) to skip the "branch doesn't exist" prompt — otherwise the command blocks/aborts: \
`darc add-default-channel --channel "VS 18.12" --branch vs18.12 --repo https://github.com/dotnet/msbuild --configuration-branch msbuild-18.11 -q`
> ✅ Executed — the only Phase 1 write, so it created the PR directly.
- [ ] **1.2d** Get the maestro-configuration PR reviewed and merged: https://dev.azure.com/dnceng/internal/_git/maestro-configuration/pullrequest/64466
- [x] **1.3** **Identify predecessor branches that will no longer be supported.** Record the list here — Phase 2.3e uses it to clean up their DARC subscriptions. \
How to identify a retired branch:
- **The combined rule:** a branch paired with both an SDK band and a VS version is retired **only when both lifecycles agree it is out of support**. If only one side says retired but the other is still supported, **keep the branch** — the still-supported lifecycle must keep receiving fixes.
- **SDK lifecycle** — for branches paired with an SDK band, check https://learn.microsoft.com/dotnet/core/porting/versioning-sdk-msbuild-vs#lifecycle. If the paired SDK band is past its support end date, the branch is SDK-retired.
- **VS lifecycle** — check the [VS Servicing Information wiki](https://dev.azure.com/devdiv/DevDiv/_wiki/wikis/DevDiv.wiki/27212/Visual-Studio-Servicing-Information). Rule of thumb: the VS support window covers the current release plus two preceding versions, so the first candidate for VS-retirement is `vs18.11 - 3` — **always confirm on the wiki**, since servicing exceptions can extend specific versions beyond the rule of thumb.
- **VS-only branches** (not paired with any active SDK band) are retired purely on the VS lifecycle.
**Result — retired branches for this release: `vs18.8` and `vs18.6`, plus orphaned `vs18.4` / `vs18.5` default channels.**
> 🔴 **Corrected 2026-09-01 — the original audit was incomplete.** It evaluated only `vs18.8` (the `18.11 - 3` rule-of-thumb candidate) and concluded "`vs18.8` (only)". A full audit shows **`vs18.6` was also retired**, and that two default channels are orphans. Cleanup PR: [maestro-configuration!64686](https://dev.azure.com/dnceng/internal/_git/maestro-configuration/pullrequest/64686).
| Branch | SDK band | Band EOL | VS lifecycle | Outbound subs | Verdict |
|---|---|---|---|---|---|
| `vs18.0` | `.NET 10.0.1xx SDK` | **Nov 2028** | out of window | → `dotnet/dotnet release/10.0.1xx` | 🟢 **keep** — SDK still supported |
| `vs18.4` | `.NET 10.0.2xx SDK` | **May 2026** | out of window | none | 🔴 **retire** — branch already deleted from repo; default channel `6705` orphaned |
| `vs18.5` | none (VS-only) | — | out of window | none | 🔴 **retire** — branch already deleted from repo; default channel `6741` orphaned |
| `vs18.6` | `.NET 10.0.3xx SDK` | **Aug 2026** | out of window | **none** | 🔴 **retire** — ❗ missed by the original audit |
| `vs18.8` | none (VS-only) | — | not on any VS branch | **none** | 🔴 retire ✅ done in Phase 2 |
| `vs18.9` | `.NET 10.0.4xx SDK` | Nov 2028 | live as `rel/oobstable` 18.9.3 | → `release/10.0.4xx`, fsharp | 🟢 keep |
| `vs18.10` | none | — | live as `rel/stable` | fsharp `release/dev18.10` | 🟢 keep |
Band ↔ VS ↔ EOL mapping from the [supported .NET versions table](https://learn.microsoft.com/dotnet/core/porting/versioning-sdk-msbuild-vs#supported-net-versions).
**Root cause of the miss.** Step 1.3 as written names a single candidate (`vs{THIS}-3`) and no later step revisits older branches, so a retirement missed in one cycle is missed permanently — `vs18.6` was the `vs18.9` release's candidate. Two compounding errors on my side:
1. **I did not open the SDK lifecycle table**, even though 1.3 explicitly links it. It states `10.0.3xx ↔ VS 18.6, EOL Aug '26` outright and would have settled this immediately.
2. **I used Maestro channel existence as a lifecycle proxy** — reasoning that `.NET 10.0.3xx SDK` and `.NET 10.0.3xx SDK Release` channels still exist, so the band must be supported. That inference is invalid; channels outlive their bands indefinitely.
Both are fixed in #14911, which converts 1.3 into a full audit.
Evidence for retiring `vs18.8`:
- Matches the rule of thumb (`18.11 - 3`); the 18.10 release retired `vs18.7` by the same rule.
- The [VS Servicing Information wiki](https://dev.azure.com/devdiv/DevDiv/_wiki/wikis/DevDiv.wiki/27212/Visual-Studio-Servicing-Information) is **no longer maintained** — it now redirects to https://aka.ms/vsdates. The VS-Dates branch/milestone map lists only `main`=18.11, `rel/stable`=18.10, `rel/oobstable`=18.9.3; 18.8 is on no VS branch.
- `darc get-subscriptions --exact --source-repo .../msbuild --channel "VS 18.8"` → **no subscriptions**, so nothing downstream consumes it.
- No VMR backflow and no forward sub to `dotnet/dotnet`, so no SDK band extends its lifecycle.
- Cleanup owed in Phase 2.3e: inbound Arcade subscription `afd0e725-2fd0-43a6-bdb3-4817b5991d85` (`.NET 10 Eng` → `vs18.8`).
---
## Phase 2: DARC Subscription Updates
> **Trigger**: `vs18.11` branch exists (Phase 1 complete). \
> **Why this runs before bumping `main`:** consumers of MSBuild via `main` (notably the VMR) should start receiving next-version bits from the `VS 18.12` channel **the moment `main` is bumped**. Reassigning `main`'s default channel **before** the Phase 3 branding bump means the first `main` build at the new version is already published to the correct channel; otherwise it lands on the now-stale `VS 18.11` channel.
First, **gather information** (read-only queries — no PR needed):
- [x] **2.1** Identify the **forward-flow** subscriptions to retarget: \
`darc get-subscriptions --exact --source-repo https://github.com/dotnet/msbuild --channel "VS 18.11"` \
This lists every `msbuild → downstream` subscription currently on the outgoing channel. **Retarget ONLY the subscriptions whose _target branch_ is `main`** — normally `dotnet/dotnet @ main` (the VMR/SDK main) and `dotnet/fsharp @ main` (fsharp tracks the channel msbuild `main` publishes to). Record their IDs. \
🛑 **Do NOT touch subscriptions that target a VMR servicing/release branch** (`dotnet/dotnet @ release/*`). That includes the SDK band now paired with `vs18.11` (it is now fed by `vs18.11` via the `VS 18.11` channel) **and** any `.NET-next` preview band (`release/*-preview*`). Leaving them on `VS 18.11` is what lets the new release branch own its downstream flow; moving them would steal it. The single rule: **retarget a forward sub only if its target branch is `main`.**
**Result — 4 forward subs on `VS 18.11`; retarget 2, leave 2:**
| Sub ID | Target | Action |
|---|---|---|
| `d1c6afb2-7bf1-43e4-8f2e-af7e0680b540` | `dotnet/dotnet` @ **`main`** | 🔄 **retarget → `VS 18.12`** |
| `c88fef6f-3728-44a8-80e6-587fb00258a1` | `dotnet/fsharp` @ **`main`** | 🔄 **retarget → `VS 18.12`** |
| `71ef5073-ce94-46bb-bbf6-f21d54bc73fc` | `dotnet/dotnet` @ `release/11.0.1xx` | 🛑 **leave** — SDK band `vs18.11` now owns |
| `89ebe3be-a7d7-4aaf-8f71-7258c0ddb02c` | `dotnet/dotnet` @ `release/11.0.1xx-rc1` | 🛑 **leave** — preview/RC band |
> 🔴 **Corrected 2026-09-01 — the "`vs18.11` owns 11.0.1xx" premise was wrong.** \
> `vs18.11` is **VS-only**: the band mapped to it was `release/11.0.1xx-rc1`, which is now finalized (sub `89ebe3be` was deleted by the .NET team in [!64592](https://dev.azure.com/dnceng/internal/_git/maestro-configuration/pullrequest/64592) along with the rc1 band config). \
> `71ef5073` currently sits on **`VS 18.12`**, not `VS 18.11`. **This is intentional, not a regression** — close to a .NET major GA, once the next release branch exists, `main` **dual-inserts** into both `.NET 11.0.1xx SDK` and `.NET 12.0.1xx SDK`. \
> Consequently **`VS 18.11` has zero forward subscriptions, and that is the correct end state** for a VS-only release. Do not "fix" it in a future audit.
- [x] **2.2** Verify release branch channel association: \
`darc get-default-channels --source-repo https://github.com/dotnet/msbuild --branch vs18.11` \
Note whether the association exists (needed for step 2.3d).
> ✅ **Exists** — `(7075) dotnet/msbuild @ vs18.11 -> VS 18.11`. Therefore **2.3d is a no-op.**
- [x] **2.2b** **(VMR backflow — do this only if `vs18.11` is paired with an SDK band that `main` was feeding; skip entirely for a VS-only release with no SDK band.)** Identify the backflow subscriptions (VMR → msbuild, source-enabled) and the band channels: \
`darc get-subscriptions --target-repo https://github.com/dotnet/msbuild --target-branch main --source-repo https://github.com/dotnet/dotnet` → record the source-enabled `→ main` backflow **ID** (for 2.3f). \
`darc get-default-channels --source-repo https://github.com/dotnet/dotnet --branch main` → the **next** SDK band channel `main` now publishes to, e.g. `.NET SDK`. Compare to the current `→ main` backflow channel — if unchanged, 2.3f is a no-op (for 2.3f). \
`darc get-default-channels --source-repo https://github.com/dotnet/dotnet --branch release/` → the **outgoing** band channel that `vs18.11` now owns, e.g. `.NET SDK` (for 2.3g).
> ✅ **Applies** — `vs18.11` **is** SDK-coupled (it now owns the forward sub to `dotnet/dotnet @ release/11.0.1xx`).
>
> - `→ main` backflow ID: **`91fa59f1-1864-46b1-b482-87955691317c`**, currently on channel **`.NET 11.0.1xx SDK`**.
> - `dotnet/dotnet @ main` now publishes to **`.NET 12.0.1xx SDK`** (7095) — **changed**, so **2.3f is NOT a no-op**.
> - Outgoing band: `dotnet/dotnet @ release/11.0.1xx` → **`.NET 11.0.1xx SDK`** (7094) — the channel to wire into `vs18.11` in 2.3g.
> - Precedent confirms the pattern: `vs18.0 ← .NET 10.0.1xx SDK` (`0ca9ffca`), `vs18.9 ← .NET 10.0.4xx SDK` (`7b782451`).
> 🔴 **Corrected 2026-09-01 — this verdict was wrong.** `vs18.11` is **VS-only** (its band, `release/11.0.1xx-rc1`, is finalized), so **2.2b/2.3f/2.3g did not apply** and 2.3g should have been skipped. The `vs18.0`/`vs18.9` precedent cited above holds only for branches that actually own a band. See the correction under 2.1.
Then, **batch all write operations into one PR** on the [maestro-configuration](https://dev.azure.com/dnceng/internal/_git/maestro-configuration) repo. \
Use `--configuration-branch msbuild-18.11-main-bump` (distinct from the Phase 1 channel branch) and `--no-pr` on all but the last command. \
_Tip: `darc add-default-channel` / `add-subscription` prompt interactively when the target branch does not exist yet; pass `-q` (non-interactive) to skip that prompt._
- [x] **2.3** DARC channel/subscription updates — all executed on config branch `msbuild-18.11-main-bump`:
- [x] **2.3a** Remove main → old channel mapping: \
`darc delete-default-channel --repo https://github.com/dotnet/msbuild --branch main --channel "VS 18.11" --configuration-branch msbuild-18.11-main-bump --no-pr`
- [x] **2.3b** Associate main with next channel: \
`darc add-default-channel --channel "VS 18.12" --branch main --repo https://github.com/dotnet/msbuild --configuration-branch msbuild-18.11-main-bump --no-pr`
- [x] **2.3c** Retarget **each** `main`-targeting forward subscription from 2.1 to the next channel — run once per ID (typically `dotnet/dotnet @ main` and `dotnet/fsharp @ main`): \
`darc update-subscription --id --channel "VS 18.12" --configuration-branch msbuild-18.11-main-bump --no-pr`
> ✅ Run twice: `d1c6afb2-7bf1-43e4-8f2e-af7e0680b540` (dotnet/dotnet @ main) and `c88fef6f-3728-44a8-80e6-587fb00258a1` (dotnet/fsharp @ main). The two `release/11.0.1xx*` subs were deliberately left on `VS 18.11`.
- [x] **2.3d** If release branch association was missing in 2.2, add it: \
`darc add-default-channel --channel "VS 18.11" --branch vs18.11 --repo https://github.com/dotnet/msbuild --configuration-branch msbuild-18.11-main-bump --no-pr`
> ⏭️ **Skipped** — association `(7075)` already existed (see 2.2).
- [x] **2.3e** **Delete subscriptions for retired branches.** For each branch identified as retired in step 1.3 (apply the same combined SDK+VS rule — do **not** delete subscriptions for a branch that's retired on only one side, since fixes must keep flowing into the still-supported lifecycle), remove its inbound subscriptions and any default channel associations.
List them: `darc get-subscriptions --target-repo https://github.com/dotnet/msbuild --target-branch ` \
Delete each: `darc delete-subscription --id --configuration-branch msbuild-18.11-main-bump --no-pr`
> ✅ `vs18.8`: deleted Arcade sub `afd0e725-2fd0-43a6-bdb3-4817b5991d85` and default channel `vs18.8 -> VS 18.8`.
>
> ⚠️ **Checklist bug — fix in Phase 5.6:** the verb above is wrong. darc `1.1.0-beta.26413.1` rejects `delete-subscription` with *"Verb 'delete-subscription' is not recognized."* The correct verb is **`delete-subscriptions`** (plural), and it needs **`-q`** to skip its confirmation prompt: \
> `darc delete-subscriptions --id -q --configuration-branch --no-pr`
- [x] **2.3f** **(VMR backflow — skip for a VS-only release, or if 2.2b found the channel unchanged.)** Repoint the `→ main` backflow (ID from 2.2b) to the **next** SDK band channel so the bumped `main` pulls next-version VMR dependencies: \
`darc update-subscription --id --channel ".NET SDK" --configuration-branch msbuild-18.11-main-bump --no-pr`
> ✅ `91fa59f1-1864-46b1-b482-87955691317c`: `.NET 11.0.1xx SDK` → **`.NET 12.0.1xx SDK`**.
- [x] **2.3g** **(VMR backflow — skip for a VS-only release.)** Add a backflow from the **outgoing** SDK band into the new release branch so that band keeps flowing into `vs18.11` (mirrors the previous release branch's backflow: source-enabled, source dir `msbuild`, everyDay, Standard merge, excluded assets `*`; the branch is brand-new so pass `-q`): \
`darc add-subscription --channel ".NET SDK" --source-repo https://github.com/dotnet/dotnet --target-repo https://github.com/dotnet/msbuild --target-branch vs18.11 --update-frequency everyDay --source-enabled --source-directory msbuild --excluded-assets '*' --standard-automerge --configuration-branch msbuild-18.11-main-bump --no-pr -q`
> ✅ Added `.NET 11.0.1xx SDK` → `msbuild @ vs18.11`, new subscription id **`8473cbd7-92c3-418d-aa27-617bf979a034`**.
>
> 🔴 **This never took effect.** darc reported the subscription created, but it was silently dropped from !64468 and never reached the YAML. Re-verified 2026-09-01: `dotnet/dotnet → msbuild` had backflows for `main`, `vs18.0` and `vs18.9` only. Re-added by hand as id `6a98fe31-74bc-4d9f-adc8-068119f9de62` in [!64686](https://dev.azure.com/dnceng/internal/_git/maestro-configuration/pullrequest/64686).
>
> 🔴 **…and then removed again — 2.3g should never have run.** `vs18.11` is **VS-only** (band `release/11.0.1xx-rc1` finalized), so there is no band to back-flow from; the step's own "skip for a VS-only release" guard applied. The darc drop was therefore a *lucky* outcome, and re-adding it in !64686 was the actual mistake. Removed in [!64688](https://dev.azure.com/dnceng/internal/_git/maestro-configuration/pullrequest/64688); it never ran (no Last Build), so no flow was affected.
- [x] **2.3h** **Arcade fix-up (run 2.4 first if you haven't).** _If the Arcade subscription from 2.4 below is missing or pointed at the wrong channel, include the fix-up here with `--no-pr` before creating the PR._
> ✅ Added the missing Arcade sub: `.NET 11 Eng` → `msbuild @ vs18.11`, everyWeek, `--failure-notification-tags "@dotnet/kitten"`.
- [x] **2.3i** **Create the PR** — re-run the final write command without `--no-pr` to open the PR on the configuration branch.
> 💡 **Process note for Phase 5.6:** "re-run the final write command without `--no-pr`" would duplicate the change. What actually works is to **omit `--no-pr` on the last command of the batch in the first place** — that both applies the change and opens the PR.
- [x] **2.3j** Get the maestro-configuration PR reviewed and merged: https://dev.azure.com/dnceng/internal/_git/maestro-configuration/pullrequest/64468
> 🔴 **MERGED BUT NOT APPLIED — ingestion failed. Follow-up PR required.**
>
> !64468 completed into `production` at **09:55Z** as merge commit `17daa00092`. The [Ingestion pipeline (dnceng/internal def 1567)](https://dev.azure.com/dnceng/internal/_build?definitionId=1567) run **20260826.6** ([build 3057904](https://dev.azure.com/dnceng/internal/_build/results?buildId=3057904)) **failed**:
>
> ```
> Entity validation failed
> IngestedSubscription collection contains duplicate Ids:
> Subscription (Id: 3714b8dc-f48d-4ad6-9c7f-e8ba9e404e5d,
> Channel: '.NET 11 Eng', Source: dotnet/arcade,
> Target: dotnet/msbuild, Branch: 'vs18.10')
> ```
>
> Ingestion is **atomic**, so *none* of !64468 is live. Verified against DARC: `main` still → `VS 18.11`, backflow `91fa59f1` still on `.NET 11.0.1xx SDK`, `vs18.8` default channel + Arcade sub still present, `vs18.11` has **zero** subscriptions.
>
> **Two defects in !64468** (diff of `17daa00092` vs parent `710ae6ab80`):
>
> | Change | Status |
> |---|---|
> | `91fa59f1` rotate main backflow → `.NET 12.0.1xx SDK` | ✅ in config |
> | delete `afd0e725` (vs18.8 Arcade sub) | ✅ in config |
> | main default channel → `VS 18.12` | ✅ in config |
> | delete `vs18.8` default channel | ✅ in config |
> | Arcade `.NET 11 Eng` → `vs18.11` | ❌ **darc wrote it with the `vs18.10` sub's Id `3714b8dc`** (duplicate → blocks ingestion) |
> | **2.3g backflow `.NET 11.0.1xx SDK` → `vs18.11`** | ❌ **absent from the config entirely** |
>
> The backflow was reported by darc as created (`8473cbd7-92c3-418d-aa27-617bf979a034`) but never reached the YAML — a `--no-pr` batch write was silently lost.
>
> **Fix (owner: @ViktorHofer):** one PR to `maestro-configuration` `production` — (a) give the `vs18.11` Arcade sub a fresh unique `Id`, (b) add the missing `.NET 11.0.1xx SDK` → `vs18.11` backflow mirroring the existing `vs18.9 ← .NET 10.0.4xx SDK` entry. Merging re-triggers pipeline 1567 and applies everything.
>
> 🐛 **Two darc bugs for Phase 5.6:** `add-subscription --configuration-branch` (1) can emit a **duplicate `Id`** by cloning a similar existing subscription instead of minting a new GUID, and (2) can **silently drop a `--no-pr` write** from a batch. Both mean *the darc command reporting success is not evidence the change is in the config* — the batch PR diff must be reviewed line-by-line before merging, and ingestion must be confirmed green afterwards.
> ⚠️ **Ordering hazard now live:** `main` is branded 18.12 (#14841 merged 13:23Z) while its default channel is still `VS 18.11`, which `dotnet/dotnet @ release/11.0.1xx` and `release/11.0.1xx-rc1` consume. Any official `main` build that publishes before the fix lands sends **18.12 bits into the .NET 11 SDK release branches**. Last BAR build at time of writing was `20260826.5` @ 12:37Z, i.e. pre-bump — no bad build had published yet.
Verifications (**parallel** — read-only, no ordering dependency):
- [x] **2.4** Verify the Arcade subscription for `vs18.11`: \
`darc get-subscriptions --exact --target-repo https://github.com/dotnet/msbuild --source-repo https://github.com/dotnet/arcade`
- **Every supported branch must have an Arcade subscription** from the matching `.NET Eng` channel (the channel is determined by the .NET band the branch is paired with — e.g. a branch paired with .NET 10 subscribes to `.NET 10 Eng`).
> ❌ **Missing for `vs18.11`** → fix-up required in **2.3h**. `vs18.11` is paired with the **.NET 11** band (`release/11.0.1xx`), and channel **`.NET 11 Eng` (10850)** exists, so that is the correct source channel.
>
> Current Arcade subs into msbuild: `main` ← `.NET Eng - Latest`; `vs18.10` ← `.NET Eng - Latest`; `vs18.9`/`vs18.8`/`vs18.6`/`vs18.0` ← `.NET 10 Eng`; `vs17.14`/`vs17.12` ← `.NET 9 Eng`; `vs17.11`/`vs17.8` ← `.NET 8 Eng`; `vs16.11` ← `.NET 6 Eng`.
>
> 📋 **Pre-existing gaps, out of scope for this release** (noted for Phase 5.5): `vs18.4` and `vs18.5` have default-channel associations but **no** Arcade subscription.
> _Roslyn subscription verification intentionally omitted from the per-release checklist: there is always exactly one Roslyn subscription, targeting `main` only and its channel does not rotate with SDK bands._
>
> **NuGet subscription:** when the next-to-ship SDK band rotates (e.g. `4xx` → `5xx`), the NuGet → `msbuild/main` subscription must be re-pointed to the new band's channel.
---
## Phase 3: Bump Main & Update Pipelines
> **Trigger**: Phase 2 DARC updates merged (`main`'s default channel is now `VS 18.12`).
> ⚠️ **Deviation (accepted, schedule pressure):** the PR was authored and opened **before** !64468 merged, because the insiders snap is 2026-08-28. The PR description carries an explicit **do-not-merge-before-!64468** note, so the ordering guarantee is preserved at merge time rather than at authoring time.
Create **one PR in `main`** containing all of the following changes:
- [x] **3.1** `eng/Versions.props`: Update `VersionPrefix` to `18.12.0`
- [x] **3.2** `eng/Versions.props`: Update `PackageValidationBaselineVersion` to `18.11.0-1.26426.2`. \
Resolve it deterministically with `pwsh ./scripts/Get-PackageValidationBaseline.ps1 -ThisReleaseVersion 18.11` (requires `az login` with devdiv access). See [How to determine `PACKAGE_VALIDATION_BASELINE_VERSION`](https://github.com/dotnet/msbuild/blob/main/.github/skills/release/SKILL.md#how-to-determine-package_validation_baseline_version) in the release skill for the manual fallback.
> 🐛 **The script was broken and is fixed in #14841.** It hardcoded the legacy `-preview--` shape; MSBuild produces `-..`. Every candidate came back `[NOT on feed]` and the script threw *"No candidate version is present on the dotnet-tools feed"*. The public dotnet-tools feed has **zero** `18.11.0-preview-*` entries — the real ones are `18.11.0-1.*`. Fixed to read `PreReleaseVersionLabel` from the release branch; it now prints `18.11.0-1.26426.2`.
>
> Value corresponds to official build `20260826.2` at branch point `9353559c2c`, confirmed on the feed.
- [x] **3.3** `.vsts-dotnet.yml`: Refresh the hardcoded OptProf baseline so the **next** `vs*` branch cut from `main` inherits valid OptProf data (this is what lets that branch's first official build succeed without the manual Phase 4.4 rerun). \
Resolve the current value with `pwsh ./scripts/Get-LatestOptProfDrop.ps1` (requires `az login` with devdiv access), then set it as `OptProfBaselineDrop`: \
`//1'`.
> ✅ `OptimizationData/DotNet-msbuild-Trusted/main/20260724.1/14773990/1` → `OptimizationData/DotNet-msbuild-Trusted/main/20260812.2/14983723/1`
- [x] **3.4** If the build pipeline fails on API-compat (only then — this step is a fix-up, not a routine action), update `CompatibilitySuppressions.xml` files. Run: \
`dotnet pack MSBuild.Dev.slnf /p:ApiCompatGenerateSuppressionFile=true` \
See [API compat documentation](https://learn.microsoft.com/en-us/dotnet/fundamentals/apicompat/overview) for details.
> ✅ **Triggered.** The Linux legs of [build 1568277](https://dev.azure.com/dnceng-public/public/_build/results?buildId=1568277) failed with `Unnecessary suppressions found` plus 96 `[Baseline] CP0001` lines. Fixed in `ef956e9c79` on #14841.
>
> **All 16 suppressions in `src/Build/CompatibilitySuppressions.xml` became unnecessary** — 4 types × 4 asset paths (`lib`/`ref` × `net11.0`/`net472`):
> `Microsoft.Build.Experimental.MSBuildClient`, `MSBuildClientExitResult`, `MSBuildClientExitType`, `OutOfProcServerNode`.
>
> These covered the MSBuild server namespace promotion ([#12099](https://github.com/dotnet/msbuild/pull/12099)) — `Microsoft.Build.Experimental` → `Microsoft.Build.Server`. The file's own comment said they were removable "once `PackageValidationBaselineVersion` advances past the first release containing the move". Advancing the baseline to `18.11.0-1.26426.2` in step 3.2 is exactly that, so the file is now an empty ``.
>
> **No new suppressions were needed.** `src/Framework`, `src/Tasks` and `src/Utilities` suppression files are untouched (12 / 23 / 12 `PKV004` entries all still required).
>
> **Verification:**
> - Regenerated with `build.cmd -pack /p:ApiCompatGenerateSuppressionFile=true`.
> - Clean pack, no generate flag → **0 errors, 0 warnings**.
> - **Control:** restored the old content, cleaned `artifacts/packages`, re-packed → **35 errors** incl. `Unnecessary suppressions found`. Confirms package validation genuinely runs on this branch and the pass is not a silent skip.
>
> 🐛 **Checklist bug:** the documented command `dotnet pack MSBuild.Dev.slnf /p:ApiCompatGenerateSuppressionFile=true` is not what works here — use `build.cmd -pack /p:ApiCompatGenerateSuppressionFile=true` (as the 18.10 bump [#14564](https://github.com/dotnet/msbuild/pull/14564) actually did). Also note a pack run fails with `Multiple packages of name 'Microsoft.Build' specified` if `artifacts/packages` still holds nupkgs from the pre-bump version — delete that folder before re-packing. Both worth documenting in 3.4. Added to the Phase 5.6 list.
- [x] **3.5** Merge main-bump PR: https://github.com/dotnet/msbuild/pull/14841 \
✅ Merged 2026-08-26 13:23Z as `02990867ec`. `main` is now `VersionPrefix` 18.12.0.
> ⚠️ **The ordering guarantee did not hold.** This merged while !64468 was merged-but-**not-ingested**, so `main`'s default channel is still `VS 18.11`. See the 2.3j note above — resolving that ingestion failure is now the critical path.
---
## Phase 4: Final Branding & VS Insertion
> **Trigger**: 7 calendar days before `2026-08-28`. \
> **Precondition**: Phases 1–3 complete. Preview builds from `vs18.11` have been inserting into VS `main` since Phase 2. \
> **Goal**: Final-brand the release branch and get the final-branded bits inserted into VS `main` before VS snaps to `rel/insiders`.
Steps are **sequential**.
- [x] **4.1** Promote public API on `vs18.11` branch: \
Move contents of `PublicAPI.Unshipped.txt` → `PublicAPI.Shipped.txt` for all projects with API changes. See [release.md](https://github.com/dotnet/msbuild/blob/main/documentation/release.md) for details.
> ⏭️ **No-op — this step is obsolete.** `git ls-tree -r origin/vs18.11` finds **zero** `PublicAPI.Shipped.txt` / `PublicAPI.Unshipped.txt` files, and there is no `Microsoft.CodeAnalysis.PublicApiAnalyzers` reference anywhere in `eng/` or the `Directory.Build.*` files. The repo no longer tracks public API this way. Flagged for Phase 5.6.
- [ ] **4.2** Bootstrap OptProf for `vs18.11`. **If the Phase 3.3 hardcoded `OptProfBaselineDrop` was kept current, the auto-triggered build should already pick it up (`.vsts-dotnet.yml` seeds `OptProfDrop` from it on `vs*` branches) and this step is a no-op.** Only if the official build still fails for lack of OptProf data (e.g. the baseline was stale/empty at branch-cut):
- [ ] **4.2a** **Cancel** the auto-triggered official build for `vs18.11`.
- [ ] **4.2b** **Re-run the official build manually** for `vs18.11` with the OptProf override from `main` — set `Optional OptProfDrop Override` to `main`'s latest OptProf drop path (`pwsh ./scripts/Get-LatestOptProfDrop.ps1`).
- [ ] **4.3** Get M2 or QB approval as necessary per the VS schedule. \
_**Only required if we are behind the VS schedule** — i.e. the insertion didn't land in VS `main` before `2026-08-28` (4.4 was missed) and a milestone-gate approval is now needed. If the insertion made the schedule, **skip this step**._
- [ ] **4.4** Babysit the VS insertion PR from `vs18.11` into VS `main` (auto-generated at https://devdiv.visualstudio.com/DevDiv/_git/VS/pullrequests). The inserted bits must be in VS `main` **before** `2026-08-28` so they are included when VS snaps to `rel/insiders`: _TBD_ \
The insertion PR contains the inserted package versions — useful for the nuget.org publishing step.
**After insiders snap** (only if a backport to insiders is needed):
> 🛑 **4.5 and 4.6 are NOT part of the regular release flow — skip them entirely on a normal release.** \
> They only apply when **servicing** a previously-shipped release (i.e. you actually have a hotfix commit on `vs18.11` that needs to be inserted into VS's already-snapped `rel/insiders` or `rel/stable` branch). If you have no such commit to service, leave `AutoInsertTargetBranch` untouched and move on to Phase 5.
>
> ⚠️ When you *do* need to service: re-confirm which VS branch you actually want to insert into before flipping `AutoInsertTargetBranch`. The default is `main`, so forgetting to retarget after the snap silently lands your fix in the next VS instead of the one you're servicing.
- [x] **4.5** Update [`azure-pipelines/vs-insertion.yml`](https://github.com/dotnet/msbuild/blob/main/azure-pipelines/vs-insertion.yml): retarget `AutoInsertTargetBranch` for `vs18.11` from VS `main` → `rel/insiders`. This enables direct insertion of hotfix commits into the insiders branch.
**After stable snap** (only if a backport to stable is needed):
- [ ] **4.6** Update [`azure-pipelines/vs-insertion.yml`](https://github.com/dotnet/msbuild/blob/main/azure-pipelines/vs-insertion.yml): retarget `AutoInsertTargetBranch` for `vs18.11` → `rel/stable`. This enables direct insertion of hotfix commits into the stable branch.
**Change waves documentation sync**:
- [ ] **4.7** Sync the public [Change Waves Learn page](https://learn.microsoft.com/visualstudio/msbuild/change-waves) with `documentation/wiki/ChangeWaves.md`. \
The page must list the waves live in **VS Insiders** — the same set that ships in the **latest released preview SDK**.
- [ ] **4.7a** Confirm the version in Insiders — normally `18.11` right after the snap: the `Microsoft.Build` version in [`msbuild-components.json` on VS `rel/insiders`](https://devdiv.visualstudio.com/DevDiv/_git/VS?path=/.corext/Configs/msbuild-components.json&version=GBrel/insiders), cross-checked with `dotnet msbuild -version` from the latest preview SDK (https://dotnet.microsoft.com/download/dotnet). If they disagree, pick latest.
- [ ] **4.7b** Port the wave lists and their section grouping from [`documentation/wiki/ChangeWaves.md` on `vs18.11`](https://github.com/dotnet/msbuild/blob/vs18.11/documentation/wiki/ChangeWaves.md). Bump `ms.date`.
- [ ] **4.7c** Open the PR against [MicrosoftDocs/visualstudio-docs-pr](https://github.com/MicrosoftDocs/visualstudio-docs-pr) (**not** the public `visualstudio-docs` mirror), file `docs/msbuild/change-waves.md`. Example: [visualstudio-docs-pr#15662](https://github.com/MicrosoftDocs/visualstudio-docs-pr/pull/15662).
---
## Phase 5: Post-GA
> **Trigger**: `2026-10-13` has passed and VS release has shipped.
Steps are **mostly parallel** unless noted.
- [ ] **5.1** Push packages to nuget.org.
> **How publishing works:** We don't push packages ourselves. We hand a link to the **Release** artifacts of the official build to the _.NET Release Team_, and they push to nuget.org. Search past mail for the subject _"Publish MSBuild 18.11 to NuGet.org"_ for the template.
- [ ] **5.1a** Determine the exact MSBuild version that actually shipped to customers. \
⚠️ **VS and the SDK might ship _different_ patch versions off the same `vs18.11` branch during servicing — so this must be looked up, never inferred from `eng/Versions.props` at branch HEAD or from the Phase 4.4 insertion PR.**
- **First, decide whether this release is coupled with an SDK release:** \
`darc get-subscriptions --target-repo https://github.com/dotnet/msbuild --target-branch vs18.11 --source-repo https://github.com/dotnet/dotnet` \
If that returns a source-enabled subscription from a `.NET SDK` channel, the release **is** SDK-coupled.
- **If SDK-coupled: the SDK is the source of truth** — look up the MSBuild version baked into the shipped SDK build of that band. It wins over VS `rel/stable`.
- **Otherwise**, read the **authoritative GA'd value from VS `rel/stable`**: the `Microsoft.Build` component version in [`.corext/Configs/msbuild-components.json`](https://devdiv.visualstudio.com/DevDiv/_git/VS?path=/.corext/Configs/msbuild-components.json&version=GBrel/stable) (e.g. `18.7.1-servicing-NNNNN-NN+`). Extract just the **numeric `VersionPrefix`** from that string — drop the `-servicing-NNNNN-NN+` suffix — and use it as `{{THIS_RELEASE_EXACT_VERSION}}` (e.g. `18.7.1`). **Do not** rely solely on the VS insertion PR — that PR targets VS `main` and can be superseded by a later servicing insertion before GA, whereas `rel/stable` reflects what actually shipped.
- _Worked example (18.9): the Phase 4.4 insertion PR said `18.9.0`, VS `rel/stable` said `18.9.1`, branch HEAD was already `18.9.8` — and the correct answer was `18.9.6`, from the coupled .NET 10.0.4xx SDK._
- [ ] **5.1b** In the [MSBuild official build pipeline](https://devdiv.visualstudio.com/DevDiv/_build?definitionId=9434), filter to the `vs18.11` branch and locate the build whose output version matches the one identified in 5.1a (e.g. `{{THIS_RELEASE_EXACT_VERSION}}`, such as `18.6.3`). Take the latest build that produced the matching versioned artifacts.
- [ ] **5.1c** From that build, open the **Publish Artifacts** step and grab the link to the **`PackageArtifacts/Release`** drop. Verify the **Release** folder contains all of:
- `Microsoft.Build.Utilities.Core.{{THIS_RELEASE_EXACT_VERSION}}.nupkg`
- `Microsoft.Build.{{THIS_RELEASE_EXACT_VERSION}}.nupkg`
- `Microsoft.Build.Framework.{{THIS_RELEASE_EXACT_VERSION}}.nupkg`
- `Microsoft.Build.Runtime.{{THIS_RELEASE_EXACT_VERSION}}.nupkg`
- `Microsoft.Build.Tasks.Core.{{THIS_RELEASE_EXACT_VERSION}}.nupkg`
- `Microsoft.NET.StringTools.{{THIS_RELEASE_EXACT_VERSION}}.nupkg`
- `Microsoft.Build.Templates.{{THIS_RELEASE_EXACT_VERSION}}.nupkg`
- [ ] **5.1d** Email the _.NET Release Team_ with the `Release` link from 5.1c and ask them to publish to nuget.org.
- [ ] **5.2** Publish docs
> **How publishing works:** The reference-publishing vendor team generates Microsoft Learn reference pages from the shipped MSBuild assemblies/xmldoc and then sends us a docs-repo PR with the regenerated content.
- [ ] **5.2a** Create a reference-publishing ticket for the new release based on [this existing ticket](https://dev.azure.com/msft-skilling/Content/_workitems/edit/565854) as a template. Then wait for the vendor team to ping you with a link to the generated PR.
- [ ] **5.2b** Review and approve the docs-repo PR the vendor team opens (example: [msbuild-api-docs#61](https://github.com/dotnet/msbuild-api-docs/pull/61)).
- [ ] **5.3** Create GitHub release:
- [ ] **5.3a** **Precondition — confirm the previous release tag exists on `upstream`.** \
`git fetch upstream --tags && git tag --list 'v{{PREVIOUS_RELEASE_EXACT_VERSION}}'` \
_(Assumes `upstream` is configured as the `dotnet/msbuild` remote. If not: `git remote add upstream https://github.com/dotnet/msbuild.git`.)_ \
If the tag is missing (e.g. the previous release was never tagged), create and push it **first**.
- [ ] **5.3b** **Identify the commit to tag.** It is the source commit of the build identified in **5.1b** (the build that produced `{{THIS_RELEASE_EXACT_VERSION}}`). Find the SHA in that build run's "Source version" field on the pipeline page.
- [ ] **5.3c** Tag this release and push:
```
git checkout
git tag v{{THIS_RELEASE_EXACT_VERSION}}
git push upstream v{{THIS_RELEASE_EXACT_VERSION}}
```
- [ ] **5.3d** Create release at https://github.com/dotnet/msbuild/releases/new — use `Generate Release Notes` to prepopulate, with `v{{PREVIOUS_RELEASE_EXACT_VERSION}}` as the previous tag.
- [ ] **5.4** Update `BootstrapSdkVersion` in [`eng/Versions.props`](https://github.com/dotnet/msbuild/blob/main/eng/Versions.props) if a fresh SDK was released. Check https://dotnet.microsoft.com/download/visual-studio-sdks — always verify the details for the targeted .NET version.
- [ ] **5.4b** Update `tools.dotnet` in [`global.json`](https://github.com/dotnet/msbuild/blob/main/global.json) to the latest released SDK in the targeted band.
- [ ] **5.5** Verify the overall subscription map across **every still-supported branch** — each `vsXX.Y` branch has an Arcade subscription matching its targeted .NET band, and each supported branch's outbound subscriptions land in the right downstream (e.g. SDK band, VMR). \
You can find more info [here](https://dev.azure.com/devdiv/DevDiv/_wiki/wikis/DevDiv.wiki/52573/MSBuild-Maestro-Flow).
- [ ] **5.6** Review this tracking issue for any process deviations. If the process changed, create a PR to update `documentation/release-checklist.md` with the improvements.
**Deviations / fixes already captured in #14841:**
- 🐛 `scripts/Get-PackageValidationBaseline.ps1` assumed the legacy `-preview--` version shape and could not resolve any baseline. Fixed to read `PreReleaseVersionLabel`.
- 🐛 Step 2.3e used `darc delete-subscription` (not a valid verb) — corrected to `delete-subscriptions -q`.
- 🐛 Step 2.3i's "re-run the final write command without `--no-pr`" would duplicate the change — corrected.
**Still open for a follow-up PR:**
- ✅ *Done in #14911* — step 1.3 rewritten as a full retirement audit (was a single `vs{THIS}-3` candidate check, which let `vs18.6` survive).
- 📌 **darc `--configuration-branch` writes are not trustworthy without verification** (hit twice in this release, see 2.3j). The checklist should require, after every batched DARC PR: (1) review the PR diff line-by-line against the intended change list, and (2) confirm the [Ingestion pipeline (def 1567)](https://dev.azure.com/dnceng/internal/_build?definitionId=1567) run for the merge commit went **green** — a merged config PR that fails ingestion applies *nothing*, atomically, while `darc get-*` keeps showing the old state with no error.
- 📌 Phase 3.5 should state the ordering dependency as "!64468 **ingested**", not "!64468 merged". Merge alone is not sufficient.
- 📌 Step **3.4**'s command is wrong: `dotnet pack MSBuild.Dev.slnf /p:ApiCompatGenerateSuppressionFile=true` does not do the job — use `build.cmd -pack /p:ApiCompatGenerateSuppressionFile=true`. Should also warn that `artifacts/packages` must be deleted first, or pack fails with `Multiple packages of name 'Microsoft.Build' specified` when stale pre-bump nupkgs are present.
- 📌 Step **4.1** (promote `PublicAPI.Unshipped.txt` → `PublicAPI.Shipped.txt`) is **dead**. The repo contains no `PublicAPI.*.txt` files and no `Microsoft.CodeAnalysis.PublicApiAnalyzers` reference. Either remove the step or replace it with whatever mechanism superseded it. `documentation/release.md` likely needs the same treatment.
- 📌 Steps **4.5 / 4.6** tell you to retarget `AutoInsertTargetBranch` in `azure-pipelines/vs-insertion.yml`, but that variable **no longer exists**. The pipeline now uses an `InsertTargetBranch` variable derived from a `TargetBranch` parameter that defaults to `auto` → `main`. The servicing instructions need rewriting against the current pipeline shape.
- 📌 The skill's Phase 1 summary lists updating `VisualStudio.ChannelName` each release; it is currently the release-agnostic value `int.main` in `azure-pipelines/.vsts-dotnet-build-jobs.yml`, so that instruction looks stale.
- 📌 Phase 1.2a/1.2b were already satisfied by the *previous* release's Phase 1.2c pre-creation, so Phase 1 collapsed to a single write. Worth stating explicitly so the next person doesn't create a redundant batch.
- 📌 Consider adding a Phase 1.3 note that the [VS Servicing Information wiki](https://dev.azure.com/devdiv/DevDiv/_wiki/wikis/DevDiv.wiki/27212/Visual-Studio-Servicing-Information) is retired and now redirects to https://aka.ms/vsdates; the branch/milestone map there is the usable signal.
- 📌 Arcade subscription gaps unrelated to this release: `vs18.4` and `vs18.5` have default-channel associations but no Arcade subscription (see 5.5).
---
## If 18.12 is a new major version
- [ ] Update VS major version references per [release.md](https://github.com/dotnet/msbuild/blob/main/documentation/release.md):
- [`src/Shared/BuildEnvironmentHelper.cs`](https://github.com/dotnet/msbuild/blob/main/src/Shared/BuildEnvironmentHelper.cs)
- [`src/Shared/Constants.cs`](https://github.com/dotnet/msbuild/blob/main/src/Shared/Constants.cs)
- [`src/Framework/Telemetry/TelemetryConstants.cs`](https://github.com/dotnet/msbuild/blob/main/src/Framework/Telemetry/TelemetryConstants.cs)
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with the checklist’s Phase 0 inputs, eng/Versions.props, and .github/skills/release/SKILL.md, then review the recorded DARC commands and linked maestro-configuration PRs. Follow the remaining phases in order, using the stated branch, channel, schedule, and release-output checks; done means all applicable checklist items are completed and artifact URLs and the exact shipped version are recorded.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- git, github
- Domain
- devops, documentation, release
- Issue type
- Documentation
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 20/100