Add live-region screen reader announcements to banner
epic-bufdir-report-preview-ui-components-task-009 — Integrate Flutter SemanticsService and live region semantics into BufdirValidationSummaryBanner so that when the validation data changes (new errors or warnings appear or are resolved), screen readers announce the updated counts automatically. Use SemanticsProperties.liveRegion with assertive priority for error changes and polite for warning changes, following WCAG 2.2 AA live region guidance.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 4 - 323 tasks
Can start after Tier 3 completes
Implementation Notes
Flutter's SemanticsService.announce() is the correct cross-platform API for screen reader interrupts — do not use platform channels directly. Use ref.listen
Test on real device if possible: iOS Simulator VoiceOver and Android Emulator TalkBack both support announcement testing but may differ from physical device behavior. Document any platform-specific quirks in code comments.
Testing Requirements
Widget tests using flutter_test semantics testing APIs: (1) verify SemanticsNode with liveRegion: true exists in tree when banner is visible; (2) use tester.pumpAndSettle and SemanticsController to assert label updates after provider state change; (3) inject a mock SemanticsService to verify announce() is called with correct string and assertiveness level on error count increase; (4) verify no announcement on initial mount with empty data; (5) verify equality guard: pumping identical state twice results in single announcement. Run tests with tester.ensureSemantics() enabled. Manual VoiceOver/TalkBack verification required before task sign-off.
Implementing the tap-to-scroll-and-focus behavior from the validation banner to a specific field row in a long scrollable list is complex in Flutter. If focus management is incorrectly implemented, VoiceOver users who navigate to the banner and select an issue will not be moved to the relevant field row, breaking the accessibility workflow and violating WCAG 2.4.3 (Focus Order).
Mitigation & Contingency
Mitigation: Use BufdirAccessibilityUtils focus management utilities (built in the foundation epic) with explicit GlobalKey-based scroll anchors on each field row. Test with a real iOS device running VoiceOver during widget development, not only in the Flutter accessibility inspector.
Contingency: If programmatic scroll-to-focus cannot be reliably achieved before the TestFlight deadline, fall back to a navigation approach where tapping a banner issue opens a modal detail sheet for that field row rather than scrolling in place, and file a follow-up ticket for the inline scroll implementation.
The validation summary banner must reactively update its issue count as underlying aggregated data changes (e.g., if the coordinator has navigated away and data was refreshed). If the banner's Riverpod provider is not correctly scoped, it may display stale issue counts or fail to disappear when all issues are resolved, eroding coordinator trust in the validation system.
Mitigation & Contingency
Mitigation: Drive the banner exclusively from the same Riverpod provider that powers the full preview model — do not maintain a separate local state for issue counts. Write a widget test that simulates a data refresh mid-review and asserts the banner updates within one frame.
Contingency: If stale state reaches production, add a manual refresh button to the banner as a short-term workaround while the provider scoping is corrected in the next release cycle.