fix(ci): rotate iPad showcase captures without Simulator UI scripting - #5094
Conversation
The landscape iPad captures from #5065 rotate the simulator by AppleScript-clicking Simulator's menus, which CI cannot do: the runner denies osascript Accessibility access (error -1719), and simctl has no orientation command. Rotate from inside the app instead: - t3-native-controls gains getShowcaseOrientation (launch-arg reader), applyShowcaseOrientation (UIWindowScene.requestGeometryUpdate), and getInterfaceOrientation so the coordinator can verify the rotation actually took effect and retry attempts made before the scene was foreground-active. - iPadOS ignores programmatic orientation for multitasking-capable apps, so the capture build sets requireFullScreen (env-gated via T3_SHOWCASE_CAPTURE_BUILD; production builds are unchanged). - iPadOS 26 windowing would put a requires-full-screen app in a fixed portrait compatibility window, so the harness switches the simulator to Full Screen Apps mode (SBChamoisWindowingEnabled=false + SpringBoard restart) before landscape captures. - The framebuffer is now natively landscape, so the sips post-rotation is gone along with the osascript helper. Verified locally end to end from a clean simulator: the iPad capture renders upright landscape at 2752x2064 and passes validation. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
| // portrait compatibility window, which defeats the in-app landscape rotation | ||
| // the capture build relies on. Switch the device to Full Screen Apps mode | ||
| // (Settings > Multitasking & Gestures) and restart SpringBoard to apply it. | ||
| async function ensureIosFullScreenAppsMode(udid: string): Promise<void> { |
There was a problem hiding this comment.
🟡 Medium scripts/mobile-showcase.ts:802
ensureIosFullScreenAppsMode permanently writes SBChamoisWindowingEnabled=false to the simulator and never restores the previous value. Running a landscape capture against a pre-existing developer simulator leaves that simulator stuck in Full Screen Apps mode after the harness exits, silently changing its multitasking configuration. The function reads the current value (and early-returns when already 0) but neither records it for cleanup nor restores it in the finally block. Consider capturing the prior value and writing it back during iOS cleanup, or only toggling the setting on simulators the runner created.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @scripts/mobile-showcase.ts around line 802:
`ensureIosFullScreenAppsMode` permanently writes `SBChamoisWindowingEnabled=false` to the simulator and never restores the previous value. Running a landscape capture against a pre-existing developer simulator leaves that simulator stuck in Full Screen Apps mode after the harness exits, silently changing its multitasking configuration. The function reads the current value (and early-returns when already `0`) but neither records it for cleanup nor restores it in the `finally` block. Consider capturing the prior value and writing it back during iOS cleanup, or only toggling the setting on simulators the runner created.
…ulators The first CI run captured a floating portrait-screen window: on a brand new device SBChamoisWindowingEnabled alone is not honored. The Settings toggle writes three SpringBoard keys (Chamois windowing, Medusa multitasking, flexible-windowing stage creation), so write all three, reboot the simulator instead of kickstarting SpringBoard, and verify the mode applied. Also gate showcase scene readiness on the orientation having settled, and report orientation from screen bounds so a floating landscape window on a portrait screen counts as portrait — an early or failed rotation now times out loudly instead of shipping wrong-size screenshots. Verified locally against a freshly created simulator (the CI-equivalent path): upright landscape 2752x2064, validation passes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
Bugbot Autofix is ON, but a cloud agent failed to start.
Reviewed by Cursor Bugbot for commit 87ff819. Configure here.
| "-bool", | ||
| "false", | ||
| ]); | ||
| } |
There was a problem hiding this comment.
Early exit skips multitasking keys
Medium Severity
The ensureIosFullScreenAppsMode function exits early if SBChamoisWindowingEnabled is 0. This is problematic because fully disabling iPadOS windowing now requires setting three SpringBoard keys. If the other two keys remain enabled, simulators can retain windowing behavior, causing landscape rotation and orientation checks to fail, which leads to showcase capture timeouts or validation failures.
Reviewed by Cursor Bugbot for commit 87ff819. Configure here.
ApprovabilityVerdict: Needs human review 1 blocking correctness issue found. CI/screenshot capture tooling changes with two unresolved review comments identifying potential bugs: simulator settings are not restored after capture, and the early-exit logic may leave multitasking keys in an inconsistent state. These issues warrant human review before merging. You can customize Macroscope's approvability policy. Learn more. |
…ortrait A headless CI simulator keeps its display portrait while the rotated app renders sideways inside it (with Simulator.app attached, the display itself rotates and no correction is needed). Detect which case we are in from the captured PNG's dimensions and rotate 270 degrees only when the buffer is portrait — verified against the actual CI capture. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
## What's Changed * feat(cli): `npx t3 pair` - generate QR code from a running server by @t3dotgg in pingdotgg/t3code#4955 * fix(server): self-update no longer rolls itself back on restart by @t3dotgg in pingdotgg/t3code#5095 * fix(ci): rotate iPad showcase captures without Simulator UI scripting by @juliusmarminge in pingdotgg/t3code#5094 * feat(web): render terminals with libghostty-vt by @StiensWout in pingdotgg/t3code#4860 * refactor: move the canonical libghostty-vt vendor to the repository root by @StiensWout in pingdotgg/t3code#5102 **Full Changelog**: pingdotgg/t3code@v0.0.32-nightly.20260731.964...v0.0.32-nightly.20260731.965 Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.32-nightly.20260731.965


Summary
The Mobile Showcase Screenshots workflow's iOS job fails on main (run): #5065 rotates the iPad simulator by AppleScript-clicking Simulator's menus, and the CI runner denies osascript the required macOS Accessibility permission:
simctlhas no orientation command (checked through Xcode 26.5), so this replaces UI scripting with in-app rotation. Getting there surfaced a chain of iPadOS constraints; the fix has four pieces:t3-native-controlsgainsgetShowcaseOrientation(reads a--showcaseOrientationlaunch arg the harness now passes),applyShowcaseOrientation(UIWindowScene.requestGeometryUpdate), andgetInterfaceOrientationsoShowcaseCaptureCoordinatorcan verify the rotation took effect and retry. Scene readiness is gated on the orientation having settled, and the orientation getter reports from screen bounds (which mirror the captured framebuffer) — a failed rotation now times out loudly instead of shipping wrong-size screenshots.requireFullScreeninapp.config.ts, gated onT3_SHOWCASE_CAPTURE_BUILD=1which only the showcase harness sets — production builds are unchanged. (The Expo config key really isrequireFullScreenin config-plugins 56; therequiresFullScreenspelling is silently ignored.)simctl spawn defaults— writing all three SpringBoard keys the Settings toggle writes (SBChamoisWindowingEnabled,SBMedusaMultitaskingEnabled,SBFlexibleWindowingPreviouslyEnabledAutomaticStageCreation; the first alone is ignored on a freshly created device), then reboots the device and verifies the mode stuck.The osascript helper and the unconditional
sips --rotate 90are gone.Verification
@t3tools/scripts/@t3tools/mobiletypechecks and the 197 scripts tests.🤖 Generated with Claude Code