Skip to content

Fix empty worktree list on first launch - #52

Merged
sapsaldog merged 1 commit into
mainfrom
fix/cold-start-empty-worktree-list
Jun 10, 2026
Merged

sapsaldog merged 1 commit into
mainfrom
fix/cold-start-empty-worktree-list

Conversation

@sapsaldog

Copy link
Copy Markdown
Owner

Problem

On first launch, the main window shows "No Worktrees" (0 count) for the selected repository. Switching to another repository loads the list correctly.

Root cause

A cold-start ordering bug between three pieces that are individually correct:

  1. At launch, AppDelegate.observeSelectedRepository() syncs worktreeViewModel.repository to the restored selection — intentionally without loading worktrees (the status menu loads lazily; pinned by selectedRepoDoesNotEagerLoadWorktrees).
  2. When the main window later opens, ContentView's .task only loaded the list when worktreeViewModel.repository == nil — but step 1 already set it, so the initial load was skipped.
  3. .onChange(of: selectedRepository) never fired either, because the selection happened before the view appeared.

Net effect: nothing ever loads the list until the user changes repositories. repository != nil does not imply the list has been loaded — the .task guard assumed it does.

Fix

  • New WorktreeListViewModel.windowAppeared(selectedRepository:): always syncs the current selection and reloads when the window content appears.
  • ContentView's .task delegates to it instead of the nil-guarded load.
  • The AppDelegate sync contract is unchanged.

Testing

  • 3 new regression unit tests, including the key case: repository pre-synced (cold-start state) → windowAppeared must still load.
  • Red→green was demonstrated against the real bug with a temporary window-hosting integration test: with the old ContentView wiring it times out (list stays empty for 5s after the window opens); with the fix it loads in ~0.2s. The integration test is not kept: AppDelegateColdStartTests has a pre-existing flaky AppKit _NSWindowTransformAnimation over-release crash (crash reports pre-date this change) that any added window-lifecycle test destabilizes — suite hardening is tracked separately.
  • swiftlint lint clean, full suite (446 tests) green 3× consecutively, scripts/coverage.sh gate passes.
  • Manually verified: worktrees now load on first launch.

🤖 Generated with Claude Code

On cold start the AppDelegate selection observer syncs
worktreeViewModel.repository before any window exists, intentionally
without loading worktrees (the status menu loads lazily). ContentView's
initial-load task then skipped loading because repository was already
non-nil, and onChange never fired since the selection happened before
the view appeared — so the main window opened with an empty list until
the user switched repositories.

Replace the nil-guarded load with WorktreeListViewModel.windowAppeared,
which always syncs the current selection and reloads when the window
content appears. Add regression unit tests covering the pre-synced
cold-start state.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@sapsaldog
sapsaldog merged commit 88ff4ae into main Jun 10, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant