high priority low complexity frontend pending frontend specialist Tier 2

Acceptance Criteria

Warning banner appears when BLoC emits AggregationWarning — shows deduplicationAnomalyCount and anomalyDescription text
Warning banner is dismissible by the user via a close button — dismissal hides the banner without changing BLoC state
After dismissal, if a new AggregationWarning is emitted (e.g., after retry), the banner reappears
Warning banner uses the design token warning colour (amber/yellow family) with WCAG 2.2 AA compliant text contrast
Warning banner is announced to screen readers via a Semantics live region (liveRegion: true) so it is read aloud without user focus
Error state renders a retry button when BLoC emits AggregationFailed
Retry button label is localised and clearly describes the action (e.g., 'Try again')
Tapping retry dispatches RetryAggregation event to the BLoC
Retry button is accessible: has a Semantics label, meets 44x44dp minimum touch target size
Error message from AggregationFailed.errorMessage is displayed above the retry button in a human-readable format
Both warning banner and error state dismiss/hide correctly when BLoC transitions to AggregationInProgress (i.e., retry started)
Widget snapshot tests cover: warning visible, warning dismissed, error with retry button visible

Technical Requirements

frameworks
flutter
bloc
flutter_bloc
data models
AggregationWarning
AggregationFailed
RetryAggregation
performance requirements
Banner show/hide must use AnimatedVisibility or similar — no layout jumps
Banner animation must complete in 200ms or less
security requirements
Error messages displayed to the user must be sanitised — no raw exception messages, stack traces, or database error codes
Anomaly descriptions must not reveal internal deduplication logic that could be used to infer individual participant data
ui components
_DeduplicationWarningBanner (private widget, dismissible)
_AggregationErrorView (private widget with retry button)

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

Use BlocConsumer or BlocBuilder with a buildWhen condition to handle the warning banner visibility state locally within the widget — track a local `_warningDismissed` bool in a StatefulWidget wrapper. Reset `_warningDismissed` to false whenever a new AggregationWarning is received so the banner reappears after retries. For the live region announcement, wrap the warning banner content in `Semantics(liveRegion: true, child: ...)` — Flutter's VoiceOver and TalkBack implementations will announce liveRegion widgets when they appear or change. Keep the close button as an IconButton with Icons.close and an explicit Semantics label ('Dismiss warning').

The retry button should call `context.read().add(RetryAggregation())` — it does not need to call `AggregationFailed.onRetry` directly; the BLoC handles the retry logic. Ensure the minimum touch target (44x44dp) by wrapping in a SizedBox with constraints if the IconButton is too small.

Testing Requirements

Widget tests using flutter_test. Test cases: (1) emit AggregationWarning — banner appears with correct anomaly count and description; (2) tap dismiss button — banner hides; (3) emit another AggregationWarning after dismiss — banner reappears; (4) emit AggregationFailed — error message and retry button appear; (5) tap retry button — RetryAggregation event is dispatched to the BLoC (verify via MockBloc); (6) emit AggregationInProgress after AggregationFailed — retry button and error message hide; (7) Semantics test confirming liveRegion is true on the warning banner container. Use MockBloc from bloc_test package to capture dispatched events.

Epic Risks (2)
medium impact high prob scope

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.

medium impact medium prob technical

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.