A rusted padlock with a brass shackle fastened through the bars of a server rack gate, with dismantled fence panels and drifting vapor visible in the blurred background.

My pipeline stacked pull requests one at a time — build a slice, open a PR, build the next slice on top of it, open another. Three things fed that design. My old laptop couldn't hold more than one full checkout of a large codebase at once, so I only ever had one working tree to build in. The database migrations in the codebase couldn't be built out of sequence without conflicting, so slices had to land in order regardless. And underneath both of those sat a goal I still believe in: every PR should be shippable on its own — reviewable and mergeable independently, not a checkpoint in something unfinished. Two of the three were hard constraints. The third was a belief about what good work looks like. I built the pipeline to satisfy all three the same way, one final slice at a time, and stopped being able to tell which parts of that shape were load-bearing and which were just habit.

I replaced that machine months ago. Sometime after that — I don't have as clean a date for this one — the migration constraint went away too. Two of the three reasons were gone and I never noticed, because I never went looking for them. I'd reviewed the stacking design plenty — paused on it, reflected on it, run it through adversarial AI review more than once. None of that surfaced the problem, because every one of those reviews started from the same premise I already held: that building in small, immediately-shippable increments was simply how the work worked. You don't question a premise you're not looking at.

The conversation that found it

I was on a work trip, describing the pipeline to a coworker who hadn't heard about it before. Nothing pointed. No review, no critique, no agenda — just talking about what I'd been building. And somewhere in there came the question, almost in passing: why does it build things piece by piece instead of building the whole thing and figuring out how to present it after?

I started answering with the reason I'd always given — parallel checkouts, memory, the laptop — and heard myself say it out loud for the first time in a year. The laptop I was describing wasn't the laptop in my bag. I'd been on an M5 Max for months. I could open a dozen worktrees of that codebase without it breaking a sweat.

That's the whole story, mechanically. A throwaway question met an offhand answer, and the answer didn't survive being said out loud to someone who didn't already believe it.

Why the design was right, and then wasn't

I want to be fair to the old design, because it wasn't a mistake when I built it. Stacking PRs as you go is a reasonable way to work when parallel checkouts are expensive: you finish a piece, you ship it, you start the next piece on solid ground, and you never have more than one tree open. Real constraint, real answer to it. The constraint just stopped being true, and the design kept running on the belief anyway.

But set the hardware and the migrations aside for a second, because the third reason — shippable-ready PRs — was fraying on its own terms by the time the coworker asked the question. Building split-up from the beginning means committing to your cut points before you've seen the whole thing. In practice that meant stacks running eight, nine, ten PRs deep, with several of them out for review at once. And the tenth PR was rarely new work. It was a fix to something in PR two, spotted while reviewing PR seven, that couldn't be folded back into PR two because PR two was already out for review and everything above it was built on its exact shape. So the fix became its own PR at the top of the stack — a patch for a problem two layers down, landing in a different order than the bug it fixed. Multiply that by a few review cycles running in parallel — some PRs approved, some still in flight, some rebasing on a base that had just changed under them — and the stack stopped behaving like eight independent, reviewable slices. It behaved like one large, brittle change wearing eight PR numbers, where touching any layer put validation on every layer above it at risk.

That's a different failure than “the constraint disappeared.” The shippable-ready goal never went away, and I still hold it. What broke was assuming the only way to reach it was deciding the slices up front and building them in that order, PR by PR, before I'd ever seen the thing whole.

The part that bothers me isn't only that two of the three reasons disappeared. It's that nothing in my process was built to notice — not the expired constraints, and not the fact that the goal I still held was being pursued through a shape that no longer served it. I reviewed that design under real scrutiny — mine and an agent's — and every review inherited the assumptions I'd set up, because I was the one who set them up. An agent I prompt with my own framing will interrogate the framing I gave it. It will not interrogate the framing I didn't think to give it. Self-review, however careful, can't get past its own premises. It can only get more rigorous inside them.

What changed

