fix: Cmd+Y crash and New Machine sheet layout
Summary
Cmd+Y aborts nightly while the New Machine sheet animates open:
NSGenericException: The window has been marked as needing another Update Constraints in Window pass, but it has already had more Update Constraints in Window passes than there are views in the window (Sentry CMUXTERM-MACOS-3YDJ, 10 events today, all with the sheet at 440×284, all on nightlies 3731595686301 and 3733464696001).
Cause: the Cloud sheets set sizingOptions = [.preferredContentSize], so the window followed SwiftUI from inside AppKit's layout pass. The crash backtrace shows the cycle: layoutIfNeeded → _changeWindowFrameFromConstraintsIfNecessary → setFrameSize → NSHostingView.didChangeValue(forKey:) → invalidateSafeAreaInsets → setNeedsUpdateConstraints. Any control whose size depends on the width it is offered keeps that cycle going until AppKit throws. The same crash class has hit this sheet three times, and each earlier fix only guarded one control:
- Sep 28 (
6edb16da4aa): a labeled checkbox. - Today, #17392: the Base pop-up.
- Today, #17417: this one set
sizingOptions = []but froze the window at its first size, so rows that appear after the sheet opens get clipped. Examples: the inherited-settings row after picking a Base machine, the loaded plan, and an expanded allowlist.
Fix: a new CloudSheetWindow (Sources/Cloud/CloudSheetWindow.swift):
- The hosting controller has no sizing options, so AppKit never sizes the window from SwiftUI during layout.
- The content reports its ideal size, which doesn't depend on the window's height.
- The window takes that size with an explicit
setFrameon a later main-queue turn, after the open animation and never inside a layout pass. The top edge stays anchored.
It is used by all three Cloud sheets that had the pattern: New Machine, Network, and Create Team.
Pop-up layout: today's fixes left the grid misaligned. The Base pop-up hugged the trailing edge (#17417), and the Size pop-up stretched across the whole column (#17392). Both now take their own width on the column's leading edge, like Network. They narrow, truncating the title, only when a long machine name or a locked size row would overflow the sheet. The Grid's first-baseline alignment still holds.
Testing
- Red, then green:
NewMachineSheetLayoutTests.presentedSheetTracksContentThatArrivesLaterpresents the real sheet throughNewMachineSheetPresenter.presenton a host window withbeginSheet.- Data matches the nightly account: 8 base machines, a cold plan, and a nearly full pool.
- Plan, pool, and machine-list refreshes land while the sheet is open, then a Base machine is picked.
- The window must end at the content's ideal size.
- Red commit
c618c1f7549(main with #17417 freezes the size); green commit6beb6228f59. Hosted CI runs both; localxcodebuild testis not allowed.
- Red, then green:
NewMachineSheetLayoutTests.popUpsShareLeadingEdgeAtNaturalWidthrequires the Base and Size pop-ups to share a leading edge, each no wider than its own size. Red commit0d997c2efd6, green commit8dc06cf58cf. The existing long-name test still guards overflow. CloudSheetWindow.swifttype-checks withswiftc -typecheck -swift-version 6.scripts/check-pbxproj.shandscripts/check-pbxproj-group-membership.pypass.- Not done yet:
- The abort has not been reproduced on demand. A standalone harness of a simplified sheet did not abort, and reproducing with the real sheet is in progress.
- No dogfood on a tagged build yet.
Changelog
- Fixed: Cmd+Y (New Machine) no longer crashes cmux while the sheet opens, the Cloud sheets resize to fit content that appears after they open, and the New Machine pop-ups line up again.
Impact map
- Source of truth:
CloudSheetWindow. - Callers:
NewMachineSheetPresenter.present(Cmd+Y, the Machines panel +, the command palette),CloudNetworkPolicySheetPresenter,CloudCreateTeamSheetPresenter. NewMachineModelis unchanged.
🤖 Generated with Claude Code