The refactor the annotations made safe¶
The scariest code in a project is rarely the buggy code. It is the load-bearing code: the 3,000-line file every feature has to touch, the utility cluster two dozen modules import. You leave it alone not because it is good but because changing it might break something you cannot see. The blast radius is the whole point and also the whole problem.
This is the fourth post in a thread, and the other three built a machine. Code comments written for the robot, not the human introduced the codemap: annotations and the risk-vs-complexity score. The test that knows what it is introduced the test taxonomy and its evidence: and kind: marks. Let the library carry the proof used both to delete hand-rolled code AND the tests that pinned it. This post is the payoff beat: a concrete, high-risk decomposition the project actually ran, where those same annotations and that same golden-test discipline are the entire reason a frightening refactor was a controlled, reviewable change instead of a blind rewrite.
Two real targets. A 3,300-line god file (the relevant server module). A diagnostics utility cluster imported by roughly two dozen unrelated files (the private source tree). Both got decomposed. Neither broke anything. The interesting part is why that was true.
The problem: blast radius is a measurable shape¶
"This file is too big" is a feeling. The review spec at the review-rule docs turns it into a metric:
(coupling removed + complexity removed) / (behavior-change risk added)
and into a catalog of measurable smells, so candidates are found by tooling, not vibes. Two of those smells are exactly our targets:
- God file / god class. The spec's own drift-smell catalog names the relevant server module at "roughly 3,300 lines, roughly 86 methods, and roughly 15 message handlers" as the standing example. The candidate band in the threshold table is
>= 1,200lines or>= 8xthe repo median.room.pywas not near the line; it was multiples past it. - High fan-in hub. The same catalog names the private source tree cluster as "imported by roughly 23 files." The fan-in candidate band is
>= 20distinct importing files. Every screen and stage that wanted to log a diagnostic event reached intoScreen.jsx,Control.jsx,screens.js,controls.js,clientEvents.js, andstageRegistry.jsdirectly -- six deep modules, a couple dozen call sites, one tangled surface nobody wanted to move.
The threshold table is the shared contract: it is read by both the blast-radius-candidate-finder and the blast-radius-drift-soft-check, so "what counts as a god file" means the same thing to the finder, the tripwire, and the human reading the ledger.
The targeting: the score already knows where the danger is¶
Here is the part that makes this an AI-enablement post and not a generic "we did a refactor" story.
"Which code is worth decomposing, and which is most dangerous to touch" is not a new question. It is, almost exactly, what the codemap scorer already answers for any proposed change, and what the blast-radius-candidates finder ranks on top of. You can run it:
The concrete command lives in the private project wrapper for this workflow.
The finder does not invent a new ranking. It reads the annotations that are already in the code. The discovery method in the spec is explicit and layered, cheapest first: static metrics (LOC, method counts, an import graph for fan-in), then the codemap ranking, then a test-cost cross-reference. That middle layer is the load-bearing one, and it is grounded in the annotation post:
- The maturity multiplier flags the load-bearing code instead of excusing it.
room.pycarriesmaturity: stable/activeannotations, and the score ranksstableaboveactiveaboveexperimental. That is deliberately backwards from intuition: "it is stable, so it is safe to touch" is the trap. Stable code is load-bearing code, so a careless edit there costs the most -- which is exactly where you most want a golden test before you change a line. - Thin behavior coverage scores the hub hotter. A high-fan-in module with a weak
covers:mark keeps most of its severity in the risk total. That is the right bias: the under-tested hub is both the most tempting to clean up and the most dangerous to clean up without first pinning what it does.
So the finder did not just say "room.py is big." It said: big, load-bearing, high-risk, decompose it -- but pin it first. The annotation system is the targeting system. It told us where to aim before we touched anything.
The safety spine: golden test first, minimum-diff extract, prove equivalence¶
This is the core, and the order is the whole technique. From the spec's decomposition protocol:
1. Write the golden test before moving any code. For the broadcast seam, that meant a characterization test (tests/unit/test_room_broadcast.py) that drives a real, server-shaped fixture through the broadcast path and snapshots the observable behavior -- who receives which role-filtered message, in what order. The input comes from a recorded fixture, not a hand-built literal, so the test pins what the server actually produces. That provenance is the evidence:fixture mark from the test post: the claim that the oracle came from reality, not from an agent's imagination. The test is the equivalence oracle, and it has to be green before the seam moves.
2. Extract the seam minimum-diff, with no compat shim. The broadcast-seam ticket pulled the outbound WebSocket send and broadcast orchestration out of room.py into a new the relevant server module, a RoomBroadcaster class. The run record's impact scoreboard row is the honest accounting:
The example table uses private project paths, so this public version describes the result in prose. | Candidate | LOC delta | Fan-in / fan-out delta | Net new files | | diagnostics facade | 0/+30 | deep fan-in from shell/stage -26; facade fan-in +26; facade fan-out +6 | +2 |
Twenty-six deep edges from shell and stage code collapsed into one facade dependency. The callers now know one name, not six.
3. Run the golden test again. Equal output is the proof. For the broadcast seam, the run record reports pass/pass: the characterization test was green before the extract and green after, on the same fixture. That -- not "it looks cleaner" -- is what licensed the change. A diff would have meant either a latent bug (which becomes its own bug ticket with live-repro evidence) or a smuggled behavior change (which is not a refactor). Equivalence proven, not hoped.
4. Re-stamp the annotations in the same edit. The moved units' codemap: hash gets re-stamped and the taxonomy marks updated in the same commit, because a stale annotation hash fails lint-annotations and a mismatched test mark fails lint-test-marks. The annotation that targeted the refactor is re-stamped by the refactor. The loop closes on itself.
The ratchet: a one-time cleanup decays, a tripwire does not¶
The thing nobody tells you about a big decomposition is that it does not stay done. Files grow back. The next feature adds 200 lines to room.py and you are halfway to a god file again, one innocent commit at a time.
So the spec pairs the periodic finder with an always-on tripwire. blast-radius-drift-soft-check (registered as lint-blast-radius-drift in the soft_checks bucket of the review configuration) runs on every review. When a touched file crosses the warn band in that same shared threshold table -- >= 600 lines or >= 4x median, fan-in >= 10 -- it does not block the merge; it warns, and drafts a remediation ticket. The gain you just bought does not silently erode, because the moment a change pushes a file back over the line, the system files the cleanup against itself.
That is the "combat drift periodically" story made mechanical. The full passes are the campaign: take the top finder candidates, file one refactor ticket per candidate, append each completed row to the impact scoreboard so the ledger becomes a trend line. The soft-check is the guardrail between passes. A one-time cleanup is a snapshot that decays. A finder pass plus a tripwire is a ratchet.
And room.py is the honest test of that claim. Since the broadcast-seam cut, the file did not keep shrinking -- it grew back past the god-file band. the relevant server module reports roughly 4,160 lines today, and the project dev wrapper still ranks it as a God file and a God class far past the candidate band. That is not a failure of the technique; catching exactly this is the tripwire's reason to exist -- and the tripwire fired. lint-blast-radius-drift flagged the regrowth and drafted the blast-radius-drift-src-server-room-py-god-file-* and -god-class-* remediation tickets a human later confirmed into the blast-radius-review backlog. The ratchet caught the file sliding back over the line and filed the cleanup against the project, exactly as advertised.
What is still primitive today¶
I want to be honest about the edges, the same way the earlier posts were.
The finder ranks approximately. It is static AST plus line-pattern heuristics over an import graph and the codemap fields. It surfaces candidates; it does not certify them. A high rank is an invitation to look, not a verdict, and a human still throws out the suggestions that violate an architectural rule.
Equivalence is per-seam, not global. Nothing here proves room.py is correct or that the broadcast path is bug-free. The golden test proves that this one seam's observable behavior was identical before and after this one extraction. That is a smaller claim than a global correctness guarantee, and it is the only one the technique can actually back. Each seam earns its safety from its own oracle, one candidate per ticket, narrow diff.
The decomposition is incremental, and the suite is not magic. room.py did not become small and stay small -- the broadcast seam was one cut of many, and a later pass was meant to keep chipping it down. It did not: the file regrew past the god-file band, which is exactly the drift the soft-check exists to catch, and the ratchet section above shows the tripwire caught it. And the safety machine pins the seam, not the world: the diagnostics decouple actually shipped with an escalation, because while its 775 component tests passed and proved the facade wiring, the broader Playwright run had failures (expected-404 diagnostics specs, a backend connection refusal, a pre-existing add-code path) that the run record verified were unrelated to the facade change. The golden test told us the seam was safe. It could not, and did not pretend to, tell us the entire end-to-end suite was green. Knowing the difference is the discipline.
That smaller claim is the whole point. The annotations tell you which load-bearing hub is worth the risk and which is most dangerous to touch blind. The golden test proves the one cut you make. And the drift soft-check keeps the win from rotting back. None of it is heroics. It is the machine the three earlier posts built, finally pointed at the code everyone was afraid of.
The three halves of that machine: Code comments written for the robot, not the human, which owns the risk score and the maturity multiplier; The test that knows what it is, which owns the test taxonomy and the evidence: mark; and Let the library carry the proof, the sibling technique that shrinks the footprint by deletion where this one shrinks it by decomposition. Same instruments, different cut.
Update: derive, don't stamp
A later post, Derive It, Don't Stamp It, names the routing principle behind this workflow: derive review signals from current artifacts, graphs, and tests rather than hand-stamping a risk label. The canonical rule is now documented in Change Risk Scoring.
Prior-art check pending
The pieces here are individually old: characterization / golden-master testing before a refactor (Feathers, approval-testing tooling), import-graph and god-class metrics (afferent/efferent coupling, the classic fan-in/fan-out literature), and drift tripwires in CI. What I believe is uncommon is joining a provenance-tiered risk/maturity annotation score to the blast-radius candidate ranking so the same metadata both targets the decomposition and -- via the golden-test-first protocol it enforces -- gates it. That combination claim is unverified. Editor: either commission a short prior-art block in the spiral-detection-watchdog house style, or soften "the annotation system is the targeting system" to "I have not seen this exact combination in the wild."
Or: subscribe to the newsletter for more posts on building this stuff.