In my previous post I argued that the human code review has become the bottleneck in our software delivery process, and that most of what a review used to buy us no longer fits in a diff. That leaves an obvious hole. If we stop reading every generated line, when does a human ever look at this code, and what should they be doing when they do?

Understanding code is the work that comes naturally after vibe coding: you take code that was generated fast, that passes a demo, and that nobody on the team can explain, and you turn it into something you would be willing to run in production. Right now that work is unplanned, unowned and done alone, usually by whoever gets paged.

I want to make it a ceremony. Same slot every week, a fixed length, a defined output, like a retrospective. I call it a Grokathon. To grok, from Heinlein’s Stranger in a Strange Land, is to understand something so thoroughly that it becomes part of you. The word is sixty-five years old and predates the chatbot it now shares a name with. A hackathon is a race to produce code nobody understands yet. A Grokathon is the opposite ritual on the same code: nobody adds a feature, everybody has to be able to explain one.

You understand a codebase by cleaning it up

Ask anyone who has inherited a codebase how they got to know it. Nobody says they read it. They renamed something, moved a file, deleted a function to see what broke, and after a week of that they knew where everything was. You learn a system by putting your hands in it. Reading is what you do when you are not allowed to touch.

A generated codebase arrives all at once. It runs, the demo looks great, and nobody has ever been through it. Three helpers do the same thing, there is a config option nobody sets, there are defensive branches for conditions that cannot happen, and somewhere in there are the two functions that actually run in production. From the outside it all looks the same.

The ceremony is simple. Everybody takes a piece of it and cleans that piece up by hand. Five rounds, twelve minutes each, and every round is one ordinary refactoring that you already know how to do.

The ceremony

Ninety minutes a week, in the slot you were already spending on reviewing generated pull requests. Three to six people. The subject is one batch of generated code that has already merged, not a pull request. Everybody clones the same repo, takes one file or module, and works on their own branch.

You can do this alone and it still works, but it works much better with other people in the call, and not because you need the help. It is the rubber duck. Renaming a variable quietly is easy. Saying out loud “this one is called data and it holds the invoices we have not sent yet” is the moment you find out you were guessing. Hunt and Thomas had programmers explain their code to a rubber duck for exactly this reason, and a colleague is a duck that occasionally says “are you sure about that”.

So there is one procedural rule: you may not tidy silently. Say what you are about to do and why, before you do it. That single rule is the difference between four people cleaning up code and a team learning a system.

Two more rules and then the timer. You never take the code you prompted into existence yourself, because you are too kind to your own output and because the point of the session is that this code stops belonging to whoever generated it. And no scoreboard. The only number worth saying out loud is how many things you deleted without the tests noticing, and a high number is bad news for the team, which is exactly why it is the useful one.

Time What
0:00 Divide the work (10 min)
0:10 Delete (12 min)
0:22 Rename (12 min)
0:34 Normalize (12 min)
0:46 Align (12 min)
0:58 Test (12 min)
1:10 Walkthrough (20 min)

The walkthrough is two minutes each: what you deleted, what you renamed, what got past the tests, and what your piece actually does now that you have been through it. Then anything that showed up at more than one desk goes into the rules that produce the code, which is the standards file, the agent skill, the linter config or the prompt. That change is a normal pull request with a normal human review, because a rule that applies to the whole codebase has to be right.

This is where architectural guidelines should have been coming from all along. Not declared in a meeting by whoever had the strongest opinion, but found by hand, by people who just spent an hour with their fingers in the code. A guideline that comes out of a walkthrough arrives with three examples attached, and nobody has to be convinced that it matters.

It runs fine on a video call and a git remote, which is where most teams already are. One repo, one branch each, no pull requests during the session, and a dev container or a single docker compose run test so nobody spends the first round installing a toolchain.

Delete, rename, normalize, align, test

Five rounds, twelve minutes each, and the trick is that understanding is a side effect of all five. You are not trying to understand the code. You are trying to make it neat, and the understanding arrives on its own.

Delete. Anything nothing needs: the third helper that does what the first two already did, the option nobody sets, the branch for a condition that cannot happen, the abstraction with one implementation. Remove it, push it, and let CI tell you what you learned. Red means you just found out what it was for, which is worth more than reading it would have been. Green means one of two things: the code was dead and it stays out, or the tests are blind and you just found a hole. Write the hole down, you will need it in an hour.

Then do the same to the comments. Generated code narrates itself, line by line, in a tone of relentless helpfulness. Delete every comment that says what the code already says, and keep the ones that say why. There will be very few, because the generator did not have a why. What survives that cut is worth reading, which was not true of the file you started with.

Rename. Name things after what they hold. Generated code is full of data, result, processedItems and handleData, names that describe the conversation the model was having rather than the value in the box. You cannot rename something correctly without knowing what it does, which makes this the cheapest way to find out that you do not.

Normalize. Normalize symmetries, in Kent Beck’s phrase: make things that do the same job look the same, and things that do different jobs look different. Three functions handle a missing record in three shapes, one returning null, one throwing, one handing back a tuple. Generated code has almost no symmetry, because every piece was written in a separate conversation without seeing the others. Doing this straight after the renaming is not an accident, because consistent names are what make the inconsistent shapes visible.

Align. Every team has a shape it wants its code to have: which layer talks to the database, where validation happens, how errors travel, what a module looks like from the outside. Your piece does not have that shape, because the generator never read that document, or read it once and drifted. Move it back. This is also the round that tells you whether your guidelines are real, because if you cannot say what the rule is for the code in front of you, that is not a failure of yours, it is the finding, and it goes to the walkthrough.

Test. Every hole the deleting exposed gets a test. Write the one that fails when you take that code out again. Not coverage, not a green wall, just the test that would have caught the thing that got past the suite an hour ago. Then take it out one more time and watch it go red, because a test you have never seen fail is a decoration.

Yes, the tests come last, and normally I would argue the opposite. Here the missing tests are what we are trying to discover, so the first four rounds use the suite you have as an oracle and the last one repays what it could not tell you.

Why this can replace the code review

Sam Newman lists four goals of a code review, and this session serves all four better than reading a diff does. Correctness is checked by the deleting and the testing, which try the test suite itself, the thing that will still be checking correctness next month. Shared learning is the entire session, out loud, in both directions, where a pull request comment teaches one author. Alignment comes from the guidelines the walk produces, which is the only mechanism here that scales, because it changes the generator instead of the output. And awareness follows from everyone having their hands in code they did not generate.

The merge gate does not change. Tests green plus policy satisfied, decided by something deterministic, exactly as before. What changes is where the expensive human attention goes: from one diff at a time to one batch a week, and from the line to the rule. Ninety minutes of a few people against the 441% increase in median review time that Faros measured is not a close call.

Tidy First? was a question, and the answer changed

None of these moves are mine. Kent Beck names them in Tidy First?. Delete redundant comments and normalize symmetries are in his list almost word for word, and explaining variables is the renaming round.

But the title of that book is a question, and the answer is the interesting part. Beck does not tell you to tidy, he tells you when it pays. His case rests on two things. It is social: a person wrote this code and a person will read it next, so structure is a courtesy between colleagues. And it is economic: tidying costs your hours now and pays them back on the next change, so you tidy first when that change gets cheaper by more than the tidying costs. That is why the book also has chapters called Tidy Later and Tidy Never.

Neither is true anymore. Nobody wrote this code, so there is no author to be courteous to and no colleague who was going to read it. And nobody paid for it, so nobody will pay for the mechanical rewrite either, because that is precisely the work the machine now does for nothing.

His answer was “it depends”, and the things it depended on are gone. That does not make tidying less important. It makes the case for it completely different, and a lot shorter:

  1. It is the only way in. No author to ask, no commit message that explains a decision, no colleague who remembers the trade-off. Reading does not work at this volume, and asking the model gives you a plausible answer rather than a true one. Renaming a variable correctly is a test of understanding you cannot pass by accident.
  2. The code is the prompt. Structure used to be for the humans who would read the code later. Today it is the context the next agent reads before it writes. Tidy code generates better code and untidy code generates worse code, on its own output, every day. Beck’s economics had no path from the structure back into the thing that produces structure. Now there is one, and it compounds in both directions.
  3. Asymmetry marks the seams. He normalized symmetries because symmetric code is easier to read. In generated code, two things that do the same job in two different shapes were written in two different conversations, neither of which saw the other. That is where the misunderstandings live, so normalizing symmetries stopped being a matter of taste and became a search technique.
  4. Nothing slows coupling down anymore. Constantine’s equivalence still holds, and Beck could take for granted that coupling accumulates slowly because writing code is slow. A thousand coupled lines is a minute of work now, and removing them costs exactly what it always did.
  5. It is how you take ownership of code you did not write. You cannot be responsible for something you have never touched, and somebody has to be. That one is not an economic argument at all, which is rather the point.

What still holds is the discipline. Structure and behavior never go in the same commit, which is why a Grokathon branch is structural from start to finish and safe to merge the same day. Batches stay small. And Tidy Never is still a real answer, which is why you do not run this on a prototype you are about to throw away.

Tidying is deciding, not editing

If applying a tidying is free now, the obvious move is to hand all five rounds to the agent and have a clean module in ninety seconds. It would do a decent job. And you would have paid for the session and received nothing, because the output of a Grokathon was never the diff.

Which means it is worth saying what tidying actually is. We have been sloppy about that for as long as it did not matter.

Every piece of work produces two things: the artifact, and the change in the person who made it. We only ever pay for the first. The second is a side effect nobody measures, and that was fine, because for most work it is a bonus. Automation is the trade where you keep the artifact and give up the side effect, and for most work that trade is obviously worth taking.

Tidying is the exception, because for tidying the side effect is the product. Which gives you a test you can apply to any task, not just this one. Throw away the diff and see what is left. If nothing is left, delegate it. If what is left is a person who knows something they did not know this morning, that is tidying, and handing it over buys you nothing at all.

Put it the other way around. The code does not need tidying. You do. Sending the agent to tidy for you is sending somebody else to the gym and asking them how it went.

That is not an argument against using the agent during the session. It is an argument about which half of the work you give it, because every one of the five rounds splits into a decision and an edit.

  • It can rename every occurrence in the repository. It cannot choose the name, and choosing the name is the entire exercise.
  • It can delete the comments that repeat the code. It cannot tell you which one was the only place a decision ever got written down.
  • It can make three functions symmetric. It cannot notice that the asymmetry was trying to tell you something.
  • It can apply your architectural guidelines. It cannot tell you that a guideline is wrong, which is the main thing the align round is for.
  • It can write the test. It cannot tell you which behavior was worth pinning down in the first place.

So the rule for the ninety minutes is not “no agents”. It is that you may let it type and you may not let it decide. “Rename data to pendingInvoices everywhere in this file” is fine, and honestly a better use of everyone’s time than doing it by hand. “Clean up this file”, “suggest better names” and “make this consistent” are not requests for help. They are the session, and if you ask for them you have skipped it.

That is the whole ceremony, and it is the reason it survives a tool that can do everything else. Understanding is not something you can schedule directly, but deleting and renaming and testing are, and they reliably produce the other. You are still responsible for what you ship, and now there is an hour and a half in the week where you earn the right to say so.