Playing AI Tennis, Surviving a Google Play Rejection, and Shipping PoquitoTalk v1.5.9

By Dorien Van den Abbeele (@DorienVibecodes) • Final Shipathon Dispatch

The Human Tennis Referee Between Two AIs

Now that I run both Claude and Antigravity side by side, my daily workflow often devolves into playing human tennis.

I sit in the middle with a browser tab on one screen and an IDE terminal on the other, frantically copy-pasting back and forth:

"Claude says your Gradle config is missing a property, Antigravity, what do you say to that?"
"Antigravity says your type definition is broken, Claude, explain yourself."

Half the time I feel like a frantic messenger boy shuttling notes between two brilliant, stubborn nerds who refuse to sit in the same room. Then Claude actually saved my entire project from an immediate store ban today.


1. Waking Up to a Google Play Rejection

Sunday morning started with a rejection email from Google Play review for PoquitoTalk v1.5.5. The reviewer flagged three distinct problems:

  1. The App Crashed on Launch: A cold start triggered an immediate Android system dialog: "PoquitoTalk keeps stopping."
  2. Subscription Policy Violation: On our Annual Pass paywall tile, the monthly breakdown price was displayed larger and bolder than the actual billed amount. Google's billing rules strictly forbid making monthly breakdown figures more prominent than the real commitment charge.
  3. The Mascot Disappeared: Our parrot mascot, Poquito, vanished from the paywall header, leaving a blank white rectangle sitting awkwardly above the headline.

Rather than slapping together a quick patch, we pulled apart every layer from the native Android manifest to the payment listeners.


2. Root Cause Autopsy

The Ghost Mascot

The missing mascot turned out to be an aggressive memory optimization. We had disabled animated WebP support in our Gradle config to save memory. Because the paywall mascot was an animated WebP file, the Android image rendering engine silently dropped every frame and rendered a transparent zero-byte box.

We scrapped the WebP file completely and replaced it with an inline React Native SVG component. The SVG animates at 60fps natively with zero image decoding overhead and cannot fail to render.

The Cold Launch Crash

The crash came from two separate native bridge issues:

We added defensive try/catch wrappers around all notification handlers, plugged in the correct native key, and sandboxed RevenueCat initialization so an offline state never crashes the interface.

Inverting the Price Hierarchy

We rebuilt both paywall screens so that the full renewal price ($39.99/yr) is now the largest, boldest text on the screen. The monthly breakdown sits underneath as secondary context. Clear billing terms sit directly below the button: "7 days free, then $39.99/year. Cancel anytime in Google Play."


3. Where Claude Saved the Project

Before hitting upload on our candidate build, I pasted the revised purchase handlers into Claude Opus for a second opinion. Claude caught four critical issues we had completely missed:

  1. The Accidental $39.99 Fallback: When a user tapped the one-time credits pack ($4.99), the tier switch failed to find a match and silently fell back to the first available package, which was the Annual Pass at $39.99/year! A customer buying $5 of credits would have been enrolled in an annual recurring subscription. That would have flagged our developer account for deceptive billing.
  2. The Travel Pass Policy Conflict: The UI copy said "One-time charge. Does not auto-renew", but the code requested a weekly subscription package. We rewrote the paywall text to match Google Play's exact prepaid terminology.
  3. The Silent Spinner: If a purchase returned an error during sandbox verification, the loading spinner vanished without any feedback. We added explicit user alerts returning the actual store response.
  4. Leaked Git Credentials: A local vault file remained tracked in git despite being in .gitignore. We purged it immediately.

4. First Live Web Dollar

While fixing the mobile app, we also finished connecting our web-to-app purchase funnel for the RevenueCat Shipathon's Funnel Vision Award.

Instead of demoing with sandbox test cards, our live web funnel processed its first real overseas order: a customer in Belgium purchased a credits pack via Stripe Link. Real money, real transaction, real production revenue on the Shipathon leaderboard.

Thanks, Mom.

Whether someone pays on the website or subscribes inside the Android app, their entitlements sync to the same user ID through RevenueCat Stripe Billing.


5. The Final Credits Fix & Shipping v1.5.9

Right after hardening the subscriptions, we spotted one last edge case: when a customer bought credits on Android, the payment cleared, but the code waited for a recurring subscription entitlement instead of depositing credits into the user's wallet.

We patched the purchase handler to deposit credits immediately upon verification, incremented to v1.5.9 (and subsequently v1.5.10), and pushed the signed bundle straight to Google Play production via our automated publishing script.

App store rejections sting in the moment, but treating them like a free security and compliance audit always makes the software better. PoquitoTalk is now faster, more resilient, and fully compliant with Google's billing rules.

Explore the Rest of the Build in Public Journey

Read all ship logs, inspect code commits, and test the live application.

Build in Public Hub Follow on X (@DorienVibecodes)