Write unit tests for DictationScopeGuard compliance enforcement
epic-speech-to-text-input-foundation-task-013 — Write thorough unit tests for DictationScopeGuard covering all state transitions: dictation allowed when no session active, dictation blocked when session is active, mid-dictation blocking when session starts during an ongoing dictation, and correct reason codes returned in ScopeGuardResult. Use mocked ActiveSessionState providers to simulate all scenarios without platform dependencies.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 2 - 518 tasks
Can start after Tier 1 completes
Implementation Notes
Use Riverpod's ProviderContainer directly in tests — do not use WidgetTester unless a widget test is explicitly needed. Override the ActiveSessionState provider with a simple StateProvider to drive state changes programmatically. Use package:async's StreamQueue to consume and assert stream events in order. For the disposal test, call container.dispose() and then verify the stream closes (emitsDone).
Group tests logically: 'initial state', 'state transitions', 'mid-session blocking', 'disposal'.
Testing Requirements
All tests are pure unit tests using flutter_test and Riverpod's ProviderContainer. Mock ActiveSessionState using a StateProvider
Aim for 100% branch coverage of DictationScopeGuard logic.
iOS 15 on-device speech recognition has a 1-minute session limit and requires network fallback for longer sessions. Peer mentor way-forward dictation may routinely exceed this limit, causing silent truncation of transcribed content without user feedback.
Mitigation & Contingency
Mitigation: Implement session-chunking logic in NativeSpeechApiBridge that automatically restarts recognition before the limit is reached, preserving continuity via partial concatenation. Document the iOS 15 vs iOS 16 on-device recognition behaviour difference in code comments.
Contingency: If chunking causes user-visible interruptions, surface a non-blocking informational banner on iOS 15 devices informing users that very long dictation sessions may need to be broken into segments, and use PartialTranscriptionRepository to persist each chunk immediately.
On iOS, speech recognition permission can only be requested once. If the user denies the permission, the app cannot re-request it. A poor first-impression permission flow will permanently disable dictation for those users, impacting the Blindeforbundet blind-user base who rely on dictation most.
Mitigation & Contingency
Mitigation: Design the NativeSpeechApiBridge permission flow to show a clear pre-permission rationale screen before the OS dialog. Implement a graceful degradation path that hides the microphone button and shows a settings deep-link when permission is permanently denied.
Contingency: If users have already denied permission before the rationale screen is added, provide a settings deep-link in DictationScopeGuard's denial message directing users to iOS Settings > Privacy > Speech Recognition to re-enable manually.
The approved field IDs and screen routes configuration in DictationScopeGuard may fall out of sync with the actual report form schema as new fields are added by org administrators, silently blocking dictation on legitimately approved fields.
Mitigation & Contingency
Mitigation: Source the approved field configuration from the same org-field-config-loader used by the report form, rather than a hardcoded list. Add a developer-time assertion that logs a warning when a dictation-eligible field type is rendered but not in the approved routes map.
Contingency: Provide a runtime override mechanism in the scope guard that coordinators or admins can use to temporarily whitelist a field ID while the config is updated, with an automatic expiry.