Skip to content

fix(macos): append streamed translation tokens synchronously - #19

Merged
PCcoding666 merged 1 commit into
masterfrom
fix/macos-streaming-translation-race
Oct 10, 2026
Merged

PCcoding666 merged 1 commit into
masterfrom
fix/macos-streaming-translation-race

Conversation

@PCcoding666

Copy link
Copy Markdown
Owner

Summary

Make the final streamed translation contain every token by construction.

OllamaService and TranslationQueue are both @MainActor, and translateStreaming invokes onToken synchronously on the MainActor. TranslationQueue nevertheless wrapped each append in Task { @MainActor in … }, deferring it. Right after translateStreaming returns, the queue builds the final TranslationQueueResult from streamingText — so correctness relied on the executor having run all deferred appends first, which Swift does not guarantee.

  • translateStreaming(onToken:) now takes an @MainActor closure (documented: runs in stream order before the call returns).
  • TranslationQueue appends tokens synchronously; the stale-generation guard is unchanged.

Honest status

This was reported by Qoder while building F10 ("final translation empty when the mock returns instantly"). I could not reproduce an empty translation with the old code — neither with a new queue-level test that delivers content and done in one response, nor through the full view-model path with an instant mock. The change removes the reliance on scheduler ordering rather than fixing an observed failure; the new tests lock in the contract.

Test results

  • ./Scripts/run_tests.sh: 506 tests, 0 failures, no new warnings; CLT build clean.
  • New TranslationQueueStreamingTests: multi-token and single-token streams whose content and done arrive in one response produce the full text.
  • Not verified live in the app: another session was running LCT GUI tests at the same time (its dev-run.sh quit my test instance), so I did not interfere.

🤖 Generated with Claude Code

OllamaService and TranslationQueue are both @mainactor and the token
callback already runs on the MainActor, but TranslationQueue re-enqueued
every append through Task { @mainactor in }. The final result is built from
streamingText right after translateStreaming returns, so its correctness
depended on the executor running the deferred appends first. The callback
is now typed @mainactor and appends synchronously, guaranteeing every token
is in the final result.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 10, 2026 22:14

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@PCcoding666
PCcoding666 merged commit 1e179bd into master Oct 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.

2 participants