With capacity=2 in the runner, two builds can run in parallel and share
the same buildkit cache mount (sharing=shared is the default). dotnet
restore writes NuGet temp files (*.ar5 etc.) that the OTHER build can
race-remove mid-extraction, yielding 'Could not find file' errors like:
error : Could not find file '/root/.nuget/packages/microsoft.identitymodel.abstractions/8.0.1/3wu4hkqc.ar5'
sharing=locked serializes cache access (one build at a time can touch
the mount). Still benefits from across-build caching, just no concurrency
on the mount itself.
Mirror the cache infra added to nas-auth (commit a1ecba3):
- Dockerfile: `RUN --mount=type=cache,target=/root/.nuget/packages`
for restore + publish, with syntax 1.6 directive.
- workflow: cache-from/cache-to registry cache mode=max, so buildkit
layer cache survives across CI runs (fresh buildkit per run otherwise).
First run after this still pays full cost; each subsequent run should
drop ~50% off dotnet restore.