Bring the phone's lock file back to the graph it actually restores
ci / build and test (push) Successful in 1m54s
ci / android head (push) Failing after 14s
ci / api image (push) Successful in 27s

The android job's restore has never been reachable — the runner had no JDK and no SDK, so it failed
before it got there — and DodoSSH.Client.Android is deliberately outside DodoSSH.slnx, so the solution
restore that keeps the other fourteen lock files honest has never seen this one either. It went stale
for a whole release and nothing could say so.

Two things had drifted by the time the repaired job reached the step: MinVer, added to
Directory.Build.props for the desktop updater, and the ABI set, which grew when the -r android-arm64
pin came off the packaging step so that the nightly is installable on more than an arm64 handset.

--force-evaluate on this project alone, and the fourteen it references come back byte-identical: an
android-* RID is not a graph any of them has a package for. Checked rather than assumed, because this
is the same mechanism that once put win-x64 into the server's lock files and broke its image build.

docs/platform-flags.md records the lasting half, which is not this fix: any change to a shared props
file touches a lock file this repository cannot verify from a machine without the Android workload.
This commit is contained in:
2026-08-04 21:58:02 +02:00
parent b4a6c19ac1
commit 7e0a1b2af8
2 changed files with 62 additions and 0 deletions
+28
View File
@@ -546,6 +546,34 @@ whose checkout is discarded and does matter on a developer's machine, so the rel
`git checkout -- '*packages.lock.json'` afterwards. `-p:RestorePackagesWithLockFile=false` is not an `git checkout -- '*packages.lock.json'` afterwards. `-p:RestorePackagesWithLockFile=false` is not an
alternative: it fails NU1005 whenever a lock file already exists. alternative: it fails NU1005 whenever a lock file already exists.
**The Android head's lock file is outside the solution, so nothing checks it until the android job runs
— and the android job was broken for an unrelated reason for the whole of the release that went stale.**
`DodoSSH.Client.Android` is deliberately not in `DodoSSH.slnx` (it needs a workload the other two jobs
have no reason to install), so `dotnet restore DodoSSH.slnx --locked-mode` — the gate that keeps every
other lock file honest — has never seen it. Its only gate is the android job's own restore, and that job
could not reach the restore step at all while the runner had no JDK and no SDK.
The result: `MinVer` was added to `Directory.Build.props` for the desktop updater and reached fourteen
lock files. The fifteenth was not restorable on a runner, so it silently kept a graph from three releases
earlier, and the first thing the repaired job did was fail:
```
error NU1004: The project's runtime identifiers have changed from.
Project's runtime identifiers: android-arm64;android-x64, lock file's runtime identifiers android-arm64.
```
Two changes at once, which is why the message names both: the missing `MinVer`, and an ABI set that grew
when the `-r android-arm64` pin came off the packaging step. `--force-evaluate` on that project alone is
the fix, and — unlike the `win-x64` case above — it is safe to commit: the RIDs land in the Android
project's own lock file and the fourteen it references are rewritten byte-identically, because an
`android-*` RID is not a graph any of them has a package for. Check that with `git status` rather than
believing it; it is the same mechanism that broke the server's image build, and it happens to land
harmlessly here rather than by design.
The lasting hazard is the first paragraph and not the fix. Any change to a shared props file is a change
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 Docker `ARG` named `VERSION` silently sets MSBuild's `Version`.** An `ARG` is an environment variable **A Docker `ARG` named `VERSION` silently sets MSBuild's `Version`.** An `ARG` is an environment variable
for the rest of the stage, MSBuild reads environment variables as global properties, and MSBuild property for the rest of the stage, MSBuild reads environment variables as global properties, and MSBuild property
names are case-insensitive — so `ARG VERSION` in a build stage sets `Version` for every project built in names are case-insensitive — so `ARG VERSION` in a build stage sets `Version` for every project built in
@@ -78,6 +78,12 @@
"resolved": "10.0.10", "resolved": "10.0.10",
"contentHash": "f5VCIE7AJpd5YvzNTeMGVzQIgyE9tX+AreTYwQF+REbu+DZo/2Ae+jNSwhPEYrVz6RRkd7y8ubXjk6Nn6Ka+Cg==" "contentHash": "f5VCIE7AJpd5YvzNTeMGVzQIgyE9tX+AreTYwQF+REbu+DZo/2Ae+jNSwhPEYrVz6RRkd7y8ubXjk6Nn6Ka+Cg=="
}, },
"MinVer": {
"type": "Direct",
"requested": "[7.0.0, )",
"resolved": "7.0.0",
"contentHash": "2lMTCQl5bGP4iv0JNkockPnyllC6eHLz+CoK2ICvalvHod+exXSxueu9hq+zNkU7bZBJf8wMfeRC/Edn8AGmEg=="
},
"Avalonia.BuildServices": { "Avalonia.BuildServices": {
"type": "Transitive", "type": "Transitive",
"resolved": "11.3.2", "resolved": "11.3.2",
@@ -1170,6 +1176,34 @@
"resolved": "1.0.22", "resolved": "1.0.22",
"contentHash": "KPD9SloJFclrsjnhABu7dzWrcyYkwPbvx5l1gRSPAX/0n+OBtSiVCKtGFv4n+ecWUHU0tCG9LSSwoZZx673zBQ==" "contentHash": "KPD9SloJFclrsjnhABu7dzWrcyYkwPbvx5l1gRSPAX/0n+OBtSiVCKtGFv4n+ecWUHU0tCG9LSSwoZZx673zBQ=="
} }
},
"net10.0-android36.0/android-x64": {
"HarfBuzzSharp.NativeAssets.Android": {
"type": "Transitive",
"resolved": "8.3.1.3",
"contentHash": "Yte9/yYql8ngAjo7YgHlXSinLJcJXIRBM9gegVXpJ2SVYT1i2O/wMA+H3jmYiYiTQxHpHKi4exZUcMzry171MA=="
},
"HarfBuzzSharp.NativeAssets.Linux": {
"type": "Transitive",
"resolved": "8.3.1.3",
"contentHash": "RI6A1LgmooU30+4QIyFt5rmBCzP0VzTR+587IJSGvYIsHHWlahFufihYxtraLfsIhW7I8dn6+xX+DZGygOPKWQ=="
},
"SkiaSharp.NativeAssets.Android": {
"type": "Transitive",
"resolved": "3.119.4",
"contentHash": "qfjNh5hZBZxpOIM1aeDByj2qNbcK2JZG5Y7YyGSeliaYnf1N/hVfsswIPUa+qzcMqS9Q0VCGk85zQLvwVXtrvQ=="
},
"SkiaSharp.NativeAssets.Linux": {
"type": "Transitive",
"resolved": "3.119.4",
"contentHash": "UAyVzbqNfZsZbKbzj68zXLyUyF/SbTKmzTfOO6qDu++dtIUMMTzPBe8oOuzU/DiewpfKoUUlOSsJmqWc6blxBw=="
},
"libsodium": {
"type": "CentralTransitive",
"requested": "[1.0.22, )",
"resolved": "1.0.22",
"contentHash": "KPD9SloJFclrsjnhABu7dzWrcyYkwPbvx5l1gRSPAX/0n+OBtSiVCKtGFv4n+ecWUHU0tCG9LSSwoZZx673zBQ=="
}
} }
} }
} }