WCAG 2.2 AA accessibility audit for both components
epic-bufdir-data-aggregation-ui-task-007 — Audit both AggregationProgressIndicator and AggregationSummaryWidget against WCAG 2.2 AA requirements: verify contrast ratios for all text and icon states (active, completed, pending, warning, error), add Semantics wrappers with descriptive labels for all interactive and status elements, ensure focus order is logical, verify that all dynamic state changes are announced via live regions, and confirm minimum touch target sizes (44ร44pt). Fix all identified violations.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 4 - 323 tasks
Can start after Tier 3 completes
Implementation Notes
Approach the audit in two phases: (1) automated โ write flutter_test semantics assertions first to catch regressions; (2) manual โ use Xcode Accessibility Inspector or Android TalkBack to validate real screen reader behavior. For contrast ratio verification, extract all color token values from the design system and run them through contrast ratio calculation (luminance formula: WCAG 2.1 ยง1.4.3). Common Flutter accessibility pitfalls to check: IconButton default touch target is 48ร48 (fine), but custom GestureDetector tap areas may be smaller โ wrap with ConstrainedBox(constraints: BoxConstraints(minWidth: 44, minHeight: 44)). For liveRegion announcements, ensure the Semantics container wrapping dynamic content has liveRegion: true AND is a direct ancestor of the content that changes.
Note: VoiceOver on iOS has known quirks with Flutter Semantics โ test on a real device or simulator, not just flutter_test. The amber warning color needs special attention โ amber on white commonly fails AA at smaller text sizes.
Testing Requirements
Accessibility tests using flutter_test SemanticsHandle: (1) enable semantics with tester.ensureSemantics(); (2) assert SemanticsNode labels for all progress stage indicators in active, completed, pending, error states; (3) assert liveRegion is true on dynamic state containers; (4) assert touch target sizes using tester.getSize() โ minimum Size(44, 44); (5) assert decorative icons have excludeSemantics or empty label. Manual audit step: use Flutter accessibility inspector in DevTools and VoiceOver (iOS simulator) to walk through both widgets in all BLoC states. Document each WCAG criterion result in the PR description. Include results for both light and dark themes.
For NHF with 1,400 local chapters, rendering a geographic breakdown as a flat list in the AggregationSummaryWidget would produce an unscrollable wall of data that is unusable on a mobile screen. Coordinators need to verify geographic completeness before export, but the raw chapter list is too long to review.
Mitigation & Contingency
Mitigation: Design the geographic distribution section as a collapsible two-level hierarchy: regions are shown expanded by default with their aggregate count, individual chapters are collapsed under each region and expandable on tap. Show only non-zero regions by default with a 'show empty regions' toggle.
Contingency: If the hierarchical display is too complex to implement before the submission deadline, fall back to a region-only summary view with a total count of active chapters per region and a note that chapter-level detail is available in the full export file.
The aggregation BLoC must handle a multi-stage async pipeline with partial success states, warning accumulation across stages, and retry logic for individual failed stages. If the state model is too simplistic (e.g., loading/success/error), warning states and partial results will be lost on retry, confusing coordinators who see warnings disappear and reappear.
Mitigation & Contingency
Mitigation: Model the BLoC state as a rich sealed class hierarchy: AggregationIdle, AggregationRunning(stage, completedStages, accumulatedWarnings), AggregationComplete(result, warnings), AggregationFailed(failedStage, accumulatedWarnings, error). Accumulated warnings persist across retry attempts so coordinators see the full warning history.
Contingency: If state management complexity causes repeated bugs near the deadline, simplify to a single AggregationResult value object that captures success, warnings, and error as nullable fields, and drive both UI components from that single object rather than a live BLoC stream.