Eine Woche vor dem Phone-18-Launch sprach im Meeting niemand über Kamerabrennweiten — alle starrten auf eine Actions-Liste voller roter Punkte. Xcode 27, das iOS-27-SDK, GitHubs gehostetes Label xcode-27 und ein paar frisch angebundene Apple-Silicon-Self-hosted-Runner: vier Linien in derselben Woche. Driftet eine, stehen App-Store-Screenshots und TestFlight-Betas gemeinsam still. Wir haben die iOS-CI/CD von „wird grün“ auf „hält die Launch-Woche“ umgebaut und die echten Stolperfallen hier festgehalten.
Der Zeitanker ist hart: Am 10. September 2026 schreibt GitHub im Changelog, dass das Xcode-27-Runner-Image jetzt auf macOS 27 läuft — Labels bleiben xcode-27 / xcode-27-xlarge, und es gibt nur arm64. Jobs, die am Vortag auf macOS-26-Basis „zufällig grün“ waren, können nach dem Image-Cut wegen OS-Version, Simulator-Gerätenamen oder Disk-Wasserstand flächig kippen. Für Golden-Gate-GA-Fenster und Geräte-Cutoff siehe intern macOS 27 Golden Gate: Releasedatum und unterstützte Modelle; hier geht es nur um die CI-Seite: wo man tritt, wie man aufräumt.
Warum vor dem Launch die ganze Pipeline neu fahren — und nicht nur die Matrix umbiegen
Viele Teams haben den Reflex: xcode-version von 26 auf 27 stellen, Destination auf iPhone 18 ändern. Vor dem Phone-18-Fenster explodiert das fast immer. Drei Schichten. Erstens: SDK und Runner-Image kommen nicht synchron — lokal liegt Xcode 27 GM, das gehostete Image hängt noch in der Public Preview oder ist gerade von macOS-26-Basis auf 27 umgestellt. Zweitens: Die Simulator-Gerätetabelle ändert sich. Im iOS-27-Runtime steht dein hardcodierter Name oft noch nicht; name=iPhone 18 endet direkt in Unable to find a device matching the provided destination. Drittens: Cache-Keys für DerivedData, SwiftPM und CocoaPods, die noch an Pfade „vor dem großen Xcode-Sprung“ gebunden sind, treffen alte Artefakte — gestern Müll, heute Compiler.
Wir trennen Abnahme: „kompiliert“ versus „hält die Launch-Woche“. Ersteres: einzelner PR-Job grün. Letzteres: Concurrency, Disk, Zertifikate und Simulator-Kaltstart treten sich im Peak nicht gegenseitig. Gehostet zuerst die GitHub-hosted-Runners-Doku lesen; Self-hosted per Label PR-Schnellfeedback und Archive-Schwerjobs in getrennte Pools — dieselbe Logik wie in GitHub Actions bremst iOS/Xcode-CI: neuer Ansatz, nur diesmal ist der Trigger Phone 18.
Falle 1: Noch macos-latest — oder xcode-27 meint „irgendein Mac reicht“
macos-latest ist im Herbst 2026 weiter gut für „läuft irgendwie“, aber ungeeignet als einzige Abnahmefläche in der Phone-18-Woche. Es folgt GitHubs Default-Image-Politik — nicht „iOS-27-SDK plus dein Simulator sind schon drin“. Für Xcode 27 explizit runs-on: xcode-27 (Schwerjobs: xcode-27-xlarge), statt zu hoffen, dass maxim-lobanov/setup-xcode auf dem falschen Basis-Image retten kann — fehlt die Runtime, hilft auch das richtige Xcode.app simctl nicht.
Subtiler: Das Changelog betont nur arm64. Bleiben Intel-Self-hosted-Knoten oder steht runs-on: [self-hosted, macOS] als „jeder Mac nimmt Xcode-27-Jobs“, wird die Matrix zu „manchmal grün, manchmal rot“ — grün trifft Apple Silicon, rot Intel, der die Toolchain nicht läuft. Labels auf die echte Menge setzen, z. B. [self-hosted, macOS, ARM64, xcode27], und nicht upgegradete Knoten vom Label nehmen.
xcode-27 nimmt, wer die macos-26-Kompat-Linie: ins Runbook, und auf der Actions-Runner-Seite wöchentlich abgleichen.
Falle 2: Destination fest auf iPhone 18 — im Image gibt es dieses „Telefon“ noch nicht
Marketing-Phone 18 und Simulator-Gerätename sind nicht dieselbe Tabelle. In actions/runner-images listet die iOS-27.0-Runtime derzeit iPhone-17-Serie, iPhone Air, diverse iPads — ohne Garantie, dass am Launch-Tag ein Simulator namens iPhone 18 erscheint. YAML mit -destination 'platform=iOS Simulator,name=iPhone 18,OS=27.0' ist die häufigste Selbstverletzung vor dem Release.
Reproduzierbar: Job-Start mit xcrun simctl list devices available -j, JSON parsen, nach „iOS-27-Runtime + Name beginnt mit iPhone“ sortieren, eine Maschine nehmen, UDID nach $GITHUB_OUTPUT, danach xcodebuild test nur mit id=…. Bei Multi-Device-Matrix: Schnittmenge verfügbare Liste ∩ Whitelist; fehlt etwas → skip + Alert, nicht die ganze Release-Linie rot. UI-Tests: erster Kaltstart des neuen Systems kostet oft Minuten extra — Timeout noch wie unter Xcode 26 bei 20 Minuten, und aus sporadisch wird systematisch.
| Schreibweise | Risiko Launch-Woche | Stabilere Alternative |
|---|---|---|
name=iPhone 18,OS=27.0 | Gerätename fehlt → Fail | Dynamisch per UDID |
OS=27.0 fest pinnten | Image evtl. 27.0.1 | Runtime-Präfix oder neueste verfügbar |
Nur macos-latest | SDK/Simulator unklar | Explizite xcode-27-Abnahme |
| Intel + Apple Silicon gemischt | Gleicher Job, sporadische Arch-Fails | Pools splitten, 27-Linie nur ARM64 |
Falle 3: Cache-Key nicht mit Xcode 27 invalidiert — grün ist die „alte Welt“
Beim Major-Upgrade kommt die stärkste Illusion des „Fixes“ aus dem Cache. SwiftPM-SourcePackages, CocoaPods-Pods, eigene DerivedData-Tarballs: steht im Key nur Branch oder Lockfile-Hash, nicht $(xcodebuild -version) / Image-Version, restored Actions fröhlich Xcode-26-Artefakte. Symptome: fehlende Link-Symbole, crashender Swift-Driver, Tests bauen, Modul-Cache-Check scheitert.
Wir erzwingen drei Segmente im Key: kurze Xcode-Version, Runner-Image-Version (gehostet aus Env oder Doku pinnten), plus Package.resolved / Podfile.lock. Am Upgrade-Tag Prefix ändern — lieber 8–12 Minuten Kaltstart mehr als in der Launch-Woche debuggen, warum derselbe Commit lokal geht und CI nicht. Self-hosted Apple Silicon: DerivedData über Jobs hinweg und ohne Xcode-Versionsverzeichnisse mischt Preview- und GM-Zwischenstände.
Falle 4: Apple-Silicon-Runner da — Disk und Queue holen dich zurück
Xcode 27 + iOS-27-Runtime + mehrere Simulatoren fressen Disk. Das gehostete xcode-27-Image ist schon schwer; Self-hosted Mac mini mit Xcode 26, zwei Betas und drei App-DerivedDatas platzt oft erst spät im Archive mit No space left on device. Vor der Launch-Woche: nur eine „aktuelle Abnahme“-Xcode, Runtime-Whitelist, DerivedData per Job säubern, nächtlich cron mit df -h und xcrun simctl delete unavailable.
Queue verschwindet nicht mit Silicon. Vor dem Launch bläht die Matrix von „ein SDK“ auf „26-Kompat + 27-Abnahme“ — gehostete Concurrency und Self-hosted-Slots sind gleichzeitig voll. PR-Schnellfeedback und TestFlight-Archive müssen Labels trennen: Minuten fürs Erste, Queue ok fürs Zweite, ohne das Erste zu blockieren. Wer im Peak den Slot kriegt, entscheidet das Label — nicht die M-Serie auf dem Poster.
Toolchain-Verhalten nach Apple-Xcode-Dokumentation; welche Simulatoren im Image liegen, nach dem runner-images-Readme der Woche — keine Blog-Screenshots vom Vorjahr als Config-Quelle.
Launch-Wochen-Runbook: so haben wir umgeschaltet
Tag 1: Produktions-PR-Abnahme explizit auf xcode-27, eine macos-26-(oder Vorgänger-)Kompat-Sentinel behalten — 27 rot blockiert Merge, 26 rot nur Alert. Tag 2: alle Test-Destinations auf dynamische UDID, Marketing-Namen aus YAML. Tag 3: Cache-Prefix invalidieren, kalten Build erzwingen, Wall-Time als Baseline. Tag 4: Self-hosted-Pool splitten: ci-pr und ci-release, keine Intel-Knoten am 27-Label.
On-Call täglich: Changelog / runner-images auf neues Image, Runner-Disk, Ratio queued/run — gelb länger als grün? Zahlen schlecht: zuerst Matrix-Parallelität kappen, dann Maschinen — mehr Maschinen ohne Label-Trennung machen nur falsche Jobs schneller.
xcode-27 länger queued als kompiliert, oder du ein GM-Image für Notarisierung und Upload pinnen musst: tagesweise Apple-Silicon-Cloud-Mac als Self-hosted ist oft günstiger als Glücksspiel in der Shared Queue. Dedizierte Knoten für Release und Zertifikatskette; PR-Masse kann auf gehosteten Preview-Images als erste Gate bleiben.
FAQ
Muss sofort jeder Job auf xcode-27?
Nein. Launch-Abnahme und Store-Builds auf 27 pinnen; Alt-OS-Kompat und Hotfixes können vorerst auf dem Vorgänger-Image bleiben. Entscheidend: Labels und Branch-Protection klar — kein „irgendein Grün reicht zum Mergen“.
Lokal Xcode 27 grün, CI trotzdem rot — warum?
Drei Checks zuerst: ist der Runner wirklich arm64-xcode-27, existiert der Simulator-Name, trifft Cache altes DerivedData? Lokal volle Runtime, gehostetes Image nicht zwingend.
Self-hosted und GitHub-hosted im selben Workflow?
Ja, aber getrennte Jobs und Labels. Kein gemeinsames runs-on-Array, das gehostet und beliebiges Self-hosted matched — sonst ist Scheduling nicht reproduzierbar.
Kann Phone-18-Gerätetest Simulator-CI ersetzen?
Nein. Gerät: Kamera, Mobilfunk, Performance-Feeling; CI: Compile, Unit-Tests, Regression pro PR. Launch-Woche braucht beides — Gerät nicht als einziges Merge-Gate.
Phone-18-Fenster · Xcode-27-On-Call
Braucht ihr Apple Silicon ohne Shared-Queue-Lotterie?
Release und Notarisierung auf dediziertem Cloud-Mac pinnen; PRs weiter über gehostetes xcode-27. Image und Zertifikatskette tagesweise prüfen — entspannter als Concurrent am Launch-Tag zu jagen.