dotnetup does not preserve global.json SDK roll-forward minimum `latestX` semantics
- Dominant language
- C#
- Stars
- 3.2k
- Forks
- 1.3k
- PR merge metrics
- PR metrics pending
Description
### Description
Dotnetup converts a `global.json` SDK requirement into a dotnetup channel string. The conversion loses information required to implement the SDK host's roll-forward semantics correctly.
Current mappings include:
| `sdk.rollForward` | Tracked dotnetup channel |
| --- | --- |
| `latestPatch` or omitted | SDK feature band, such as `11.0.1xx` |
| `latestFeature` | Major/minor, such as `11.0` |
| `latestMinor` | Major, such as `11` |
| `latestMajor` | `latest` |
| `disable`, `patch`, `feature`, `minor`, `major` | Fully specified version |
### Problems
#### `latestX` policies lose the requested-version lower bound
For example:
```json
{
"sdk": {
"version": "11.0.100-preview.6.26489.188",
"rollForward": "latestPatch",
"allowPrerelease": true
}
}
```
is represented as `11.0.1xx`. `UpdateChannel.Matches` checks only the major, minor, and SDK feature band. Consequently, an older preview 5 SDK is considered a match even though the original requirement has preview 6 as its minimum.
The same problem applies at broader levels:
- `latestFeature` loses the minimum feature band.
- `latestMinor` loses the minimum minor version.
- `latestMajor` loses the minimum major version.
This may be masked during normal online installation because resolving the latest published version often returns a newer version. It remains observable during offline garbage collection, with mixed installed SDKs, or when the requested SDK is newer than the public release metadata.
#### Non-`latest` policies become overly restrictive
`patch`, `feature`, `minor`, and `major` are converted to an exact version. This avoids rolling backward, but it also discards the fallback roll-forward behavior those policies permit when the requested SDK is unavailable.
#### Prerelease policy is lost
`sdk.allowPrerelease` is parsed but is not passed into channel derivation or resolution. This is also tracked in #53396.
### User impact
- Garbage collection may retain an older installed SDK that does not satisfy the original `global.json`.
- Installation may resolve a different SDK from the SDK host, particularly for future/private versions or mixed stable and prerelease environments.
- Removing another SDK may expose a supposedly retained GlobalJson requirement that `dotnet` cannot actually resolve.
### Proposed behavior
Do not represent a GlobalJson requirement solely as a dotnetup channel. Retain and evaluate at least:
- requested SDK version
- `rollForward`
- `allowPrerelease`
Resolution and garbage-collection matching should use semantics equivalent to the SDK host, including the requested version as the lower bound where applicable.
### Acceptance criteria
- No `latestX` policy selects an SDK older than the version specified by `global.json`.
- `patch`, `feature`, `minor`, and `major` perform their permitted fallback behavior when the exact SDK is unavailable.
- Stable/prerelease eligibility respects `allowPrerelease`.
- Online installation and offline GC reach decisions consistent with the SDK host for the same installed-version set.
Related: #53396, #54874, and #54916.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.