From 881562e81b841ca230fdf4279f4541ad3521a907 Mon Sep 17 00:00:00 2001 From: Jaap-Jan de Wit | DodoTech Date: Wed, 12 Aug 2026 11:50:42 +0200 Subject: [PATCH] Follow the SDK's ILLink version into the three lock files that pin it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- docs/platform-flags.md | 24 +++++++++++++++++++ src/DodoSSH.Client.Android/packages.lock.json | 6 ++--- src/DodoSSH.Contracts/packages.lock.json | 6 ++--- src/DodoSSH.Crypto/packages.lock.json | 6 ++--- 4 files changed, 33 insertions(+), 9 deletions(-) diff --git a/docs/platform-flags.md b/docs/platform-flags.md index b4a69d7..ebc87ab 100644 --- a/docs/platform-flags.md +++ b/docs/platform-flags.md @@ -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. diff --git a/src/DodoSSH.Client.Android/packages.lock.json b/src/DodoSSH.Client.Android/packages.lock.json index aeb0ac1..c9baa32 100644 --- a/src/DodoSSH.Client.Android/packages.lock.json +++ b/src/DodoSSH.Client.Android/packages.lock.json @@ -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", diff --git a/src/DodoSSH.Contracts/packages.lock.json b/src/DodoSSH.Contracts/packages.lock.json index 25e824a..6c374b1 100644 --- a/src/DodoSSH.Contracts/packages.lock.json +++ b/src/DodoSSH.Contracts/packages.lock.json @@ -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", diff --git a/src/DodoSSH.Crypto/packages.lock.json b/src/DodoSSH.Crypto/packages.lock.json index c92c2df..0d4bae0 100644 --- a/src/DodoSSH.Crypto/packages.lock.json +++ b/src/DodoSSH.Crypto/packages.lock.json @@ -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",