winget was the wrong road$ winget install --id GoLang.Go --source winget --silent --disable-interactivity
(no output, no toolchain, hangs until killed)
winget wants a session it can elevate from. From a non-interactive automation context there is nothing to show the UAC prompt to, so it blocks forever and prints nothing at all — the worst possible failure shape, because it looks identical to "still working".
The official ZIP archive needs no elevation: unzip it into a directory you already own and
put bin on your PATH. That is everything the MSI does that matters. Written up as
tools/install-go.ps1, which:
https://go.dev/dl/?mode=json which release is current, so the script does not go
stale with a pinned versionwindows-amd64 archive and verifies the SHA-256 from that same JSON%LOCALAPPDATA%\Programs\Go…\Go\bin to the user PATH — no admin, nothing outside the profileOn the checksum, honestly: it comes from the same origin as the download, so it proves the bytes arrived intact, not that go.dev is honest. That is exactly the assurance the MSI gives too.
go version go1.27.1 windows/amd64
One gotcha that will bite again: a persistent PATH change is read at process start, so
every terminal already open — including the one that ran the installer's parent — cannot see
it. The script sets $env:PATH for its own session so the verification works immediately;
other shells need restarting.
PASS c
PASS java8
PASS go
PASS python
4 passed, 0 failed, 0 skipped
gofmt -l . printed nothing and go vet ./... was clean, both first time. That is worth
recording rather than glossing: of the four tracks, Go is the only one where the first
compilable version was also byte-exact against the golden file. The C track needed the
%-20.20s precision fix and the _setmode call; Java needed the thenComparing type
annotation and the byte-level stdout write.
That is not because Go is better. It is because Go has fewer places to make a decision, and three of the decisions the other tracks got wrong are ones Go does not offer you.
strings.Fields on tabs — still unverified, and it is a fixture gap, not a track
gap: access.log contains no tab-separated line, so no track's whitespace handling is
actually exercised against one. Closing it means regenerating the fixture, which means
regenerating the golden file, which means amending SPEC 1. Deliberately not done as a side
effect of adding Go. Logged below.%-20s pads by runes in Go, by bytes in C — confirmed by reading, not by test, since
SPEC 4 says ASCII and no fixture service is non-ASCII. Real divergence, currently masked.dot < 1 guard — correct. strings.IndexByte returns -1 for absent and 0 for
a leading dot, and both must be rejected. The fixture's 12.48 and -3.000 cases pass.GOOS=linux GOARCH=arm64 go build -o logagg-linux-arm64 .
ELF 64-bit LSB executable, ARM aarch64, statically linked
One command, from a Windows x64 box, no toolchain to install, statically linked. The Q2 claim about why infrastructure tooling is written in Go rests on this, so it was worth spending thirty seconds proving instead of asserting.
os.Stdout.WriteString writes the bytes given, on every platform. The other three tracks each
needed a different fix for the same problem:
| Track | Fix |
|---|---|
| C | _setmode(_fileno(stdout), _O_BINARY) |
| Java 8 | System.out.write(s.getBytes(US_ASCII)) |
| Python | sys.stdout.buffer.write(s.encode("ascii")) |
| Go | nothing |
Four rows, and the best single illustration in the repo of what a language choosing a default for you is worth.
Go does not merely leave map order unspecified — the runtime actively shuffles it per run, so a program depending on it fails on the first developer's machine rather than in production two years later.
Which means: without SPEC 3's mandatory tie-break, this program's output would differ between
consecutive runs of the same binary. The other three tracks would have passed regardless —
CPython's dict is insertion-ordered and Java's HashMap is at least stable within a JVM
version. Go is the track that would have caught a missing tie-break, and it is the strongest
retrospective argument for that clause being in the spec at all.
os.Exit, in one placefunc main() { os.Exit(run(os.Args[1:])) }
os.Exit skips deferred functions. Calling it inside aggregate would silently skip
defer fh.Close(). Putting all the work in a function that returns a code, with exactly one
os.Exit at the top, is the standard Go answer — and worth carrying back to the Python track,
where sys.exit inside a with block has a milder version of the same shape.
access.log, regenerating the golden file, and amending SPEC 1 in
the same commit so the change is reviewable. Until then no track's whitespace handling
is tested against a tab.--shard N (SPEC 6) with a chan map[string]*Stats, then go test -race. This is the
track where the concurrency stretch goal is the actual content rather than an extra.sync/errgroup and errors/wrap.go (Q9).