Analysis Kevin Lee

AI fills the code review gap most teams never talk about

Most engineering teams review for correctness. What they miss is the slower, harder problem: developers who write code that works but does not look like it belongs in the codebase. This gap is where stack switching breaks down.

AI fills the code review gap most teams never talk about

The first time we showed a developer's Go PR to a senior Go engineer who had never seen HackQuest before, the feedback was immediate: "This code works, but it doesn't look like Go." The PR had no bugs. All tests passed. The logic was sound. But the error handling used exception-style flow, goroutines were started without clear ownership, and the struct methods used receiver names that were five characters long instead of the idiomatic single initial.

Nothing in that PR would get flagged by a linter. Nothing would fail in code review unless a senior Go developer who cared about idioms was paying close attention and had time to explain themselves.

Most don't. Most teams don't.

The gap nobody names

Engineering teams have reasonably good processes for reviewing correctness. PRs get looked at for obvious logic errors, security holes, and test coverage. But there's a second layer of review that happens inconsistently and silently: whether the code looks like it belongs.

When a developer writes Python for five years and switches to Go, they bring a mental model of how code should be structured. That mental model is wrong for Go in specific, predictable ways. Functions get longer than they should. Error handling happens at the top of a function rather than at each call site. Goroutines get launched inside loops without tracking whether they'll complete. These patterns don't cause immediate test failures. They accumulate into codebases that other Go developers have to maintain with increasing friction.

The code review process mostly catches bugs. It rarely catches mental model mismatches, because mental model mismatches are hard to articulate quickly in a comment box, and most reviewers don't want to write a five-paragraph explanation during a lunch break.

What this looks like in a real PR

Consider a PR that adds a worker function in Go. The developer came from Python with strong asyncio experience, so they understand concurrency well in the abstract. Their implementation launches goroutines and uses channels to collect results. The tests pass. But the goroutines are launched inside a range loop over a slice, the done channel is unbuffered, and there's no context cancellation path.

A senior Go reviewer who looked at this would want to explain: goroutine lifecycle, why an unbuffered channel here creates a race condition under specific timing, why context cancellation matters for production code, and why the loop pattern needs a WaitGroup or errgroup. That's four distinct concepts. In a code review, they might write "consider using a WaitGroup here and adding context cancellation" and move on, because that's all the time they have.

The developer reads the comment, looks up WaitGroup, applies it, gets the PR approved. But they haven't actually understood why the original code was problematic. They've fixed the symptom. The next PR will have different goroutine lifecycle issues, because the underlying model is still wrong.

This is the gap. The fix was applied, but the concept wasn't transferred.

Why traditional code review cannot close it

Code review is not designed to be a teaching mechanism. It's designed to catch issues before they reach main. The two goals occasionally align, but the incentive structure of code review pushes reviewers toward efficiency: comment on what must change, approve if acceptable, move on.

Teaching requires patience, sequencing, and feedback that meets the learner where they are. A good explanation of goroutine lifecycle takes ten minutes if the person already understands interfaces and channels. It takes forty minutes if they don't. Reviewers generally don't know which case they're in, and they don't have forty minutes.

Teams that have a senior developer who will sit with a new-stack developer for an hour a day and trace through concepts in their actual code do close this gap. But that's a significant investment, and that senior developer has their own production work to do. It doesn't scale past a very small team, and even in small teams it degrades quickly when the senior developer is heads-down on something critical.

Where AI grading actually helps

The specific thing AI grading can do here is not replace the senior developer. It's doing the job that the senior developer would do if they had unlimited time and full knowledge of what the developer already understands.

When HackQuest grades a PR, it reads every changed line and maps each error to a concept category. A goroutine launched without lifecycle tracking maps to "goroutine ownership." An unbuffered channel used for signaling between goroutines maps to "channel buffering semantics." These are different concepts with different lessons. They're also concepts the system already knows whether the developer has seen before.

If the developer has already been through a goroutine lifecycle lesson, the feedback in the next PR can be terse: same goroutine ownership issue as PR 4, here's what's still missing. If they haven't, the feedback queues that lesson first and surfaces the PR comment as an entry point into it.

That feedback loop, where concept identification drives lesson selection, is what's missing from standard code review. It's not that code review is wrong. It wasn't designed to do this.

We are not saying code review should be replaced

To be clear about what this is not: AI PR grading is not a substitute for team code review. Production code needs human review for context, business logic, security, and the thousand things that require knowing what the system is actually supposed to do. No automated process replaces that.

What we're describing is a separate track for developers who are still building fluency on a new stack. That track runs alongside production work. The PRs being graded are practice PRs, against a learning branch, specifically designed to surface concept gaps. The goal is to compress the time between "writes code that works" and "writes code that belongs" from twelve months to six weeks.

The gap between working and belonging is real. It's common. Teams talk around it without naming it, because naming it feels like saying the developer isn't good enough, which isn't the point. The point is that stack switching takes time for specific, identifiable reasons, and those reasons can be addressed systematically if you know what to look for.

We built HackQuest because we watched this gap cause real problems. Developers who were genuinely capable spending months writing code that worked but accumulated review friction. Seniors burning hours on comments that weren't sticking. The feedback loop between "here's what you wrote" and "here's what you were missing" was too slow and too lossy. That's the thing we're trying to fix.