fix(app): windowResizability(.contentMinSize) so window stops auto-resizing

Root cause of the "window grows whenever I switch to Chat / the
v2.3 Sessions tab" bug. Prior commits (4baa3d4 sessions-tab
clamp, 9aad905 chat+projects detail-area clamp) were defensive
but not sufficient — with the actual window policy treating
content's ideal height as a BINDING (not a minimum), those
clamps only kept things inside the view, not inside the window.

scarfApp's WindowGroup had .defaultSize(width: 1100, height: 700)
but no explicit .windowResizability(...) modifier. On macOS, a
non-Settings WindowGroup defaults to .automatic, which evaluates
to .contentSize — meaning every layout pass rebinds the window to
the currently-displayed detail view's ideal height. Explains
every symptom:

- Switching to Chat / Sessions grows the window to content size
- User drag-to-resize snaps back on next layout
- Sections with ScrollView-bounded content (Dashboard, Insights)
  "work" because their ideal height is their visible slot
- Resize while in a bounded section looks sticky because the
  rebind target doesn't push back
- Coming back to Chat reasserts the bind and the window grows
  again — sometimes past the screen

Switched to .windowResizability(.contentMinSize). Content's ideal
height is now a minimum FLOOR — user resize works freely, the
window persists across section switches, and it still can't
shrink below a section's minimum render (so tool bars, input
fields, etc. stay visible).

Pre-existing pre-v2.3 bug; v2.3's new content-heavy surfaces
(per-project Sessions list) just made it much more obvious. The
earlier clamp commits stay in — they're still correct for
intra-view layout, just not the window-level fix.

80/80 Swift tests still pass. No test change; behavior is
platform-layout-policy level.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Alan Wizemann
2026-04-24 00:06:57 +02:00
parent 9aad9051c4
commit d9688781ee
+13
View File
@@ -86,6 +86,19 @@ struct ScarfApp: App {
registry.defaultServerID
}
.defaultSize(width: 1100, height: 700)
// Without an explicit resizability, `WindowGroup` defaults to
// `.automatic` which on macOS evaluates to `.contentSize`
// meaning the window is BOUND to its content's ideal size
// rather than bounded-below by it. Any section whose content's
// intrinsic height changes (Chat's message list, the v2.3
// per-project Sessions tab, Insights charts) would resize the
// window on every section switch, snap back against user
// resize, and sometimes push the whole window past the
// screen. `.contentMinSize` turns the content's ideal height
// into a minimum floor: user resize works freely, the window
// stays put across section switches, and it still can't shrink
// smaller than a section's minimum render.
.windowResizability(.contentMinSize)
.commands {
CommandGroup(after: .appInfo) {
Button("Check for Updates…") { updater.checkForUpdates() }