← Weekend at Claude's / Vol. 10
Build  ·  Vol. 10

The Body Was Fine. We Were Just Looking at Old Photos.

Gradle's stale cache problem, gradlew clean, and the build timestamp that catches it early.
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

Here's what eight hours of debugging taught me: Gradle will tell you files are up-to-date when they are not.

I was chasing a bug in Aphilaty's Android build where behavior in the mobile app didn't match the same code running in the PWA. The code was right — I could verify that. The PWA worked. The logic was correct. But Android was wrong in a consistent, reproducible way that made no sense.

Claude Code analyzed everything. The logic was sound. The data flow was correct. The Firebase calls were fine. All of it looked exactly right, because all of it was exactly right.

What neither of us could see was that Gradle had cached the compiled output from an earlier build and wasn't recompiling. When it reported the JavaScript files as "up-to-date," it meant up-to-date compared to its cached state — not compared to what was actually on disk. Old code was being compiled. New code was sitting there ignored. And Gradle was reporting success the entire time, with complete sincerity, like someone confidently describing a person who is no longer available to be described.

We were looking at old photos and wondering why the subject didn't respond to our questions.

The fix: gradlew clean assembleRelease instead of gradlew assembleRelease. One word. Forces Gradle to discard the cache and recompile from scratch. Slower build. Honest build.

Eight hours. One word.

I've added it to CLAUDE.md as a hard rule — always clean for release builds — and to the diagnostic protocol: if Android behavior doesn't match expected behavior and the code looks correct, run a clean build before doing anything else.

But clean is the cure. Here's the early warning system.

After the fact, I suggested to Claude Code that we append a build version to every error message — a cheap way to confirm at a glance that you're running the code you think you're running. Claude Code agreed with the concept but improved the implementation: instead of decorating individual error messages, it generated a buildinfo.ts file with a build timestamp compiled into the app at build time.

// buildinfo.ts — generated at build time, never hand-edited
export const BUILD_TIMESTAMP = "2026-06-14T18:32:00Z";
export const BUILD_ID = "aphilaty-1.0.0-20260614";

The timestamp surfaces in logs and the debug UI. When something behaves wrong, you check it first. If it doesn't match when you built, you're not running what you think — and you know immediately, before the eight hours start.

My suggestion was right in spirit. Claude Code's version was better in practice: lower overhead, one source of truth, no risk of forgetting to update it across a dozen error paths.

gradlew clean stops the lie from happening. The build timestamp tells you the moment it would have.

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

← Previous
We've Been Going in Circles. What if We Just... Went Somewhere Else?
Next →
Three Ways Claude Can Remember Your Project — And Why I Use Only One