uttrflow / uttrflow/uttrflow-swift

Closing onboarding during the model download hides it: no progress anywhere, the model isn't loaded when it lands, and updates never install that session

Open
#670 0 comments 0 reactions 0 assignees View on GitHub
area:general bug P1
Dominant language
Swift
Stars
4
Forks
17
Avg merge
3h 32m
Merged PRs (30d)
277

Description

## What happens

The speech model download (about 600 MB) runs inside the onboarding window. If the user closes that window with its close button while the download is running, several things go wrong at once. All references are on `main`.

1. **The download keeps going, with no progress shown anywhere.** `OnboardingModel.start()` / `press(_:)` run the flow in a `Task` that holds it (`Sources/Uttrflow/Onboarding/OnboardingView.swift:31-44`), and `OnboardingFlow.beginInstall()` awaits the install to the end (`Sources/UttrflowUX/OnboardingFlow.swift:272-301`). Closing the window cancels nothing. The menu bar has a "Setting up… 40%" line for `SpeechModelReadiness.downloading` (`Sources/UttrflowUX/MenuBarPresentation.swift:382-384`), but `AppDelegate` never sets `speechReadiness` to `.downloading` (it is only ever `.notInstalled`, `.loading`, `.ready` or `.loadFailed`, `Sources/Uttrflow/AppDelegate.swift:244-275`). So the menu says "Setup hasn't finished" while 600 MB downloads.
2. **The model is not loaded when it lands.** `onClose` calls `loadSpeechModelIfItArrived()` once, at the moment the window closes (`AppDelegate.swift:364-367`), when the model is not there yet. Nothing calls it when the download completes, so dictation stays unavailable until the next launch.
3. **Updates never install for the rest of the session.** `onClose` does not clear `self.onboarding` (only `onFinish` does, `:359`), and `updateActivity` reports `isOnboarding: onboarding != nil` (`:1337`). `UpdateActivity.isQuiet` is false while `isOnboarding` is true (`Sources/UttrflowUX/UpdateGate.swift:31`), so a downloaded update waits for a quiet minute that never comes.
4. **Reopening setup can start a second download.** "Set Up" (`Sources/UttrflowUX/MainPresentation.swift:197`, `DiagnosticsPresentation.swift:487`) calls `presentOnboarding`, which builds a new flow (`AppDelegate.swift:352-354`) while the first flow's install is still running. `FileSystemSpeechModelStore.install` has no guard against a concurrent install of the same model into the same `.partial` staging directory (`Sources/UttrflowSpeech/SpeechModelStore.swift:139-181`).
5. **No window is left on screen.** At launch the main window is shown only when onboarding is not needed (`AppDelegate.swift:220-222`), so after closing onboarding nothing is on screen until the user thinks to click the Dock or menu bar icon.

## Why it matters

Closing a setup window is a normal thing to do ("I'll finish this later"), especially on a slow connection where the download takes minutes. The user is then left with an app that says setup hasn't finished, downloads in the background with no sign of it, and does not start working even after the download succeeds. On an 8 GB M1 Air on a slow network this can look like the app is broken.

## How to reproduce

1. Remove the installed speech model and the onboarding record (dev bundle).
2. Launch, go through to "Setting things up", and close the window with the red button while the bar is moving.
3. Open the menu bar menu: it says "Setup hasn't finished" with no progress. Watch the model directory under Application Support grow.
4. After it finishes, try to dictate: nothing loads until relaunch.
5. For point 4, click "Set Up" on the Dictation page during step 3 and watch two downloads write into staging.

## Acceptance criteria

- Closing the onboarding window during the download either cancels it (and the menu bar says so) or keeps it visibly running; pick one and document it in `Docs/ux-onboarding.md`.
- While the model downloads, `speechReadiness` is `.downloading(fraction)`, so the menu bar and floating button show progress.
- When a download that outlived its window completes, the model is loaded without a relaunch.
- `onboarding` is cleared however the window closes, so `UpdateActivity.isOnboarding` reflects a window that is actually on screen.
- Only one install of a model runs at a time; a second request joins or waits for the first.
- A test covers the close-mid-download path (the flow and the store both take injected installers/downloads).

Contributor guide

Open the contributing guide

Research direction

Start with the close and install paths in Sources/Uttrflow/Onboarding/OnboardingView.swift, Sources/UttrflowUX/OnboardingFlow.swift, and AppDelegate.swift, then inspect SpeechModelStore.swift and the existing injected-installer tests. Trace the download, readiness, onboarding, and update-state transitions before choosing the documented close behavior; done means progress remains accurate, completion loads the model, reopening cannot duplicate an install, and the close-mid-download test passes.

Written by the indexing model from the issue text.

Assessment

Tech stack
macos, swift
Domain
desktop, documentation, testing-qa
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.