--- name: mlkit-release description: Use when triaging incoming issues or PRs for google-mlkit-swiftpm, or when cutting a release. Covers the four failure modes consumers keep reporting (undefined symbols, "Invalid model path.", ITMS-91065, no arm64 simulator), how to tell them apart, and the build → verify → publish sequence. --- # ML Kit SwiftPM triage and release Read `CLAUDE.md` for the pipeline shape first. This skill is the procedure; that file is the reference. ## Triage: match the report to a known mechanism Almost every consumer report is one of these four. Identify the mechanism before changing anything — three of the four are invisible when building the Example app, because it links every product at once. | Symptom | Mechanism | Check with | | --- | --- | --- | | `Undefined symbols … _OBJC_CLASS_$_MLKXeno*` when adopting one product | The `.library` product omits a transitive framework. A product links only the targets it lists. | `ruby scripts/check_product_closure.rb` | | `MLKTextRecognizerInternalErrorCreationFailure "Invalid model path."` | The module's model bundle was never published. `Pods//Resources//` is the full list; ten of them exist only there, not nested in any framework | `ls GoogleMLKit/*.bundle` against `ls -d Pods/*/Resources/*/`, and `./scripts/verify_local_archive.sh` | | A framework binary that is ~33KB in the app | The framework binary is a bare Mach-O object, so Xcode relinks it as a dylib and dead-strips the data | `file GoogleMLKit/.xcframework/*/.framework/` — must say `ar archive` | | `ITMS-91065: Missing signature` on upload | A framework bundle on Apple's commonly-used-SDK list is embedded in the app. Xcode embeds a stub bundle for every static framework bundle it links. | `./scripts/verify_local_archive.sh` | | Cannot build for the Simulator on Apple Silicon | The simulator slice has no arm64. Xcode 26 dropped Rosetta simulators, so an x86_64-only slice is unusable. | `lipo -archs` on the simulator slice | | `Invalid MinimumOSVersion … is ''` (90530) on upload | A `Resources/*-Info.plist` template is missing the key; the templates ship verbatim into consumers' apps | `ruby scripts/verify_build.rb` | Reports about **missing dSYMs** are expected and harmless: Google ships no DWARF, the frameworks are static, and their symbols land in the consumer's own dSYM. Close with that explanation. ## Triage: dependency PRs - `Package.swift` dependency pins are **generated** from `Podfile.lock` by `scripts/update_package_dependencies.rb`. `renovate.json` disables the `swift` manager for the root `Package.swift`; close any PR that still slips through, and never merge one that breaks a pod constraint (e.g. `GTMSessionFetcher` is pinned `< 4.0`). - Ruby major upgrades are blocked on purpose: Ruby 4.0 broke CocoaPods on the macOS runners. - Anything touching `Example/` only is safe to merge on a green CI run. ## Fix, then verify before publishing ```bash make run # full pipeline into GoogleMLKit/ make verify # closure + artifacts + Package.swift parse ./scripts/verify_runtime.sh # slices, Info.plists, symbol table ./scripts/verify_local_archive.sh # runs ML Kit on the Simulator, archives for device ./scripts/verify_app_store_upload.sh --upload # Apple-side validation and delivery ``` `verify_local_archive.sh` is the gate. It repoints `Package.swift` at the local XCFrameworks, **runs ML Kit on the arm64 Simulator**, archives for device, and fails if an ITMS-scanned SDK is embedded, if anything is linked dynamically, or if the app binary is too small to still contain the ML Kit model data. Never publish without a green run. The runtime step is not optional theatre: a missing model bundle links and archives perfectly and only fails when inference runs. Two of the four recurring reports would have been caught years earlier by it. `verify_app_store_upload.sh --upload` is what closes out ITMS-91065: Apple reports it during post-upload processing, so no local check can stand in for a real delivery. The App Store Connect side is already set up: - app record **SwiftPM Binary Verify** (`6814873277`), bundle ID `com.d-date.google-mlkit-swiftpm` (`7Y76Y69Z42`), team `N5U649DS4Z` - provisioning profile **SwiftPM Binary Verify App Store** (`MJ47UVM4SC`), built from the `Apple Distribution` certificate `JWTYWVHM8Z` Four things cost time the first time round; they are worth knowing: - **Creating an app record needs a web session** (`asc web auth login`); the public API cannot do it. The session defaults to whichever provider Apple returns first, which may be another organisation entirely -- check with `asc web bundle-ids list` before creating anything, and select the right one with `--provider-id --developer-team N5U649DS4Z` (passing a wrong `--public-provider-id` conveniently lists the valid ones). - **Automatic signing does not work here**: Xcode has no signed-in account, so the profile has to be created through the API and installed with `asc profiles local install`. - **Signing settings must not be passed to `xcodebuild` on the command line.** They reach every target in the graph, and SwiftPM's resource-bundle targets fail with "does not support provisioning profiles". Put them in ExportOptions.plist instead. - **altool wants its API key as a file** in one of a few fixed directories, while `asc auth login` keeps it in the keychain. The script stages a copy and removes it afterwards. To reproduce a consumer's single-product setup, the static closure check is enough — do not rely on the Example app. ## Publish ```bash ruby scripts/update_version.rb # only when bumping the pod version gh release create --prerelease # prerelease when the tag has a suffix ./scripts/upload_release.sh # uploads *.xcframework.zip and *.bundle.zip ruby scripts/update_checksums.rb # rewrites Package.swift URLs + SHA256s swift package dump-package > /dev/null ``` Prefer the **Build MLKit XCFrameworks** workflow for a normal version bump; do it locally only when the pipeline itself changed, since that is what needs verifying. Resource bundles must be uploaded too — consumers add them by hand, and `scripts/download_bundles.sh` fetches them from the release. After publishing, reply on each issue the release fixes with the tag and the manual steps it still requires (bundles, `-ObjC -all_load`). ## When adding a module `Podfile` → `Resources/-Info.plist` → `MLKIT_MODULES` in the `Makefile` → `Package.swift` (`.binaryTarget` plus product wiring). Everything else derives from those. Finish with `ruby scripts/check_product_closure.rb`.