mobile-store-submission
Why It Exists
Every one of this skill's nine invariants was extracted from a single real
submission cycle — one app, submitted across iOS, tvOS, and Android, that hit
two separate rejections before shipping (commit 26f7a25). It exists
specifically because mobile-expo-app stops at "a signed build exists" and
only briefly touches store-record creation; this skill picks up from there,
covering what actually happens between having a build and having a released
app.
Two of the nine invariants are worth calling out as the kind of thing that
only a real rejection surfaces. The App Store Connect "Update Review" button
looks like it resubmits a rejected version — it doesn't. It only unlocks the
version into a locked "Ready for Review" state, and in that state fastlane's
upload_to_app_store fails immediately with You cannot create a new version of the App in the current state, because the API genuinely cannot touch a
client-side-locked version. The actual finish line is a separate button, on
the reviewsubmissions detail page for that specific rejected submission —
and the version-level status label reads identically whether or not that
click has actually happened, so there's no way to infer completion from the
version page alone. Separately, an App Store Connect subscription can show
"Ready for Review" at the product level while Apple still rejects the whole
app with "Subscriptions were labeled Unavailable" — because the
subscription's parent group has its own, entirely separate localization
requirement, and a missing group display name alone is enough to trigger the
rejection even when nothing about the product's own configuration is wrong.
What It Does
Covers the submission-and-review side of both stores: bumping the native
build number every single submission (Expo has no local auto-increment),
satisfying Play Console's release_status:draft requirement for a brand-new
app's first release, correctly localizing both an App Store Connect
subscription and its parent group, working around the sandbox-tester
requirement for testing draft in-app purchases, actually finishing an App
Store resubmission after a rejection, budgeting for Play Console's mandatory
12-testers-for-14-days closed-testing gate on personal developer accounts,
and deciding a bundle-ID/platform strategy correctly before it becomes
unfixable.
How To Use It
Trigger phrases: "App Store Connect", "TestFlight", "fastlane ios release", "fastlane android release", "Play Console closed testing", "subscriptions labeled Unavailable", "release_status:draft", "versionCode already used", "12 testers 14 days", "sandbox tester account", "Resubmit to App Review", or submitting/resubmitting a mobile app for store review.
skills add git@github.com:catesandrew/next-starters.git --skill skills/mobile-store-submission -g
npm install @next-starters/skill-mobile-store-submission
/plugin marketplace add catesandrew/next-starters
/plugin install mobile-store-submission@next-starters
Gotchas & Invariants
- Bump the native build number (
app.config.ts'sandroid.versionCode, and the iOS build number fastlane reads) before every submission — Expo does not auto-increment it, and a stale value gets rejected as "already used," not flagged as a reminder. - A brand-new Play Console app's first release must pass
release_status:draftexplicitly, or the upload API rejects acompletedrelease with "Only releases with status draft may be created on draft app." - Draft or unreviewed in-app-purchase products are invisible to StoreKit under a developer's own regular signed-in Apple ID — this needs a genuine Sandbox Tester account (created in ASC, signed into the device via Settings → App Store → Sandbox Account), and Apple's own guidance confirms IAP doesn't need prior approval to function in sandbox review.
- A companion platform (tvOS, for example) can only be added to an existing app record if it shares that record's bundle ID — two app records with different bundle IDs can never be merged after the fact, so the bundle-ID/platform decision has to be made before registering the second platform, not after.
- Apple app-record creation cannot be scripted end-to-end under any
circumstance —
produce'screate_appstep needs an interactive Apple-ID login that no API key can substitute for. - A misleading "dimensions are wrong" error on an ASC screenshot upload can
actually be caused by the PNG's alpha channel rather than its pixel
dimensions — check
sips -g hasAlphabefore re-cropping anything.
Related Skills
- mobile-expo-app — the build/EAS/push side this skill picks up from once a signed build exists.
Sourced from: skills/mobile-store-submission/metadata.json, skills/mobile-store-submission/SKILL.md, git commit 26f7a25