Skip to content

Sidebar Command/Rewrite record buttons bypass ASR arbitration #760

Description

@shreeraman96

Summary

The sidebar Command Mode and Rewrite Mode pages start the shared ASRService directly, with no check that a file transcription is running and no dictation-intent claim. Two entry points therefore sit outside the arbitration that every other start path goes through.

// Sources/Fluid/Views/CommandModeView.swift:596
Task { await self.asr.start() }

// Sources/Fluid/Views/RewriteModeView.swift:265
Task { await self.asr.start() }

Repro

  1. Drop audio files so a transcription is running.
  2. Navigate to the Command Mode (or Rewrite Mode) page in the sidebar.
  3. Press the page's record button.

Both drive the shared ASR model concurrently. Either transcription can fail or return corrupted output.

Pre-existing, not introduced by #716

Both lines are unchanged on main at the same line numbers, and neither view is touched by #716. MeetingTranscriptionService.transcribeFile already used asrService.fileTranscriptionProvider on main, so the conflict was reachable before batching existed.

Filing it because #716 makes it materially easier to hit — a batch keeps the model busy far longer than a single file — and because #716 adds arbitration (FileTranscriptionSession, the isBatchTranscribing guards, the dictation-intent flag) that these two sites silently opt out of. Anyone reading that PR would reasonably assume the case is covered.

Fix

The straightforward version is the guard the hotkey paths already use, plus an intent claim so the batch's wait loop sees it:

guard !FileTranscriptionSession.isBatchTranscribing else { /* blocked feedback */ return }

The better version is what two independent reviews of #716 both recommended: a single canBeginRecording() gate used by every start site. The condition is currently duplicated across startRecording, beginDictationRecording, commandModeCallback and rewriteModeCallback in three different orderings, with four copies of notifyDictationBlockedByBatch(). That duplication is why these two sites were missed, and why a guard-ordering bug (fixed in #716, d2dd76d) was possible in the first place.

Note notifyDictationBlockedByBatch() is private to ContentView, so the shared gate needs it moved somewhere both views can reach.

Residual window

Even with the guard, a start racing a batch start can slip through between the check and asr.isRunning flipping true. That is the window beginDictationIntent() exists to close, so the sidebar sites should claim intent too — with matching release on every termination path, per the bug fixed in ebe47e7.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions