skip to content
graham@mccarthy:~$

My AI Filed 51 Issues Against Its Own Code. Then It Shipped the Fixes.

graham_m·2026-07-31·6 min read
My AI Filed 51 Issues Against Its Own Code. Then It Shipped the Fixes.

Eight months ago I launched Multiplay Games, a real-time multiplayer party platform built entirely with AI-assisted development. That post was about prompting techniques. This one is about the part that actually changed how I build software.

The interesting frontier isn't AI writing code. It's AI running the whole loop: review the codebase, file the tickets, ship the PRs, and write down what it chose not to do. That didn't make my job smaller. It moved it up a level, from writing the code to directing the work: deciding which problems matter, pointing the AI at them with the right lens (a security audit, a game-design review, a marketing pass on the copy), setting the bar for the product experience, and keeping the merge button. In one month that loop produced 45 merged PRs, a critical security find, and a brand-new game that went from idea to production in 24 hours.

Here's how it happened, and what I'd tell you to steal from it.

Three acts

The git history tells the story in three acts.

Act 1 (Nov–Dec 2025): build fast. Thirty-nine PRs in two months, all from direct AI sessions. Eight games, a realtime migration off polling, a replay system, subscriptions.

Act 2 (Jan–Jun 2026): dormancy. Two PRs in six months. Life happened and I stopped watching the site, but people didn't stop playing it. When the admin dashboard later backfilled usage history, the quiet months weren't quiet at all: rooms kept getting created the whole time. Nobody was maintaining it, and it didn't matter. That I didn't expect.

Act 3 (Jul 2026): the loop. I pointed the AI back at its own year-old codebase, one review pass per lens I cared about: game design, security, staff-engineer rigor. Those three passes filed 51 issues in one night, every issue the repo has ever had. Those issues became PRs: 45 merged in a month, about 40 of them in a single three-day sprint. Issues → PRs → deploy, with me as the approval gate.

Five things the AI did that I didn't expect

1. It traced a five-link failure chain through its own past decisions. The self-review found a P0 (#73): starting a game rotates the room's encryption key, only the owner gets the new key directly, and everyone else learns it from polling. But a bandwidth optimization the AI itself shipped last December disables polling when realtime is healthy, so score submissions fail with an error the client silently swallows. Result: in bigger rooms, some players sat at 0 on the leaderboard all game with no error anywhere. The fix (#80) came with a scripted reproduction of the exact sequence. My favorite detail: mid-investigation it cleared one of its own suspects, noting that a "stuck in lobby" state it had reproduced was actually the idle-disconnect feature working as designed on a hidden tab.

2. It audited its own new feature and found a seven-month-old critical hole. Asked to security-review the admin console it had just built, the AI ran the database advisors and discovered that every privileged database function (including the delete-everything ones) was executable by anonymous visitors through the public REST API (#129). Postgres grants execute permission to everyone by default, and seven months of migrations had never revoked it. Anyone could have wiped every room and account. The AI verified nothing legitimate used that path, wrote the lockdown migration for all 14 functions, and, blocked by design from touching production, escalated to me. The hole was closed about 40 minutes after discovery.

3. It measured before refactoring, and left the abstraction unfinished on purpose. Before proposing any consolidation, the AI quantified the duplication across seven game pages: 70–78% matched lines, ~9,100 lines that could collapse to ~700 shared (#77). It also wrote an explicit do-not-do list: Quick Draw, at 16% overlap, "would poison the abstraction" and must never adopt it. The rematch consolidation alone removed a net 1,803 lines (#87); the shared orchestrator cut Wordle by 41% and Trivia by 40% (#117). Five of seven games are still on the old wiring, tracked by a written checklist. Incremental, not heroic.

4. Asked "does the cleanup cron work?", it answered "it has never run." Instead of reading the code, it checked production config: the cron file was empty (#100). The data-retention job promised by the privacy policy had never been scheduled. It quantified the backlog (654 stale rooms, 1,425 history rows, 9 accounts past their deletion deadline), then refused to merge its own fix, flagging the PR as a destructive first run that only the owner should merge. In effect: you pull this trigger. One accidental upside of the late start: the admin dashboard could backfill usage trends all the way to December 1, history an always-on cleanup job would have deleted.

5. It shipped a game in 24 hours and playtested it before merging. Ballpark (everyone guesses a number, closest to the truth takes the points) went from proposal to production in a day: a pitch with three rejected alternatives (#120), then a +3,465-line implementation with 627 passing test assertions (#128). Before merge, the AI ran a real two-browser playtest, desktop host and mobile guest, and filed bugs against its own game: the reveal screen said "CLOSEST!" next to "+0 points," and the final podium crowned a "CHAMPION — 0 PTS" (#137). The scoring fix and three mobile UX issues shipped the same day, each re-verified live.

Operating, not just building

By late July the AI was acting like it ran the place. The admin console it built (pictured above: pixel-art charts, no chart library) got an accuracy audit against live production data, and every stats bug was quantified before fixing: "2 of 110 days inflated, max +2" (#131–#136). Generated database types caught two games reading a column that doesn't exist (#114). A lint sweep surfaced a prop that was wired up but never called (#95). The repo has zero TODO comments, not because nothing is unfinished, but because unfinished things live in issues instead.

What didn't ship (and why that's the point)

A "built 100% with AI" claim invites skepticism, so here's the honest ledger. A second new game exists as a fully-designed five-phase epic (#121–#126) with zero lines of code. A handful of hardening ideas were weighed and consciously deferred, with the tradeoffs written down in the issue tracker rather than quietly ignored. The performance numbers from the launch post were the migration's design targets, not independent benchmarks, and I've updated how I phrase them.

That ledger is the real product. Every caveat above was written down by the AI itself, in issues, PR bodies, and do-not-do lists. Code generation is table stakes now. What the loop produces that a coding session doesn't is candor with receipts.

If you're building with AI, steal the shape. Your value isn't typing the code anymore; it's picking the right problem, choosing the lens the AI looks through, and holding the quality bar. Give it the whole loop, keep the merge button, and make it write down what it didn't do.

Play the result at grahammakesgames.com, or see the project page for the full build story.