← All writing

Week 7: The Crash Claude Couldn't Fix

Week 7 of Shipping Every Week — my app crashed all week and the agent loop couldn't close it on its own. A story about the exact point where vibe coding runs out, and what has to take over.

Week 7 of Shipping Every Week: my app was crashing all week. Claude couldn't fix it.

That sentence is the whole week, and it's also the most useful thing I've learned in seven weeks of building, so let me actually walk through it.

The loop that wasn't working

Sentry went in on Monday — crash reporting, so I'd at least see the wreckage. After that I ran the loop you're supposed to run when an AI agent is your primary way of writing code: feed Claude the crash report, get a hypothesis, add telemetry around the suspect code, reproduce on a real device, paste the new breadcrumbs back, repeat.

It's a good loop. It's closed most of my bugs. This time it didn't. A few cycles in, the hypotheses were still drifting — each one plausible, none of them right — and the app was still dying on launch. The breadcrumbs would point somewhere, I'd instrument it, and the next crash would point somewhere slightly different. The loop was spinning without converging.

I'd coasted for about a month and a half just letting Claude ship features, and it had been genuinely great. This week was the bill coming due for that comfort. The agent loop had hit a wall it couldn't get over by iterating, and I had to slow down and reason about the system harder than I'd let myself in weeks.

Narrowing it down

Here's what I had that the breadcrumbs didn't: a pattern. The crash was always on launch, and always on the home tab. That's not a stack trace, but it's a constraint, and constraints are what you use when telemetry fails you. Whatever was happening, it happened in the code that runs when that one screen opens.

So I changed the question I was asking Claude. Instead of "here's the latest crash, what's wrong," I asked it to walk me through every piece of logic that executes when the home tab mounts, and list every candidate for an out-of-memory crash, with reasoning for each. Not "fix it" — "enumerate the suspects in this specific room."

The cause: the home tab shows a row of your recent workout videos. The code was eagerly loading every video the user had ever recorded the moment the app opened, and re-generating each thumbnail from scratch, at full size, on launch. On a fresh test account this was invisible. On any account with real training history, it allocated enough memory in the first second that iOS killed the app before a single thumbnail ever rendered. The crash scaled with how much you'd used the app — which is exactly why it hit my most engaged users and never showed up in a quick test.

The fix: only load the handful of videos about to scroll into view rather than all of them, by letting the list virtualize — render a few rows, recycle the rest. Only regenerate a thumbnail if one actually fails to load, and cache the result so it's generated once, not every cold start. I also added a small negative cache so a corrupt clip can't send the app into a retry loop trying to thumbnail something that will never succeed. Then — and this is the part that mattered most — I went looking for the same shape of bug everywhere else: anywhere the app did unbounded work proportional to your history at a moment it should've been doing a fixed, small amount. I bounded those too, before they became next month's crash.

The lesson

Powr is entirely vibe coded. I lean on that and I'd defend it. But vibe coding only gets you so far. Eventually something breaks in a way the agent loop can't close on its own — not because the model isn't smart, but because closing it requires a hypothesis the breadcrumbs can't supply. That's when engineering instinct has to step in: what's suspicious, where to look, how to systematically reduce the unknowns. The gut feeling you build from years of debugging is still the differentiator, maybe more than ever.

And here's the part that surprised me: stepping in didn't mean reading the code myself. I didn't. It meant pointing Claude at the right constraints — "it's always launch, always the home tab, it's memory, enumerate the suspects in that path" — the constraints the breadcrumbs couldn't carry. The skill that mattered wasn't writing the fix. It was knowing which question would make the fix findable, and recognizing that the loop had stopped converging and needed a human to re-aim it.

Vibe coding doesn't remove the engineer. It moves the engineer up a level — from writing the lines to framing the problem. The weeks where that's invisible are the easy weeks. This wasn't one of them.

What did you ship this week?

Want a site that does this for your business?

I build warm, fast, mobile-first sites for local businesses and solo pros — clear price, quick turnaround. A free, no-pressure intro call is the place to start.