← Weekend at Claude's / Vol. 6
Debugging  ·  Vol. 6

Two Things Walked Into a Bar at the Same Time. Neither Was Ready.

Diagnosing and fixing a race condition in a React Native / Firebase app.
Weekend at Claude's — all posts
Prologue Vol. 0 Vol. 1 Vol. 2 Vol. 3 Vol. 4 Vol. 5 Vol. 6 Vol. 7 Vol. 8 Vol. 9 Vol. 10 Vol. 11 Vol. 12 Vol. 13 Vol. 14 Vol. 15 Vol. 16 Vol. 17 Vol. 18 Vol. 19 Vol. 20 Vol. 21

Series: Weekend at Claude's — misadventures in building a production app with an AI anyone could mistake for the person who's going to make the whole thing happen

Let me tell you about the closest I've ever come to rage-quitting a project.

About five years ago I was working on an early version of Aphilaty — a prototype, really, built by modifying Firebase's "Friendly Eats" sample app. I hit a race condition. Two things trying to happen at once, neither of them ready for the other, the app breaking in a way that was invisible, intermittent, and completely resistant to diagnosis.

You know what race conditions feel like if you've hit one. The bug is there and then it isn't. It reproduces at the worst times and vanishes when you're watching for it. You stare at the code and the code looks fine, because the code is fine — the problem isn't in the code, it's in the timing, and timing doesn't show up in a code review.

I found it. Eventually. Fixed it. The elation when it finally resolved was one of the best feelings I've had working on software. And then I didn't touch the project for six months.

Not because I was done. Because the experience had taken something out of me. The will to go through another troubleshooting session that complex, that uncertain, that draining — I just didn't have it. The project sat. Aphilaty nearly died not from a bad idea or lack of funding but from a race condition in a Firebase sample app.

This Time

Fast forward to this build, with Claude Code.

At some point during development I noticed this in Claude Code's output:

The old seed tried to work around this with:
await sleep(12000)   // hope that's enough for the trigger to finish

The problem is the timing is indeterminate. If Firebase Functions has a warm
instance, onUserCreated fires in 1–3 seconds and finishes before the 12-second
wait ends. Then the seed's merge correctly layers orgMemberships on top. ✅

But if Functions is cold-starting (no warm instance available — common after
10+ minutes of inactivity), the container spin-up alone can take 10–20 seconds.

I stopped. Read it again.

There was a race condition in the database seed script — a sleep(12000) that assumed Firebase's cold-start would always finish within 12 seconds, when in reality a cold-start can take 10–20 seconds. If the timing was off, the seed would try to layer data on top of a trigger that hadn't finished running. Silent failure. Indeterminate. Exactly the kind of thing that shows up as a mysterious bug three sessions later with no obvious cause.

Claude Code had identified it, explained it, and fixed it. I didn't know it was there. I didn't ask Claude to look for it. It was just — handled, as part of writing the code correctly in the first place.

I didn't know the race condition was there. Claude handled it before it became my problem.

What That Moment Meant

I wanted to cheer. I'm not being dramatic — I genuinely felt something close to relief and gratitude that I wasn't expecting to feel about a coding tool.

Here's what Claude Code understood that I didn't, and that took me a painful debugging session five years ago to learn the hard way: Firebase Cloud Functions have a cold-start latency window of 10–20 seconds when no warm instance is available — common after just 10 minutes of inactivity. A seed script that uses a fixed sleep() to wait for a trigger to finish is making a timing assumption that isn't guaranteed. If the cold-start runs long, the seed tries to write on top of a trigger that hasn't completed. Silent failure. No error. Just wrong data and a mystery to solve later.

Experienced Firebase developers know this. They don't use fixed sleep timers to sequence async operations. Amateur developers — and I was one, five years ago — have to discover it the hard way, usually at the worst possible moment.

Claude Code just knew. Saw the pattern, understood why it was fragile, fixed it correctly.

One thing worth noting for any Firebase developers reading this: in production, this specific problem largely goes away. If your app has meaningful traffic, Firebase keeps warm instances running and cold-starts are rare. And if you need a guarantee, you pay for minimum instances — a known cost, a solved problem. Most production apps never see this issue.

But in development and testing — especially solo development where you're the only person hitting the backend, where instances go cold between your evening sessions, where you're not going to pay for warm instances on an app that isn't live yet — this is a genuine killer. The bug is real. The timing is indeterminate. And when it manifests, it looks like your code is wrong, not your infrastructure assumptions.

That's exactly the environment I was working in. And Claude handled it without me ever knowing it was there to be handled.

This is the category of value that's hard to quantify but impossible to overstate. It's not the hours saved on a specific bug. It's the entire class of problem — the known pitfall that experienced developers avoid effortlessly because they've been burned before — that you never have to fall into in the first place. Claude carries five years of Firebase developer experience, or a hundred years, or whatever the right metaphor is. It knows where the holes are.

Human-to-Claude calibration setting #10: Claude knows pitfalls you don't. Ask it what they are.

We may find other issues. There may be limitations ahead we haven't hit yet. But not having to relive the experience I had five years ago — the diagnostic spiral, the intermittent reproduction, the six months of lost momentum — that's not a minor efficiency gain. That's the difference between a project that ships and one that sits in a notebook.

It sat for five years before. It's not sitting anymore.

Aphilaty is a privacy-first community coordination app. aphilaty.com

← Previous
Everyone Is Standing Up and Moving Under Their Own Power
Next →
He Seems Fine. He's Always Seemed Fine.