high priority low complexity backend pending backend specialist Tier 6

Acceptance Criteria

dispose() is safe to call from any state: idle, recording, or stopping — no exception thrown in any case
Calling dispose() twice in a row produces no error and no duplicate bridge cancellation calls
dispose() cancels any in-flight NativeSpeechApiBridge operation before closing the StreamController
dispose() closes the StreamController only if it is not already closed
After dispose(), all internal state flags are reset to their initial values (same as post-construction state)
After dispose(), calling startListening() throws a DisposedException (service is not reusable after dispose)
Microphone resource is released — verified by platform not showing mic indicator after dispose completes
dispose() logs lifecycle events at DEBUG level: 'SpeechRecognitionService.dispose() called', 'session cancelled', 'stream closed'
dispose() is synchronous from the caller's perspective (returns void, not Future) — internal async cleanup completes detached

Technical Requirements

frameworks
Flutter
Dart async
speech_to_text package
apis
NativeSpeechApiBridge.cancelRecognition()
StreamController.close()
SpeechToText.cancel()
data models
_SpeechSessionState
_isDisposed: bool flag
performance requirements
dispose() must not block the calling isolate — fire-and-forget async cleanup is acceptable
Microphone release must complete within 500ms of dispose() call
security requirements
Any partially captured audio data must be discarded immediately on dispose
No transcript data retained in memory after dispose completes

Execution Context

Execution Tier
Tier 6

Tier 6 - 158 tasks

Can start after Tier 5 completes

Implementation Notes

Implement a private bool _isDisposed = false flag checked at the top of every public method. dispose() pattern: (1) set _isDisposed = true, (2) if recording, call bridge.cancelRecognition() unawaited (fire-and-forget to avoid blocking), (3) if !_controller.isClosed, close _controller, (4) reset _sessionState to idle, (5) log lifecycle. Use Dart's debugPrint() or an injectable Logger interface (prefer injectable for testability). The key design constraint is dispose() must be void not Future — this follows Flutter's Disposable convention and prevents callers needing to await disposal.

For BLoC integration, the Cubit/Bloc that owns this service should call dispose() in its own close() override. Note: after dispose(), the service should NOT be restarted — construct a new instance. Document this in the class-level dartdoc.

Testing Requirements

Unit tests (flutter_test): dispose from idle — verify no bridge calls except cancel (which is no-op); dispose from recording — verify bridge cancel called, stream closed, state reset; double dispose — verify no exception and no double bridge cancel; startListening after dispose — verify DisposedException; verify log messages emitted (use a captured log output or injectable logger). All tests with mocked NativeSpeechApiBridge.

Component
Speech Recognition Service
service high
Epic Risks (2)
medium impact medium prob technical

The speech_to_text Flutter package delegates accuracy entirely to the OS-native engine. Norwegian accuracy for domain-specific vocabulary (medical terms, organisation names, accessibility terminology) may fall below the 85% acceptance threshold on older devices or in noisy environments, causing user frustration and manual correction overhead that negates the time saving.

Mitigation & Contingency

Mitigation: Configure the SpeechRecognitionService with Norwegian as the explicit locale and test against a representative corpus of peer mentoring vocabulary on target devices. Expose locale switching so users can fallback to Bokmål vs Nynorsk. Clearly set user expectations in the UI that transcription is a starting point for editing, not a finished product.

Contingency: If accuracy is consistently below threshold on specific device/OS combinations, add a device-capability check that hides the dictation button with an explanatory message rather than offering a degraded experience. Document affected device models for QA and org contacts.

medium impact low prob dependency

The speech_to_text Flutter package is a third-party dependency that may introduce breaking API changes or deprecations on major version upgrades, requiring rework of SpeechRecognitionService when Flutter or platform OS versions are updated.

Mitigation & Contingency

Mitigation: Wrap all speech_to_text API calls behind the SpeechRecognitionService interface so that package changes are isolated to one file. Pin the package version in pubspec.yaml and review changelogs before any upgrade. Write integration tests that exercise the package contract so regressions are caught immediately.

Contingency: If the package is abandoned or has unresolvable issues, NativeSpeechApiBridge already provides the platform-channel abstraction needed to implement a direct plugin replacement with minimal changes to SpeechRecognitionService.