App Review is a boundary too
Apple rejected my app twice in three weeks. Neither rejection was a crash in my code. Both were my assumptions meeting the platform's rules at the edge, which is the same place every other bug in this series has lived.
App Review is a boundary. What crosses it is not your code. It is your assumptions about devices, rules and users you have not met. This is the record of what crossed, what came back, and what I do differently now.
The first rejection: a label, not a line of code
The app is a reader and meeting recorder with a community feature and a small learning game. The first submission came back with one outstanding issue, under guideline 5.1.2(i), which covers privacy labels and tracking. Sign in with Apple and account deletion, the two things I had worried about, were accepted.
App Store Connect said the app collected "Other User Content" and "Gameplay Content" for tracking. It does not. There is no advertising SDK, no device advertising identifier, no data-broker sharing. There is first-party analytics: which screens are opened, sent to my own API.
The instinct, when Apple says "tracking", is to add the App Tracking Transparency prompt and move on. That would have been the wrong fix. Apple defines tracking narrowly: linking your app's data with third-party data for advertising, or sharing it with a broker. First-party analytics is not that.
So the fix was a form, not code. Open the App Privacy questionnaire, and for every declared data type answer the question "is this data used for tracking?" with the truth, which is no. Publish the label. Resubmit.
The lesson: read the definition before you reach for the mitigation. The boundary asked a question in its own vocabulary. I nearly answered in mine.
The second rejection: an iPad I do not own
The next build was reviewed on an iPad Air 11-inch. I developed on an iPhone and a Mac. The reviewer found five things in an hour that I had not found in weeks, because they were all on the other side of a device boundary I had never crossed.
Guideline 2.1(a), the splash hang. On iPad the app appeared to freeze on its launch screen. The native splash and my own overlay were stacking, and on that device the hand-off took long enough to look like a hang. Fix: remove the native splash on the first frame and shorten the overlay to well under a second. On my iPhone it had never been visible. On the reviewer's iPad it was the first thing they saw.
Guideline 2.1(a), the share sheet. The invite button in the learning game did nothing on iPad. iPhone presents a share sheet from the bottom; iPad presents it as a popover, and a popover needs an anchor. Without one, iPadOS declines to show it at all. Fix: give every share sheet a source rectangle. One parameter, missing on every call.
Guideline 4, the sign-in. Sign-in with a third-party provider opened the system browser and left the app. Apple wants authentication to stay inside the app experience. Fix: an in-app browser view for the OAuth flow. A one-line launch mode change.
Guideline 1.2, user-generated content. The community feature let people post. It did not let anyone report a post or block a user, and there was no acceptance of terms at sign-up. For anything with user content, Apple treats those as hard requirements, not polish. Fix: a terms gate on authentication, report and block on every post, a profanity filter, and the database migration to back it all. This was the only finding that was a real feature, and the only one I should have known in advance.
There was a fifth question, about how an in-app currency is purchased. It touches Apple's payment rules, and I will write about it once the answer has settled.
What the two rejections have in common
The label rejection was about vocabulary. The device rejection was about a device. In both cases my app was fine in the environment I had built for it, and wrong in the environment it was actually reviewed in.
That is the boundary pattern exactly. Inside the line, the code works. At the line, something I did not control, a definition or a device, applied its own rules and the assumptions I had never written down failed.
I now keep a checklist that I read before I press submit. It has the five findings above as lines. It also has two questions I did not used to ask:
Which devices will the reviewer plausibly use, and have I run this build on each of them, including the ones I do not own? Simulators count. Borrowed devices count. Not testing does not count.
For every question App Store Connect asks in its own words, have I read the definition, or have I answered the question I assumed it was asking?
The general form
Every platform you ship through is a boundary of this kind. An app store, a browser extension store, a package registry, a payment processor's compliance review, a customer's security questionnaire. Each has a vocabulary. Each will test your work in an environment you did not build it in.
The move is the same as for any other boundary. Write down the assumptions before you cross. Find the environment on the other side and run in it. When a question comes back, answer it in the asker's vocabulary, not yours.
Both fixes shipped in the next build. The checklist is longer than the app's changelog for that week, and it should be.
This is sheet 028 in a drawing set on software, security and AI. The first essay covered the five boundaries inside a system. This one is about the boundary around it. The last essay in the set, next Thursday, is about a tool I built whose most important feature is that it refuses to act.