The redesign took about a day to plan and ship once the premise was gone — and it was a day, not a quarter, because of how the pipeline is built in the first place. It runs entirely as swamp models and workflows: a set of independent model methods — plan, implement, test, review, verify, assemble a PR stack, finalize, submit, teardown — wired together by a declarative workflow that just says which step feeds which. None of those methods needed to change. What changed was the wiring: prototype-first mode is a new branch through the same workflow, calling the same implement/test/review/verify methods in a different order and adding one gate before the PR-assembly step instead of after it. Redesigning the shape of the pipeline meant rewiring a DAG, not rewriting the components sitting on it.

Planning came first, as its own pass, separate from writing any code: eleven dependency-ordered slices, checked by five rounds of adversarial review before implementation started, until a review cycle came back with nothing left to flag. Implementation went slice by slice through the night — subagents doing the work, the main session orchestrating — reusing whatever already existed instead of rebuilding it: the same artifact-config pattern, the same stack-plan schema, the same PR-assembling fan-out. The two modes end up sharing one finalization, submit, and teardown step, referenced from both branches of the workflow rather than duplicated. The one genuinely new component is a tree-identity gate: the commits materialized into the PR stack get their combined tree hashed and checked against the approved prototype's tree, and a mismatch is a hard failure, not a warning. That's what turns "cutting up a proven thing" into something you can assert instead of something you're trusting.

The new default, for anything spanning multiple PRs, builds the entire thing on one integrated branch first — full test suite, browser checks, QA, a multi-role review panel with an independent verifier that patches and re-verifies until it's clean. A human reviews that whole, working prototype and gives feedback, and the loop repeats — revise, reverify, review again — for as many passes as it takes. Only once the prototype is approved as it stands does an agent propose how to partition the proven diff into a stack of PRs, a human approves the partition, and the split is materialized deterministically: each PR's tree checked to be identical to its slice of the thing already proven to work. The old build-it-split-up mode still exists. It's opt-in now instead of the default.

The point of the new shape is that you stop arguing about the boundaries of code that doesn't work yet. Under the old design, every PR in a stack was a bet that the slice had been cut in a sane place — a bet placed before anyone knew whether the whole thing held together. Under the new one you review one working thing, and cutting it up afterward is a mechanical operation on a proven artifact instead of a sequence of guesses about where the seams belong. If the prototype gets rejected, the feedback goes back in and the whole gauntlet reruns on a fresh build. Nobody patches a rejected prototype in place and hopes.

It needed the faster machine to even attempt — parallel worktrees of a big repo, a clean base clone kept in sync so spinning up a new one is cheap. Which is its own small irony: the upgrade that quietly erased the old constraint is the same upgrade that made the new design possible. I just hadn't connected the two until someone asked.

None of this guarantees smaller output. The result might still be a stack seven or eight PRs deep, same as before. But a stack cut from a thing that already works is a different object than a stack that was the thing, each layer a bet on a shape nobody had earned yet — cutting it up is now a mechanical step after the fact, not the method the work was built by. I'm also loosening a boundary I used to hold hard: how many lines a slice was allowed to be. I'm leaning closer to vertical slices in the Shape Up sense — each piece a complete, working sliver of the feature — rather than a size-bounded chunk of one. I don't know yet what that does to review quality or to how the eventual stacks come out. That's an open question I'm running the new pipeline to answer, not one I've answered by writing this.

The honest caveat, since overselling this would defeat the point of writing it down: all of it is proven at the fixture and local level so far. The first live run against real work hasn't happened yet. And the harness I wrote to test the new mode caught eight defects that static validation could never have seen — CEL expressions that quietly assumed a homogeneous map, a couple of scope errors, an undeclared resource spec, evidence gates no real run could ever satisfy, a worktree branch conflict — which is its own reminder that a design can look sound right up until you actually run it.

The part that isn't about pipelines

This happens outside software, and probably more often than I catch. A decision made for a reason that quietly expired. A boundary set for a season of life that ended. A routine shaped around a limitation you no longer have. A plan you're still executing for a because that stopped being true two years ago. Sometimes the because never stopped being true at all — it's the shape wrapped around it that went stale, a good goal pursued through a method built for constraints that no longer apply. You can review those alone as long as you like and never find the seam, because your review starts where your decision started.

What finds it is usually a person, saying something ordinary, who never held your assumption in the first place. Not a critic. Not someone trying to catch you out. Just someone in the room, asking the question you quit asking yourself a long time ago.