Build It in Go · Episode 2
5 AIs Built the Same Go App. I Reviewed Them Blind.
The one project I’d merge was the most broken code in the contest.
I gave five AI models the exact same spec and had each one build the same Go app, twice, from scratch. Then I reviewed all ten projects blind. There was exactly one I’d merge, and it turned out to be the most broken code in the whole contest. Here’s how it was scored, which AI actually won, and the one line of Go that fooled me.
The contest: a URL shortener
The app is a URL shortener, like Bitly. You give it a long link, it gives you back a short code, and anyone who visits that code gets redirected while the app counts the visit. I picked it because it’s small enough to build in one sitting, and it has real traps:
- It has to save your links so they survive a restart.
- It needs an admin token, so random people can’t delete your links.
- It has to handle a lot of visitors at the same time without losing count.
One rule makes it harder: standard library only. No frameworks, no database packages, just Go. I wrote it all down in one spec, and every model got the exact same words.
The five models were GPT-6.1 Sol, Claude Opus 5.5, Claude Sonnet 5.5, Gemini 3.1 Pro and DeepSeek V3.2. Each one built the app twice, from an empty folder, in the same harness with the same six tools, 40 model calls and 20 minutes. AI doesn’t give you the same answer twice, and I wanted to know whether a model was actually good or just got lucky once. That’s ten projects.
How it’s scored
If I just looked at the code and picked my favorite, that would be a vibes video. So the score is out of 100, and most of it doesn’t come from me.
- Does it work? (40 points) 55 hidden tests the models never saw. They start the program and talk to it over HTTP: the API, the admin token, restarts, and lots of visitors at once.
- Bugs and security (20 points) Security and error-checking tools plus Go’s race detector over every project. Every confirmed problem in the shipped code costs points. Problems in test files don’t count.
- Readable Go (10 points) Also measured by tools, like how complex the functions get, and ranked across projects.
- Its own tests (10 points) Did the model write tests, do they pass, and how much do they cover?
- Would I merge it? (20 points) That’s me. Would I approve this pull request, and do I actually understand it?
How do I know the hidden tests are fair? I ran them against my own hand-written version of the app and it passed all 55. Then I planted 15 realistic bugs in copies of it, like a missing admin check or an unlocked visit counter, and made sure the tests caught every one.
One disclosure: I used Claude to help build the scorer and write the hidden tests. So yes, Claude helped grade Claude. That’s exactly why the spec, the tests, the scorer and all ten projects are public. You can check every number.
My blind review
Before I saw a single score, I reviewed all ten projects with the names hidden. They were renamed A through J and shuffled, and I didn’t know which model wrote which. I reviewed them the way I’d review a pull request at work. Not “does it pass the tests?”, because I hadn’t seen the tests yet. Just: if this landed in my queue, what would I do?
A lot of them ended up tied, not because they were all great but because they did things I didn’t like in the same ways: too much code, and more structure than a small app needs.
Then there was A. A was the one I’d merge. It was small. I could open main.go and follow it from top to bottom. Clear names, no clever tricks, and the least complex code of all ten. Its own tests passed on my machine. I gave it 10 out of 10 for “would I approve it” and 10 out of 10 for “do I understand it”, the only project that got both.
At the very bottom I put G. Too much going on, hard to follow. Remember G.
The twist: the hidden tests
Then I ran the hidden tests. Every Claude project passed all 55. Both GPT projects passed all 55. Gemini passed 53. A passed 46, the lowest of all ten.
The one line of Go that fooled me
It came down to one line. When someone visits a short link, A kicks off saving the visit in the background with a go func and redirects them right away:
// Increment visits asynchronously
go func() {
if err := h.store.IncrementVisits(code); err != nil {
log.Printf("Failed to increment visits for %s: %v", code, err)
}
}()
http.Redirect(w, r, link.URL, http.StatusFound)Honestly, that looks smart. The visitor doesn’t wait on a disk write. If you’ve written Go for a while, you’ve probably written this exact pattern.
Here’s what happens under load. One of the hidden tests sends 500 visits at the same time. A recorded 39. Every visit gets its own background save, and every save rewrites the whole file to disk, one at a time. So they line up. By the time all 500 visitors had been redirected, only 39 visits had been saved. The rest were still waiting in line, and if the server stops right then, they’re gone.
And the tests that passed on my machine failed in the scored run, for the same reason: a test finished and started cleaning up its temp folder while a background save was still writing to it. The tests were flaky. They pass until they don’t, which is the worst kind of test, because most of the time it tells you everything’s fine.
So did I make a bad call? Everything I judged was true. A really was the clearest code in the contest. What I couldn’t see by reading was how it behaves when 500 people show up at once. That’s what tests are for. Clean isn’t the same as correct, and that’s why my review is only 20 points out of 100. I set it up that way before I saw any results, because I know a human reviewer can be fooled. I just didn’t expect it to be me, this fast.
Results: who actually won
| Model | Works /40 | Bugs /20 | Readable /10 | Own tests /10 | Merge /20 | Total | Cost per run |
|---|---|---|---|---|---|---|---|
| GPT-6.1 Sol | 40.0 | 11.0 | 10 | 10.0 | 10.0 | 81.0 | $0.33 |
| Claude Sonnet 5.5 | 40.0 | 4.0 | 6 | 9.4 | 10.0 | 69.4 | $0.16 |
| DeepSeek V3.2 | 33.5 | 6.0 | 6 | 5.0 | 17.0 | 67.5 | $0.59 |
| Gemini 3.1 Pro | 39.3 | 1.0 | 8 | 8.9 | 8.0 | 65.2 | $1.48 |
| Claude Opus 5.5 | 40.0 | 3.0 | 2 | 8.9 | 8.0 | 61.9 | $0.28 |
- 5th, Claude Opus 5.5 (61.9). That one surprised me. It passed every hidden test in both runs, but lost points on bugs, came last on readability, and I didn’t love either of its runs.
- 4th, Gemini 3.1 Pro (65.2). Close to perfect on the tests, but the most confirmed bugs of any model.
- 3rd, DeepSeek V3.2 (67.5). That’s A’s model. It got the highest score from me, and still lost the most points on the hidden tests: its two runs passed 46 and 49.
- 2nd, Claude Sonnet 5.5 (69.4). Every hidden test in both runs, good tests of its own, and the cheapest and fastest at about a minute and 16 cents a run.
- 1st, GPT-6.1 Sol (81.0). All 55 hidden tests in both runs, the fewest bug findings, first on readability and full marks for its own tests.
And remember G, the project I ranked dead last? That was GPT. G was one of the winning runs. To be fair to me, its other run, C, was my second pick. But the project I’d merge came from third place, and the project I ranked last came from the winner.
Four lessons
- Clean isn’t always correct. The easiest code to read was the most broken. If you only review by reading, you’re grading the writing, not the program.
- Human review can be fooled, and that’s okay. My review is good at whether code is clear and whether I’d want to maintain it. It can’t see what happens at runtime. So run the tests before you judge the code, not after.
- Bigger didn’t mean better. Claude’s biggest model came last and its smaller sibling, Sonnet, came second. For a small app with a clear spec, size wasn’t the advantage.
- Run it more than once. GPT’s two runs were one I ranked second and one I ranked last. DeepSeek’s two runs passed a different number of tests. Judge a model on one try and you’re partly judging luck.
And if you write Go, be careful with go func inside a request handler. If the work matters, don’t fire and forget it: do it before you respond. If it really has to happen in the background, keep track of it, wait for it to finish before you shut down, and test it under load, not just once.
Run the scorer yourself: the repo has the spec, the hidden tests, the scorer and all ten projects. If you think one of my scoring rules is unfair, tell me which one and why in the YouTube comments. The review agent that helped grade these is from episode 1.
Next up: a free AI model on my 8 GB Mac, without crashing it.
Project Details
Technologies