The Best Paragraph in My App Review Notes Was the First One I Deleted

Wait 5 sec.

Fingertips went on sale on 5 September on iPhone and iPad, and on 6 September on Mac. Here is the whole calendar, because the shape of it is the point:12 Aug, 20:36 UTCSubmitted, both platforms, with review notes written to pre-empt two guidelines20 AugmacOS rejected: 2.3.7, 2.1(b), 2.4.527 AugAppeal on 2.4.5 upheld against me. Feature deleted2 SepiOS rejected under 2.1(b), 21 days after first submission. Resubmitted the same evening5 SepiOS approved, 3 days later. macOS resubmitted, 11:11 UTC, in review within 7 hours6 SepmacOS approved, one day after submission10 Sep1.2.0 submitted, both platforms - and the notes rewritten, see the postscriptTwenty-four days from first submission to first approval. One day for the last one.What I wrote before anyone looked at itI expected two guidelines to be a problem, so I wrote notes about both before submitting.The first was 2.4.5. The Mac app used to paste for you: you pressed a hotkey, typed a few letters, pressed Return, and the snippet appeared in whatever you were writing in, because the app posted a synthetic Command-V with CGEvent.post. macOS gates that behind a permission it files under Accessibility.The second was 3.1.1, the trial. Fourteen days free, then a one-time unlock, no subscription.Both notes were detailed and both were, I thought, obviously correct. macOS came back rejected on three guidelines, including 2.4.5.I appealed. On 27 August the decision was upheld, and I deleted the feature the Mac app had been built around.Lesson one, and it cost me a week: a review note cannot argue you into a permission. 2.4.5(iv) is about what the permission is used for, not about how carefully you explain yourself. There was no version of that paragraph that would have worked, and writing a better one was never the answer.The paragraph that caused a rejectionThis is the part I would most want another developer to see, because it is the opposite of what people worry about when they write review notes.On 2 September, 21 days after I first submitted and 13 days into the queue for the build that was actually rejected, the iOS build came back under 2.1(b): "we were unable to purchase IAPs". Reviewed on an iPhone 17 Pro Max.Nothing was broken. The Paid Applications Agreement was active, a real sandbox purchase of that exact product had completed on 12 August, the offering and price schedule were correct, and the in-app purchase was attached to the submission. The purchase worked.The buy button was in a sidebar that the iPhone layout never renders. One branch, if isSideWindow { palette } else { splitLibrary }, and an iPhone is always compact, so the only route to paying was an unlabelled overflow menu.And my review note told the reviewer to look in the sidebar. I had written a paragraph pointing them at a place that does not exist on the device they were holding. A note I wrote to help had sent them to the one screen that could not contain what they were looking for.The fix was not in the purchase stack at all:// First item, above the palette, and it removes itself once bought.if entitlement.state != .purchased { Button(entitlement.menuBarBuyTitle) { AppDelegate.showPaywall() } Divider()}Button("Open Palette ⌥Space") { PaletteController.shared.show() }That is the Mac menu bar. The iPhone got the same treatment as a safeAreaInset pinned above the list. Both share one title property, so the two surfaces cannot drift into reporting different numbers of days left.The notes that went back, in fullHere is the entire iOS review note as submitted with the build that was approved. No summary, no tidying.HOW TO REACH THE PURCHASE - please read, this is what build 22 got wrong.Build 22 was rejected under 2.1(b) because the reviewer could not purchase. Thepurchase itself worked; it was not findable on iPhone. The buy control lived in asidebar that the iPhone layout never renders, leaving only an overflow menu. Ourown review note made it worse by telling you to look in "the sidebar".In build 24, on iPhone and in the iPad side window, a row reading "Buy Fingertips- 14 days left" is pinned at the TOP OF THE SCREEN as soon as the app opens. Nomenu, no scrolling. Tap it and the purchase sheet opens showing the realstorefront price, with Buy, Restore Purchase and Redeem a Code. On a full-widthiPad and on Mac the same row is the first item in the sidebar.No account, login or demo credentials are needed. Fingertips has no accounts atall. On first launch the 14-day trial is active and every feature works, so thepurchase is reachable immediately rather than only after expiry.And the top of the macOS note, which is the one that had to prove a removal:AUTOMATIC PASTE HAS BEEN REMOVED - please read first.An earlier build of this app posted a synthetic Command-V with CGEvent.post so achosen snippet landed in the app the user was working in. That was rejected underGuideline 2.4.5 on 20 August 2026. We appealed, the decision was upheld on 27August, and the feature is gone.This is verifiable rather than asserted. Running "nm -u" on the shipped executablereturns NOTHING for AX, CGEvent or PostEvent. There is no CGEvent.post, noCGRequestPostEventAccess, no Accessibility API call of any kind, and the apprequests no Accessibility permission. Mac/Paster.swift is now 40 lines: it writesthe pasteboard and returns focus to the previous app.Two things about that second note.It admits a rejection in its first line. I had assumed that was a bad idea, on the theory that you do not hand a reviewer a reason to be suspicious. I now think the opposite: the reviewer can see the rejection history anyway, and leading with it is the difference between a note that reads as a defence and one that reads as a status report.It gives them a command rather than a promise. Undefined symbols are what a binary imports from the system, so if the app cannot call CGEvent.post, it cannot be hiding one. Anyone can run this against a binary, mine or yours:nm -u YourApp.app/Contents/MacOS/YourApp | grep -E '_AX|CGEvent|PostEvent'Use -E with the leading underscore, not -Ei. I had it case-insensitive in an earlier draft of this very article, which is worse than useless: AX then matches Axis.Set and maxWidth, and on the binary I tested it against it returns twenty-one lines of SwiftUI. A check that fires on every app on earth is not a check.Here is the strict form against the build that still had automatic paste, and against the one I submitted this week:$ nm -u Fingertips.app/Contents/MacOS/Fingertips | grep -E '_AX|CGEvent|PostEvent' # build 22_CGEventCreateKeyboardEvent_CGEventPost_CGEventSetFlags_CGEventSourceCreate_CGPreflightPostEventAccess_CGRequestPostEventAccess$ nm -u Fingertips.app/Contents/MacOS/Fingertips | grep -E '_AX|CGEvent|PostEvent' # build 26$Six symbols, then none. That is the entire argument, and it takes ten seconds to check.Did pre-empting work? Partly, and not where I expectedHonest scoring, because a postmortem that only reports wins is an advert.2.4.5: the note failed completely. Written before submission, detailed, correct about what the app did, and the rejection came anyway. Then the appeal failed too.3.1.1, the trial: never raised, on either platform, in any round. I cannot prove the note prevented it, and I will not claim it did. It costs a paragraph and it removes an entire category of question, which is a good trade on an unfalsifiable bet.2.1(b): my note made it worse. It pointed at a sidebar the review device does not render.The rewrite, which stated the previous rejection and the fix in the first line: 3 days on iOS and 1 day on Mac, no questions. The Mac was in review within 7 hours of submission, against thirteen days for its first round.I want to be careful about that last row. It is one app and a sample of one, a faster queue in September is not proof that my paragraph did anything, and there is a plainer explanation I cannot rule out: a resubmission of a rejected version is not the same queue as a first submission, and a quick second round is the ordinary shape of that. What I can say is narrower and still useful: the build that went back could not hide its purchase entry point on any layout, and the note described a removal that the reviewer could verify with one command.What review notes are actually forThe general shape, after four rounds and one appeal:They cannot make a feature findable. If the reviewer has to be told where a button is, the button is in the wrong place, and the note is a workaround for a bug that your users have too. Mine was.They cannot win an argument about a guideline. 2.4.5 is about what a permission is for. My note explained, accurately and at length, a use that the guideline does not allow.They are extremely good at making a removal checkable. "The feature is gone" is a claim. "nm -u returns nothing for these three symbols" is a check, and it takes the reviewer ten seconds.They are good at pre-empting a question nobody has asked yet. The trial paragraph may have done nothing at all. It cost me four sentences.They expire, and the best sections expire fastest. That one I only learned four days after writing the rest of this, and it is the last section below.And the biggest one: a review note is read by someone holding a specific device. Mine described a layout that device does not have. Before you write "in the sidebar" or "at the top right", open your app on the device class named in the rejection, or the one most likely to be used, and describe what is actually on that screen.Fingertips is on the App Store now on all three platforms. Twenty-four days from first submission to first approval; the last round took one, and the difference I can point to was not a better argument. It was a build that did not need one.Four days later I deleted a third of themI wrote everything above on 6 September. On 10 September I submitted 1.2.0 on both platforms, opened the review notes to add one paragraph about a new feature, and ended up rewriting them.The automatic paste section went first. All of it: 960 characters, 36% of the approved macOS note, headed please read first, quoted above as the strongest thing in it. Cutting it forced me to correct something I asserted earlier in this article.I said that admitting the rejection in the first line was right, because the reviewer can see the history anyway. That was true within one version. The note went back on the same 1.0 record, into the same Resolution Center thread the rejection was sitting in. 1.2.0 is a new version with an empty thread. The identical paragraph that read as a status report on 5 September reads as a defence of a closed case on 10 September, and not one word of it changed. The framing was never a property of the writing. It was a property of the submission.Then every build number. The approved iOS note says "this is what build 22 got wrong" and "In build 24, on iPhone…"- and the build attached to it was 25. I had caught that on the Mac copy and corrected it by hand before submitting. The iOS one went out pointing at a build that was not the one under review, and was approved anyway. Nobody asked. The 1.2.0 note contains no build numbers at all, which is the only version of that sentence that cannot rot.Two sentences of the paste material survived, because they still answer a live question about a Mac clipboard utility - does this thing paste for me, and what is it allowed to touch? They stopped being a confession and became a description:The app posts no synthetic events, makes no Accessibility API call of any kind,and requests no Accessibility permission. This is verifiable rather thanasserted: "nm -u" on the shipped executable returns nothing for AX, CGEvent orPostEvent.960 characters down to 242. Same fact, same check, no longer arguing a case that closed.And here is the part I did not expect: the notes did not get shorter.approved 1.0submitted 1.2.0iOS2,353 characters3,431macOS2,658 characters2,644macOS came out fourteen characters different while more than a third of its content was replaced. iOS grew by a thousand, because 1.2.0 adds a row showing eight characters of CloudKit's user record name, so somebody can tell whether two of their devices are on the same iCloud account. It looks exactly like the kind of identifier a reviewer flags, so the notes now open on what it is, what it is not, and why it exists. The pre-empting did not stop. It moved to the thing that is actually new.Which is the lesson I did not have when I wrote the first half of this article. A review note is not a document you maintain. It is a snapshot of what you expect one reviewer, holding one build, on one version record, to ask - and it has to be rewritten when any of those three change. The best sections expire fastest, because the better a paragraph is at answering a question, the more tightly it is bound to the moment that question was live.Read them before every submission as though the last rejection never happened. For the person opening them, it did not.Fingertips is a snippet library for iPhone, iPad and Mac, built for RevenueCat's Shipaton 2026. It is on the App Store and at usefingertips.com. Earlier in this series: an entitlement check that turned an unreachable RevenueCat into an unlimited licence, why you cannot give a hackathon judge a free unlock before you submit, an on-device model that ignored its search tool and made up my data, and the rejection for a Buy button the iPhone layout never rendered.