Follow the SDK's ILLink version into the three lock files that pin it
ci / build and test (pull_request) Successful in 2m13s
ci / desktop nightly (pull_request) Skipped
ci / android head (pull_request) Successful in 3m22s
ci / api image (pull_request) Successful in 6s

CI's restore stopped on a commit that changed no dependency and touched none of
these files:

    error NU1004: The package reference Microsoft.NET.ILLink.Tasks version has
    changed from [10.0.10, ) to [10.0.11, ).

◆ NOTHING HERE MOVED. THE RUNNER'S SDK DID. Microsoft.NET.ILLink.Tasks is
referenced implicitly by the SDK — no .csproj asks for it — and its version
tracks the runtime patch band. global.json pins 10.0.100 with
rollForward: latestMinor, so setup-dotnet installs whatever the newest 10.x SDK
is on the day. When that band moved to 10.0.11, every lock file carrying the
entry went stale at once, and RestoreLockedMode is what turns that into a stop
rather than a silent upgrade. Three files carry it: the Android head, Contracts
and Crypto.

Contracts and Crypto are regenerated by --force-evaluate under SDK 10.0.303,
which bundles the same 10.0.11 the runner has; the contentHash is NuGet's, from
that restore. dotnet restore DodoSSH.slnx --locked-mode is clean under it.

◆ THE ANDROID LOCK FILE IS HAND-EDITED AND WAS NOT VERIFIED BY A RESTORE. Same
three lines, same version, same hash the real restore produced — but generated
by an editor, not by NuGet. Installing 10.0.303 rewrote the machine-wide
workload manifests for the 10.0.300 band, after which that project fails
NETSDK1147 asking for wasm-tools (which nothing here targets) under 10.0.302 as
well as 10.0.303, so there was no working local restore left to produce it
honestly. The android workload on that machine is Visual Studio-managed and
repairing it is not a thing to do in passing. This is the hazard the docs
already record — the Android head is outside DodoSSH.slnx, so the locked-mode
gate that keeps the other fourteen lock files honest has never seen it — landing
again, from the other direction. If the android job still fails on NU1004, this
line is the first thing to doubt.

platform-flags.md gains the failure beside the existing lock-file hazards,
including the trap that cost the most time here: --force-evaluate from an SDK
older than the runner's rewrites the lock at the OLD version, changes nothing,
and looks like it worked. Check dotnet --version against the version in the
error before believing a regeneration.

This recurs on every SDK patch that moves the band. That is the accepted cost of
letting the SDK float; pinning an exact SDK trades a recurring lock-file bump
for a recurring toolchain bump and one mandated SDK per contributor.
This commit is contained in:
2026-08-12 11:50:42 +02:00
parent cec73010d3
commit 881562e81b
4 changed files with 33 additions and 9 deletions
+24
View File
@@ -712,6 +712,30 @@ The lasting hazard is the first paragraph and not the fix. Any change to a share
to a lock file this repository cannot verify from a machine without the Android workload, and it will go
on being noticed later than every other one.
**A lock file can go stale with nothing in this repository changing, because `Microsoft.NET.ILLink.Tasks`
is versioned by the SDK and `global.json` lets the SDK float.** The reference is implicit — nothing in any
`.csproj` asks for it — and its version tracks the runtime patch band, while `global.json` pins only
`10.0.100` with `rollForward: latestMinor`. So `setup-dotnet` installs whatever the newest 10.x SDK is on
the day, and the moment that SDK's band moves, locked-mode restore stops:
```
error NU1004: The package reference Microsoft.NET.ILLink.Tasks version has changed
from [10.0.10, ) to [10.0.11, ).
```
It named `DodoSSH.Client.Android`, `DodoSSH.Contracts` and `DodoSSH.Crypto` — the three lock files that
carry the entry — on a commit that touched none of them and no dependency at all.
The fix is `--force-evaluate` on those three, **from a machine whose SDK is at least as new as the
runner's**, which is the part that is easy to get wrong: a `--force-evaluate` from an older SDK rewrites
the lock at the older version, changes nothing, and looks like it worked. Check `dotnet --version` against
the version in the error before believing a regeneration.
This will recur on every SDK patch that moves the band. It is the accepted cost of letting the SDK float:
the alternative is pinning an exact SDK in `global.json`, which trades a recurring lock-file bump for a
recurring toolchain bump and makes every contributor install one specific SDK. Neither is free, and this
repository has chosen the floating side deliberately.
**.NET for Android cannot be built on a musl host, and this project's runner is Alpine. Every message the
toolchain produces on the way to saying so names a missing file that is present.** Three CI rounds went
into this and the first two fixed symptoms, so the messages are worth reading in the order they arrive.
@@ -74,9 +74,9 @@
},
"Microsoft.NET.ILLink.Tasks": {
"type": "Direct",
"requested": "[10.0.10, )",
"resolved": "10.0.10",
"contentHash": "f5VCIE7AJpd5YvzNTeMGVzQIgyE9tX+AreTYwQF+REbu+DZo/2Ae+jNSwhPEYrVz6RRkd7y8ubXjk6Nn6Ka+Cg=="
"requested": "[10.0.11, )",
"resolved": "10.0.11",
"contentHash": "IBf7lbovvjGWVWXZX5cJ/cO0WXbId0Zq4BuSeT94mGZuOAP66oMeH9PTBZ9Jpp3Jb6jtK0qm/NyUbPRo1gC/wQ=="
},
"MinVer": {
"type": "Direct",
+3 -3
View File
@@ -22,9 +22,9 @@
},
"Microsoft.NET.ILLink.Tasks": {
"type": "Direct",
"requested": "[10.0.10, )",
"resolved": "10.0.10",
"contentHash": "f5VCIE7AJpd5YvzNTeMGVzQIgyE9tX+AreTYwQF+REbu+DZo/2Ae+jNSwhPEYrVz6RRkd7y8ubXjk6Nn6Ka+Cg=="
"requested": "[10.0.11, )",
"resolved": "10.0.11",
"contentHash": "IBf7lbovvjGWVWXZX5cJ/cO0WXbId0Zq4BuSeT94mGZuOAP66oMeH9PTBZ9Jpp3Jb6jtK0qm/NyUbPRo1gC/wQ=="
},
"MinVer": {
"type": "Direct",
+3 -3
View File
@@ -16,9 +16,9 @@
},
"Microsoft.NET.ILLink.Tasks": {
"type": "Direct",
"requested": "[10.0.10, )",
"resolved": "10.0.10",
"contentHash": "f5VCIE7AJpd5YvzNTeMGVzQIgyE9tX+AreTYwQF+REbu+DZo/2Ae+jNSwhPEYrVz6RRkd7y8ubXjk6Nn6Ka+Cg=="
"requested": "[10.0.11, )",
"resolved": "10.0.11",
"contentHash": "IBf7lbovvjGWVWXZX5cJ/cO0WXbId0Zq4BuSeT94mGZuOAP66oMeH9PTBZ9Jpp3Jb6jtK0qm/NyUbPRo1gC/wQ=="
},
"MinVer": {
"type": "Direct",