All checks were successful
check / check (push) Successful in 1m23s
The reordered COPY --from=lint did not make the two stages provably one toolchain, as the Dockerfile comment, the previous commit message and TODO.md all claimed. script/bootstrap compares its pin against whatever PATH resolves, and $GOPATH/bin sits ahead of /usr/local/bin, so any drift was absorbed: bootstrap rebuilt the pinned version from source, verified that, and the build went green with the lint stage having linted at one version and make check having run at another. Bumping the lint stage image without touching the pin was enough to produce it. New script/verify-linter-pin fails, naming both versions, unless a given golangci-lint binary is exactly the version script/bootstrap pins. The build stage runs it on the binary copied out of the lint stage, immediately after the copy and before bootstrap, so no reinstall can satisfy it. The pin is read out of script/bootstrap, which stays its single source of truth; a pin that cannot be read is a hard failure rather than a skip. The check takes no CHECK_EPOCH because its only inputs are the copied binary and script/, so Docker invalidates the layer exactly when a cached result would stop being true. The linter version is pinned independently in the lint stage's image digest and in GOLANGCI_LINT_VERSION, with nothing keeping them in sync; a half-applied bump is now a build failure instead of a silent split. ENV PATH keeps $GOPATH/bin, but its comment no longer claims a reinstall is the reason: bootstrap must be able to run and verify what it installs, and nothing in this image is shadowed by the entry. Verified: with the lint stage's linter faked to 2.11.0 after the gates had really run, the build fails at verify-linter-pin naming 2.11.0 and 2.12.2, with bootstrap and the check gate never reached; an unmodified make docker is green with all three gates run on a fresh epoch and real test results. A planted unused finding still fails at the lint stage with gate check absent from the log; the image still fails TestScanHardlinkRunFailsTogether under --user 0:0 and passes as uid 1000, both with the Go test cache disabled; and a second build serves bootstrap, the verify layer and the dependency layers CACHED while the gates go cold.