The main video-generation service had a wizard runner at 15,177 lines. A page component at 7,341. A media-stitching module at 3,473. These weren't accidents of neglect — they were the natural result of a fast-moving pipeline where the cheapest thing to do, every single time, was add one more branch to the file already handling that concern. Splitting them wasn't the hard part. The hard part was making sure the split actually held, and that a file couldn't quietly grow back to god-file size the moment nobody was watching.
A refactor isn't finished when the split lands. It's finished when there's a mechanical guardrail that makes the original problem structurally impossible to reintroduce.
26 commits, zero behavior changes
The modularization PR is explicit about what it is and isn't: a move to a "modular monolith" — one deployable app, but with real module boundaries, a single public surface per module, typed errors, and unified logging. Twenty-six commits, no behavior changes, nothing spent on a paid render or a plan-gate sweep to verify it, because there was nothing to verify against — the claim was structural, not behavioral, and the test suite (3,987 tests passing) was the actual proof.
| File | Before | After |
|---|---|---|
lib/swipe/wizard-runner.ts |
15,177 lines | 84 lines — a barrel over 18 modules |
app/wizard/[jobId]/page.tsx |
7,341 lines | 385 lines — 9 components |
lib/media/stitch.ts |
3,473 lines | 29 lines — a barrel over 12 modules |
lib/swipe/ugc-dynamic.ts |
2,254 lines | 21 lines — a barrel |
The rollback plan is worth noting on its own: a branch and a tag pinned to the exact pre-modularization commit, kept as an explicit safety net rather than trusted to git history alone. When you're about to touch fifteen thousand lines with a script, you want the "undo everything" path to be one command, not an archaeology exercise.
The refactor shipped its own dead code
The honest admission in the very next PR is the most valuable paragraph in the whole cluster: the modularization itself shipped dead code. A new error-handling module went in with twenty-five passing tests and a documentation section describing it as current practice — "routes wrap, withRouteErrors() gives one logged failure path." Measured against the actual codebase: zero call sites in app/api, zero typed errors thrown in production, zero non-test files importing the module.
// what shipped: a correct, tested, documented mechanism
export function withRouteErrors<T>(handler: () => Promise<T>) { /* ... */ }
// what was true everywhere it mattered
// app/api/**/*.ts: 13 routes, 0 try/catch blocks, 0 callers of withRouteErrors
The thirteen routes with no error handling were still thirteen routes with no error handling. The module was built, tested, and documented — and never called. It's the same failure shape that kept surfacing across this pipeline all month: correct code with no consumer reads exactly like a working feature until someone asks specifically whether anything calls it.
A stale-cache bug the split shipped twice
PR #495 split a 2,756-line clip step into fourteen modules — pure refactor, no behavior change, explicitly framed as unblocking a multi-cast feature that couldn't be written while the file was frozen on the size ledger. The technique matters: four phases share one run-context object rather than a parameter list, each phase reading what it needs and writing back only what it changed, keeping the code inside each phase byte-identical to what it was inside the monolith — verified by comparing source-code hashes, not just behavior.
That shared-context pattern has exactly one failure mode: a phase that delegates to another phase and then writes back its own now-stale local copy, silently overwriting whatever the delegated phase had just changed. The split shipped that exact bug twice before it was caught — the same mechanical mistake, independently, in two different phase boundaries, which says more about how easy the mistake is to make than about carelessness in either instance.
Wiring what the split had frozen
Two PRs earlier, four new pure measurement modules had been built for defects a human had found by eye and no number had ever caught: whole-file color saturation reading a healthy 23.53 while individual segments actually ranged 8.1 to 36.2 — a 4.4x spread the aggregate number flattened into invisibility; a vendor silently merging a sub-3-second shot into its neighbor and billing, reporting, and slicing it as if the merge had never happened; a product rendering white in library footage and black in generated scenes with no cross-scene check able to see it; fifteen independent voice-synthesis charges with no scene-to-scene continuity comparison at all.
Those four modules shipped with zero callers outside their own tests. PR #481 wired three of the four into one real entry point in the render pipeline, and the PR's own framing names the pattern by then-established reputation: "the code reads correctly, the mechanism never runs, and every test passes" is this repository's most expensive recurring shape, restated for the third time in its own documentation. A whole-run measurement report type — seven of them — got carved out of a shared job-types file that had hit its own size cap at exactly zero lines of headroom, specifically so the next measurement type would have somewhere to go that didn't require raising the cap.
The cap that makes it stick
The mechanism holding all of this in place is a boundaries test that diffs the working tree against the main branch and fails the build on any net-changed file still sitting on a tracked size ledger — "you touch it, you split it." Fifty-five files were frozen on that ledger: you could not land a one-line fix to a file already over the cap without splitting it as part of that same change. PR #488 enforced the cap at lint time with max-lines as an ESLint error, so a next-build and a plain lint run both fail on an oversized file, not just the dedicated boundary test. PR #489 closed the obvious gap in that: the same cap, ported to the development branch, verified by deliberately planting a 419-line file and confirming both ESLint and the boundary test caught it before removing it again.
The cap's own number had drifted from its own documentation. Two project-level docs both still said "files are capped at 900 lines" after the real threshold had already dropped to 400 — a 2.25x gap between what every agent reading the onboarding docs believed and what the tooling actually enforced. Phase 0 of the whole modularization effort fixed the tooling and the stale documentation before relying on either, and did it a second time, deliberately as a separate cherry-pick rather than a merge, when the same guardrail needed to land on a development branch that had diverged by ten commits in one direction and two in the other — a plain merge would have dragged unrelated feature work across with it.
Five entries, wrong in five different ways
A "verified dead" list of code, carried forward across handoffs as settled fact, turned out to be five-ninths wrong when actually checked against the running code — and not wrong in one repeated way. One function was simply live, called from a file the audit hadn't checked. A second was a working environment-flag read that deleting would have silently disabled. A third and fourth weren't functions at all but job-state fields with real readers and no writer — a UI panel rendering permanently empty, and an empty series getting archived into permanent snapshots as if it were real data. A fifth was genuinely dead but cascaded: comments elsewhere in the codebase documented an unrelated mapping by reference to the dead function's name, meaning the mapping might have no other producer at all.
Five different failure modes under one label of "dead code" is the finding underneath the whole cluster: a claim about what's unused is only as good as the audit that produced it, and a claim inherited from a previous session's handoff is a claim that hasn't been re-verified against the code as it exists today — not five instances of the same mistake, but a reminder that "checked once" and "true now" are different claims.
The pattern: the split is the easy 80%
Every PR in this cluster that split a file cleanly landed with zero behavior changes and a green test suite. Every PR that followed one found something the split itself had broken, forgotten to wire, or left undocumented — a mechanism nobody called, a bug pattern repeated twice, docs describing a cap that no longer matched the code enforcing it. None of that is a case against modularizing a 15,000-line file. It's a case for treating the follow-up pass — the one that checks whether the new pieces actually got wired to each other and to reality — as load-bearing work, not cleanup. The guardrail that makes a god file structurally impossible to reintroduce is worth more than the split itself, because the split is a one-time fix and the guardrail is what stops the same file from growing right back.
Top comments (0)