The Friday Deploy: Your PR Shouldn't Make Your Stomach Hurt

Garrett and I recorded episode two of The Friday Deploy. We started with personalized interfaces and ended with a basketball app and me casually mentioning that I’d rewritten a chunk of Flare to run on Cloudflare. As one does.

But the thing I keep coming back to is the pull request that makes your stomach hurt.

I’ve made plenty of those lately. Ask AI to build something. Have another model review it. Fix the findings. Review it again. Find more things. Fix those. Pretty soon the little change you wanted is 3,000 lines and you don’t want to merge any of it.

For a while, my response was to keep going. Surely one more review would make me feel better.

Sometimes the better answer is to throw it away and ask for something smaller.

Put an End on the Review

I wrote up the Nunebot process already, so I won’t repeat the whole thing here. The detail that helped most: after the first review, review the fixes, not the entire change again. Bound the loop. If it’s still a mess, stop.

Garrett came at the same problem from the UI side. His Workbench process runs deterministic checks, gets other models to look for holes, and tracks findings against the state of the code where they were found. Each finding needs a decision. Fix it, dismiss it, or bring it to him. Don’t just keep rediscovering the same thing forever.

We took different paths, but ended up wanting the same thing: a small change with enough proof that merging it feels obvious.

Quiet Support Isn’t Proof

This came up while we were talking about moving Fireside’s file storage to Cloudflare R2.

Support was quiet. Which is great! Except when you’re changing something important and start wondering if it’s quiet because everything works or because nobody has tried the thing yet.

So I asked the agent to watch more than errors. Successful MP3 uploads. Images. Transcripts. Cloudflare errors. Honeybadger. Support requests. Tell me what’s actually happening while we roll this out.

It started with short check-ins and backed off as we gained confidence. We weren’t just waiting for somebody to tell us we’d broken their podcast.

That distinction feels important. No errors is one signal. People successfully doing the thing you changed is another.

Two Flags, Two Decisions

We separated R2 reads from R2 writes.

First, read from R2 while the old storage was still receiving writes and replicating them over. Get comfortable with that. Then switch writes.

The flags gave us smaller decisions instead of one giant moment where everything had to change at once. They also made us be specific about rollback. Switching writes back while leaving R2 reads on was one thing. Switching reads back after new files had landed only in R2 would mean copying those files back first.

A flag is useful. Knowing what the flag can safely undo is useful too.

One version of this work wanted another database column to track the switch. I wasn’t convinced we needed it. Starting over with a simpler approach helped get the implementation back to something I felt good about.

More of the Fun Stuff

My favorite part of the conversation was Garrett talking about the iOS app he’s building to help analyze basketball shooting mechanics.

He coaches. He likes basketball, information design, and math. Now he can put those things together without first taking a detour through learning an entirely new platform. He’s going to the gym, recording shots, testing with other people, and iterating.

He still runs reviews and tests. He’s still making decisions. He’s just spending more of his time on the parts he enjoys.

That’s the bit I’m excited about too. Smaller changes. Better evidence. Less time wrestling with a PR I don’t want to merge.

Listen to episode two, or start with episode one. You can subscribe on Apple Podcasts, Spotify, or RSS.

Thanks for reading! I’m John — I build software and software businesses, and I write here about how it goes.