01
Arguing with Apple instead of paying them
Apple rejected Poppycal twice. The second rejection cited Guideline 3.1.1
and demanded In-App Purchase for subscriptions, which costs 15 to 30
percent of every subscription forever.
Apple's own rejection message offered a way out: the US storefront link-out
allowance, letting the app link to an external purchase page. That looked
like the easy path.
It was a trap. Adding a purchase link would have disqualified the app from
Guideline 3.1.3(f), the free stand-alone apps exemption, which requires an
app to have no purchase calls to action at all. It would still have failed
3.1.3(b), which demands IAP. Taking the path Apple suggested meant failing
both rules instead of one.
So I argued the 3.1.3(f) exemption directly, and added neither IAP nor a
link.
Approved two days later. The app ships with no purchase links anywhere,
which is precisely what makes it approvable.
02
A bug that was actually an architecture problem
Kid Mode is a PIN-locked kiosk that limits what a child can see and do. It
shipped with a defect: a kid could reorder the chore board. That sounds
small. It broke the entire promise of the feature.
The cause was not a coding mistake. The rule defining "is this session
locked" had been written by hand into three separate iOS files instead of
imported from the one shared definition. Over time the copies drifted, and
iOS quietly lost a gate that the web app still had.
Fixing the bug was not the fix. I deleted the redundant concept so Kid Mode
became one flow instead of two, then built a CI check that fails the build
when web and mobile grow a new copy of the same logic.
The honest part: that gate cannot catch omissions. Three of the four parity
breaks in this incident were iOS missing something web had.
Absence has no duplicate to detect. "Does iOS actually do everything web
does here" is still a human question, and I still have to ask it.
03
Two weeks of shipping nothing
In May the web app was live and working, and I decided to build iOS.
The fast move is to start the iOS app. Instead I spent about two weeks
moving the entire codebase into a monorepo with a shared business logic
package first. No features shipped in that stretch.
The iOS app was scaffolded on May 13 and reached parity with a large,
mature web product within weeks. The two apps share zero rendering code and
one hundred percent of their rules.
It still was not enough on its own, which is why decision 02 exists.
04
Saying no to the most requested feature
Users asked for family group chat. Competitors ship it.
I researched it and said no. What families wanted was not another place to
send messages. They wanted the context that belongs to an event to live on
the event.
So I shipped comments on events instead. It is one of the smallest features
in the app and it covers the job people were hiring group chat to do.