Monday, 7 September 2026

The refactor run halfway

The last post set up a ladder. Four runs, each adding exactly one thing. Plain spec, the baseline erosion. Plain English, good advice with no number. The refactor run, a tool that catches the sore spot and nudges it, still no number shown. The formula, the full measurable target, already run and already gamed.

This is an update on the third rung. The refactor run is about halfway through, and it is behaving. So here is what I can already see, and what I still cannot.

What the refactor run is

It is the tool lever on its own. The agent gets the plain spec and nothing else. No formula, no cost, no mention of the experiment. It just implements the change.

Behind it sits ImpactGate. On every change it scores the structural impact with the same cost formula from the earlier posts. When a change scores above the line, the tool does not lecture the agent. It runs a refactor step on the clean code, names the heavy classes, and breaks them into smaller cohesive ones. Then the change is attempted again on the cleaner code.

The key difference from the formula run is the wall between the tool and the agent. The agent never sees the number. There is nothing for it to optimise, so there is nothing for it to game. The number only ever points the tool at where to cut.

How far it has run

Two codebases, Spring and OfficeFloor, the same two as always. Ten independent chains each, sixty checkpoints a chain. Six chains are done on each side, and the seventh is running. So a little over half the run is in.

It is clean so far. Every finished chain ran all sixty checkpoints. No build ever broke. No chain stopped early. The gate is advisory here, so it records and continues rather than aborting, which is why a flag never derails a chain.

The one thing I can already see

When the tool fires, it works.

The refactor has triggered on about a hundred and twenty checkpoints so far. Every one of them was a change the formula scored near the top of the scale before the cut. After the refactor, the same change lands on cleaner code and its impact score falls by about two thirds. The average impact on those changes drops from roughly nineteen thousand to roughly six thousand. It falls in about nine of every ten cases. Spring trips the gate far more often than OfficeFloor, which is exactly the concentrated-versus-cohesive split the whole series keeps finding.

So the mechanism is honest. The tool catches the change that would concentrate complexity, and the refactor moves that complexity somewhere less painful before the change lands. No number was ever shown to the thing writing the code.

The curve it has to bend

A cheaper change on the day is not the point of the experiment. The point is the shape of the standing code at the end. So the number that matters is the heaviest class in the app, measured by its weighted complexity, and how fast that grows checkpoint after checkpoint. That is a god class forming in slow motion. It is measured on the final code, the same way for every rung, on a number the agent could never aim at.

On the plain spec baseline the biggest class keeps growing. Spring's heaviest class gains about one and eight tenths of weighted complexity every checkpoint. OfficeFloor's gains about seven tenths. Spring concentrates roughly two and a half times faster. That gap is the erosion the tool is meant to fight.

An early read of the slope

I did not want to quote a number off half a run. But half a run with nothing in it says very little, so here is the honest interim, with the caveats loud. Six of the ten chains are in on each side. Measured the same way as the baseline, the growth per checkpoint so far is:

  • OfficeFloor. Baseline about seven tenths. Refactor run about six and a half tenths. Essentially unchanged.
  • Spring. Baseline about one and eight tenths. Refactor run about one and a half. Lower, but the chains are all over the place.

OfficeFloor is the easy read. It was already cohesive, so the tool rarely fires and there is little to bend. Its slope barely moves, which is what you would expect when the problem was never there.

Spring is the interesting one, and not in the clean way I hoped. The average slope drops by about a fifth. But the spread is wide. Four of the six Spring chains stayed reasonably flat. Two of them still ran away, ending with a single class carrying about a hundred and sixty weighted complexity, a full god class, gate and refactor notwithstanding.

So the per-change cut is real, and it is not reliably reaching the end state. The tool lowers the impact of the change in front of it. The standing god class on the arm that has the problem still grows at roughly four fifths of the baseline rate, and unevenly. The complexity the tool pushed off today's change is landing on some later one.

Treat those numbers as a direction, not a verdict. They are six chains, not ten. The final figure uses a more careful slope with confidence bands, and Spring's variance is exactly the kind that moves once the last chains land. The sign looks right. The size is not settled.

Where this leaves the ladder

The formula run proved a measurable target gets gamed. This run is the opposite bet. Keep the number away from the agent, and let a tool spend it instead.

Halfway in, the tool does its job on every change it touches, and the standing curve bends only part way. That is the Tesler shape again. The complexity did not leave. It moved. A gate on each change slows the concentration on the arm that concentrates, but it has not stopped it, and twice in six tries it barely dented it.

A few more days and both sides finish. Then the real measurement, on the standing code.

No comments:

Post a Comment