This is another Wally-themed episode my friend. Looks like I’m stuck on these, but you do remember those books, right? Where’s Wally? Or Waldo, depending on which side of the Atlantic raised you.
Where’s Wally? was a deliberately chaotic series of illustrated books, stuffed with confusion and distraction, red herrings sprinkled on top, and somewhere in that color maelstrom, one striped character waiting to be found. Finding Wally is a somewhat fine-grained search problem akin to so many other mechanical tasks. Cumbersome, sometimes maddening, but ultimately a pattern-matching exercise where your eyes scan, discard, scan again, and bam! There’s the fella.
Now consider a new proposition for the Where’s Wally? saga: once you find the guy, look at what he’s doing. Does it look like he’s doing something illegal? Is he stealing from that vendor? Is he jaywalking in front of a bus? Is he carrying a suspiciously large bag through customs? What type of shenanigans is he up to, hmm? You’ll be the judge, and you win or lose by correctly calling balls and strikes.
This proposition is an entirely different cognitive exercise. You need context. You need to understand the scene around him. You need memory of what’s socially acceptable in that particular frame. You need judgement.
Two steps. One picture. No internet pun here. Completely different skills.
Finding Wally is what we are used to, but judging him brings a whole extra layer of requirements to the table that makes the challenge way more interesting.
What does this teach you about B2B sales? Nothing. But how about code reviews? Let’s turn the page to find it out.
A typical code review starts with a change to something that already exists, a chunk of code that changes a previous version of, well, another chunk of code. Sometimes you are reviewing a full project with a specific objective. Sometimes it is the first version of something but, most of the time, somebody sends you a diff and asks whether the change should go in.
Upon first inspection, you rarely stay inside that diff. You expand outward. You inspect the surrounding classes, follow a call into another service, look at an interface, check where a value came from, inspect a database migration, or find the consumer of an API that was just changed.
Some would rather start with the tests, regardless of whether the code was actually developed using TDD. Tests can be one of the fastest ways of understanding what the author believes the new behavior should be. And sometimes the difference between what the tests claim has changed and what the implementation actually changes is where the interesting part of the review begins.
The objective is not necessarily to read every line of the repository. It is to build a good-enough picture to understand the change.
This is our first version of finding Wally. And we’ve been doing it with our bare eyes and mushy brains for decades.
Humans naturally mix this search process with judgment. We read a little bit, notice something, form a hypothesis, read some more, reconsider it, and perhaps leave a comment. That is not necessarily a bad way of working. In fact, judgment often helps us decide where to look next.
If I notice suspicious shared state, I will probably follow the concurrency paths. If I see a transaction boundary in an unexpected place, I will inspect what sits behind it. If an API contract changed, I will start looking for consumers.
So code review is not really:
read everything, then start thinking.
It is more like:
observe, hypothesize, expand the context, revise the hypothesis, judge.
The problem comes when we collapse those stages too quickly. We notice something strange and immediately convert it into a review comment. But a suspicious pattern is not yet a review finding. Sure, some things can be caught early and fixed without full context. A formatting inconsistency. A typo. Dead code. An import that is no longer necessary. These are mechanical on most occasions. They belong close to the Wally-finding side of the exercise.
Other things live somewhere in that liminal space between mechanics and judgment.
A strange variable name may look like a readability problem until you discover that it uses terminology from the business domain. Some duplicated code may actually represent two concepts that happen to look similar today but evolve independently. An abstraction that seems unnecessary locally may exist because of a constraint elsewhere in the system.
And then there are questions that are unmistakably contextual.
Does this implementation make sense within the existing architecture? Does it actually solve the problem we were asked to solve? Is eventual consistency acceptable here? Is the added complexity justified? Is this the right trade-off given the constraints of this system and this organization?
Those questions cannot reliably be answered by staring harder at one block of code. You need the picture with progressively more context and better resolution.
This is where LLM-assisted Wally-catching review becomes particularly interesting. A good code-aware model can inspect a lot of material very cheaply. It can follow references, compare implementations, inspect tests, look for repeated patterns, identify suspicious error handling, trace where a value is consumed, notice that an interface changed without an obvious corresponding update somewhere else, or simply ask questions about pieces of code that a human reviewer might reasonably skim or ignore.
After hundreds of lines, another configuration file looks remarkably uninteresting. Another mapper looks exactly like the previous three. The fourth test fixture probably feels less exciting than the first (as if test fixtures were ever exciting).
Our friendly LLM has a very useful property here: asking it to inspect one more boring thing costs almost nothing.
But we also know very well that the relevant context of a software system frequently extends well beyond its source code. There are deployment constraints, data already sitting in production, feature flags, ADRs, external systems, undocumented agreements between teams, historical decisions, operational incidents, and business requirements that may exist nowhere near Git.
The code repository is just one of the picture artifacts, and a very black-and-white-ish one, if I may say.
For a good code-aware LLM, finding Wally is increasingly the easy part. And even better, it can look at a very large portion of the frame at once, layer the differences on top, follow references repeatedly, and revisit details without the same Saturday-afternoon drop in attention span that we humans know too well.
There is also a legitimate objection around size since many software projects are simply too large to give a model everything at once. But I don’t think the interesting architectural question is whether the whole repository fits inside a context window. The more important question is whether the architecture gives us meaningful boundaries. A large monolith can still be understandable if responsibilities, contracts, and dependencies are clear enough to isolate the relevant slice. A distributed system can be almost impossible to reason about if every service depends implicitly on everything else. Size and architectural quality are not the same thing, and good architecture allows context to be progressively disclosed without exhausting the model’s context window.
If you work with projects where understanding a few-line change requires loading half the company into context, code review might not be the process you need to fix or optimize first. I have reviewed codebases that I would not wish on anyone, so I know that nice boundaries are not guaranteed.
The distinction in the picture above matters because the naive version of AI code review is not particularly attractive. A model finds a pattern and immediately tells the developer what to change.
Missing validation. Review comment Potentially expensive loop. Review comment Duplicated logic. Review comment
Soon the pull request contains twenty superficially intelligent observations, and the developer has to review the reviewer. If we are feeling overwhelmed with the current code output, reviews like these will just make it even more frustrating.
And by the way, we didn’t need LLMs for this. So many automated tools already create this type of noise, and you sure do know some “sonars” waiting to get you every time you try pushing code to master. That is not necessarily augmentation unless we are talking about augmenting noise.
A more useful model could be:
detect → gather evidence → expand context → rank suspicion → reason → recommend.
So where does this leave us, carbon-unit humans, in our Wally-judgment book series? Can we leave the Wally-finding to LLMs and reserve the judgment stage for ourselves? Probably not.
Here is where my initial attempt at extending the Wally book series starts becoming a bit more interesting than I first thought. The LLM does not have to stop after finding Wally. A sufficiently capable model can look at what Wally is doing too. It can inspect the architecture around a change, understand existing patterns, compare alternatives, and tell us something like:
This dependency introduces synchronous coupling between two components that were previously independently deployable.
Or:
This abstraction duplicates responsibility already owned by another layer and will probably create two competing ways of solving the same problem.
Or even:
Given the architecture already present in this repository, I would move this responsibility here instead and keep this interface stable.
This already goes way beyond mechanical detection and already enters that liminal judgment space.
And if you’ve been around with our friendly LLM helpers, you already know that they can provide very good judgment indeed.
So I don’t want you to take my analogy as:
Machines find potential problems; humans decide whether they are real.
A good model can often decide whether they are real too, and sometimes with high confidence.
If a value can demonstrably be null along one execution path and is unconditionally dereferenced later, that is more than a vague suspicion. If two locks can clearly be acquired in opposite orders, there may be a concrete concurrency problem. If an API schema says one thing and the implementation returns another, that can often be established from the evidence.
And increasingly, the same thing happens at a higher level. An LLM can reason over several services, understand architectural patterns, inspect ADRs, consume requirements, and challenge an implementation choice. Give it enough relevant context, and it may form an opinion that looks suspiciously similar to what we call engineering judgment.
And I’m perfectly fine with that.
The more interesting limitation is context itself, not just the size of the context window we’ve already talked about.
Imagine the model tells me:
This synchronous dependency is architecturally wrong because it introduces availability coupling.
And just maybe it is completely right. But then I tell it:
This feature will live for three months, and building the asynchronous mechanism would cost us two weeks. And suddenly the answer probably changes. The synchronous dependency might now be the perfectly sensible trade-off.
So we give the LLM that context too, and then perhaps another constraint appears, and another. This is much closer to how engineering actually works. The repository doesn’t contain the full system of incentives, constraints, history, and compromises behind every line of code.
Sometimes I know something the model doesn’t. Sometimes the model notices something I don’t. Sometimes one of us is simply wrong.
That is starting to look less like a tuple of (mechanical assistant, smart human) and more like two reasoning systems with different context and different failure modes.
However, there is one distinction that remains very real and ties my analogy together in the correct way.
Accountability.
The LLM can tell me that the change is safe, reason over the architecture, propose the corrections, and it can even produce a better solution than the one I had in mind. But when the P1 hits the fan, I cannot finger-point at the model and walk away. I accepted the change, approved the trade-off, and, in the end, I own the system. I pulled the lever on this trolley problem full of code.
The important bits are:
- Human judgment is not inherently superior.
- Judgment and accountability are not the same thing.
The machine can make the case, but we still put our fingerprints and sign it with blood, not tokens.
LLM-assisted code review augments any software engineer’s powers, but not because the model only handles the big boring part. It expands how much of the search space we can afford to inspect. It systematically looks at things we might otherwise skim, reminds us about interactions we did not initially follow, and can surface candidate problems before our own attention happens to land on them, if it ever would. It can also reason about those findings, challenge architectural decisions, and propose alternatives. Sometimes it can even force us to explain why we disagree, and that last part may be one of the most useful things of all.
If the model tells me:
This design is wrong because of X, Y, and Z,
I should not reject the comment merely because I am the architect.
I should be able to explain why the model is missing something, why the trade-off is intentional, or why my original decision still holds. And sometimes I won’t be able to do so. Good. Perfect!
So perhaps my enhanced Where’s Wally? version for software engineers might make some sense.
First, find Wally. Then understand what Wally is doing. Then build the case for whether something is wrong. Check your premises and make the call.
The LLM can increasingly participate in the first three. It can search the scene, gather context, form an opinion, and propose what should happen next. The human role is not to sit on some magical throne of superior judgment. It is to challenge the reasoning, add the context that is missing, weigh the trade-offs, and ultimately own the decision.
Let the machine find Wally and inspect the scene. Let it tell you why it thinks Wally is breaking the law. Then make it prove the case before you convict him.
Because in the end, the machine can make the case, but you still sign off on it.
PS: Don’t yet have a name for such a book.
PPS: Still want to keep finding Wallys for fun? How about a semicolon instead? Pay a visit to semicolon.trm.sh and go wild :)
