apple: release type (apple.releaseType, apple release --after-approval|--manual), device-family preflight, TestFlight invite needs an installable build

This commit is contained in:
CRTkafa 2026-10-27 17:07:37 +07:00
parent 4763862178
commit 85cf494c0a
24 changed files with 899 additions and 18 deletions

View file

@ -1547,3 +1547,41 @@ that fails without the fix (see CONTRIBUTING.md).
are not the user's and are not hits. A prebuilt vendored framework carries its own paths: rebuild it path-free.
- **Never:** point a shared build folder at the default DerivedData, or run the privacy scan only after the upload.
- **Guard:** `cli/lib/path-free.ts`, `tests/path-free.test.ts`, the hint when `--out` is outside the home folder.
## 125. Updates sat in Pending Developer Release: the version was created and submitted with release type MANUAL
- **Symptom:** an approved update did not go live; it waited in PENDING_DEVELOPER_RELEASE because `apple listing` created the
version with releaseType MANUAL and `apple submit` never touched it.
- **Do:** set `apple.releaseType: afterApproval` (or `manual` / `scheduled` with `apple.earliestReleaseDate`). `apple listing`
creates new versions with it, `apple submit` / `apple resubmit` set it on the version before submitting when it differs
(the dry run shows `releaseType MANUAL -> AFTER_APPROVAL`). On one version: `storebound apple release --after-approval --yes`
(`--manual`, `--scheduled <ISO date>`; `--platform`, `--version`, `--json`; exit 7 when it already has that type). The type
is editable until App Review approves the version; an approved one is released with `apple release --manual-release`.
Unset: new versions are MANUAL and existing ones are left as they are. Updates are agent steps; `--after-approval` on the
first version of an app puts it on sale by itself, so that is the owner's (exit 3 `OWNER_STEP`, `--first-release`).
- **Never:** wait for an approval email and then look for the console button, or flip the type back with `apple listing` runs.
- **Guard:** `cli/lib/release-type.ts`, `tests/apple-release-gaps.test.ts`.
## 126. iPhone-only build of an app whose live version runs on iPad: ITMS-90101 after a full archive
- **Symptom:** `storebound check` passed with `apple.ipad` false; the upload was refused after the archive with ITMS-90101 "This
bundle does not support one or more of the devices supported by the previous app version" (TARGETED_DEVICE_FAMILY = 1).
- **Do:** `storebound validate` and `apple build` read the live version (READY_FOR_SALE, else the newest that was) from App
Store Connect: its build bundle (`deviceProtocols`, device models of `buildBundleFileSizes`) and its screenshot sets
(`APP_IPAD_*`); any iPad signal means iPad. They compare it with TARGETED_DEVICE_FAMILY of the Release configuration in the
Xcode project and with `apple.ipad`, and stop BEFORE the archive with the fix: `TARGETED_DEVICE_FAMILY = "1,2"` and
`apple.ipad: true`. Offline `check` warns when the live families cannot be known. `--allow-device-gap` builds anyway.
- **Never:** drop a device family the live version supports, or turn `apple.ipad` off to silence the screenshot check.
- **Guard:** `cli/lib/device-families.ts`, `cli/apple/device-families.ts`, `tests/apple-release-gaps.test.ts`. The build bundle
attribute names come from Apple's spec; which signal carries the iPad answer live is not recorded, hence the merge.
## 127. TestFlight invite on a new external group: 409 STATE_ERROR.TESTER_INVITE.NO_INSTALLABLE_BUILDS
- **Symptom:** `apple testflight testers --group <g> --invite --yes` created the tester but the invitation failed with 409
NO_INSTALLABLE_BUILDS: the group had no build past Beta App Review yet.
- **Do:** `--invite` first checks that a build of the tester's group is installable (external: BETA_APPROVED / IN_BETA_TESTING;
internal: READY_FOR_BETA_TESTING / IN_BETA_TESTING). If not, the tester stays added, no invitation is sent and the run prints
"tester added; the invite goes out when a build in <group> passes Beta App Review (re-run with --invite then)", exit 0. The
409 itself is treated the same way. `apple testflight distribute --submit-review` prints the line for testers not invited yet.
- **Never:** retry the invitation in a loop, or report the added tester as a failure.
- **Guard:** `installableBuild` / `noInstallableBuildHint` in `cli/lib/testflight.ts`, `tests/apple-release-gaps.test.ts`.