ANTIGRAVITY LABJP
Articles/App Development
App Development/2026-08-31Advanced

Why I took the show-or-not decision away from every dialog

A paywall prompt, a review request and a rewarded-ad confirmation landed on the same frame. Here is how I moved the show-or-not decision out of each dialog into a single gate, how I rewrote the agent instructions as invariants, and how a CI check keeps it that way.

antigravity449android30agent18ui-design3

Premium Article

About a second after launch, the paywall prompt opened. A review request landed on top of it, and a rewarded-video confirmation was queued behind both.

It never reproduced on my test devices. It happened only on devices that had reached the category screen in a previous session, been closed there, and reopened the next day.

This was a real path through the Android wallpaper app I maintain as an indie developer.

Each dialog was correct on its own

All three owned their display conditions locally.

DialogCondition it ownedCorrect in isolation?
Paywall promptLaunch count above threshold, not ad-freeYes
Review requestDays-used above threshold, not yet ratedYes
Rewarded-video confirmationAd inventory loaded, not ad-freeYes

Nothing in that table is wrong. The problem is that every condition answers only one question: "am I allowed to show?" Nowhere in the codebase did anything ask "is someone else already showing?"

Ask an agent to add one dialog at a time and you get exactly this shape, because the spec you hand over is the spec for that dialog. The agent wrote correct code for the scope it was given. What was missing was the cross-cutting condition I never wrote down.

I had already centralised the ad-free value itself, which I covered in where the source of truth for billing state lives. The value was centralised; the decision was not.

Trap 1: conditions do not add up to an ordering

My first instinct was to add "and nobody else is showing" to each of the three conditions.

That does not scale. Three dialogs mean six references, four mean twelve, and every addition requires opening the existing files to extend their conditions. Ask an agent to add one dialog and only that file changes — the other three quietly go stale.

A design that keeps conditions distributed breaks a little on every addition. The failure mode is "occasionally overlaps" rather than "never appears", which is exactly the kind of thing tests do not catch.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
You will be able to look at your own dialog code and decide whether the display rules should stay local or move into one gate
You will be able to catch overlapping-modal defects with a CI check instead of waiting for them to reproduce on a user's device
You will be able to hand UI work to an agent as invariants rather than as isolated features, so the next dialog does not reopen the same hole
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Antigravity Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $15 for lifetime access
View Membership →

Related Articles

App Dev2026-06-21
The Back Button Showed an Interstitial Sometimes, Not Others — Rewriting Nested ifs Into a List of Independent Guards
Interstitial display on back press was unstable because nested if statements hid the priority between conditions. Here is how I split it into reason-returning guards and generated tests from a decision table.
App Dev2026-07-18
After Compose-First: Choosing Which View Screens to Migrate, Ranked by Churn Instead of Count
Google has declared Android development Compose-first. Here is how I rank View-based screens for migration using git history rather than screen counts, with the scoring script I actually ran and the three places partial migration quietly duplicates state.
App Dev2026-07-09
Deciding When to Stop a Staged Rollout, Before You Have To — Agents Watch, I Halt
Field notes on building a Google Play staged-rollout watcher with Antigravity. Crash rate as a ratio to baseline, delayed ANR evaluation, and an explicit insufficient_data verdict — with the halt action kept in human hands.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →