critical priority medium complexity frontend pending frontend specialist Tier 2

Acceptance Criteria

SemanticsWrapperWidget accepts a required `child` widget parameter
Widget accepts optional `label` (String) parameter mapped to Semantics.label
Widget accepts optional `hint` (String) parameter mapped to Semantics.hint
Widget accepts a `role` enum parameter (button, textField, image, header, link, tab, slider, checkbox, radio, switch, listItem) that sets the correct Semantics flags
Widget accepts a `state` parameter object with optional fields: enabled (bool), checked (bool), selected (bool), expanded (bool), readOnly (bool)
Widget accepts an `excludeSemantics` (bool) parameter that wraps child in ExcludeSemantics when true
When `excludeSemantics` is true, the child is wrapped in ExcludeSemantics and no Semantics widget is applied
All WCAG 2.2 AA naming conventions are followed: labels are concise, non-redundant, and describe the purpose not the type
Widget renders identically to its child in visual output; semantics are additive only
Widget compiles without warnings and is exported from the accessibility library barrel file
Widget is documented with dartdoc comments on all parameters

Technical Requirements

frameworks
Flutter
Riverpod
apis
Flutter Semantics widget
ExcludeSemantics widget
SemanticsProperties
data models
SemanticRole (enum)
SemanticState (value object)
AccessibilitySettings
performance requirements
Widget adds zero rendering overhead when excludeSemantics is true
Widget rebuild cost is O(1); no expensive computations in build()
security requirements
Labels must not expose sensitive data (names, medical info) in plain text to the semantics tree; defer to SensitiveFieldConfigurationRegistry for flagged fields
ui components
SemanticsWrapperWidget
SemanticRole enum
SemanticState class

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

Define a SemanticRole enum in a shared enums file (e.g., lib/accessibility/semantic_role.dart). Map each role to the appropriate SemanticsProperties flags using a switch expression for exhaustive coverage. Define SemanticState as an immutable value class (use @immutable and const constructor) with nullable bool fields, defaulting to null (unset) rather than false to avoid overriding Flutter's own semantic state. The widget itself should be a StatelessWidget.

The build method should return ExcludeSemantics(child: child) when excludeSemantics is true, or Semantics(..., child: child) otherwise. Do not read from Riverpod providers in this task — that is added in task-010. Keep this widget purely prop-driven.

Testing Requirements

Widget tests using flutter_test and SemanticsController (tester.semantics). Verify: (1) Semantics.label is set correctly from the label parameter, (2) Semantics.hint is set from hint parameter, (3) each SemanticRole value maps to the correct SemanticsProperties flags (e.g., role: button → isButton: true), (4) SemanticState fields map to the correct flags (e.g., state.checked → isChecked), (5) ExcludeSemantics is applied when excludeSemantics: true and no Semantics widget is in the tree, (6) child renders correctly in all configurations. Use SemanticsHandle via tester.ensureSemantics() to enable the semantics tree during tests.

Component
Semantics Wrapper Widget
ui medium
Epic Risks (2)
high impact medium prob technical

Flutter's SemanticsService behaves differently between iOS (VoiceOver) and Android (TalkBack) in edge cases — e.g., announcement queuing, focus-gain timing, and attribute support. If the facade does not correctly abstract these differences, announcements may be silent or misfired on one platform, causing regression on the other platform to go unnoticed until device testing.

Mitigation & Contingency

Mitigation: Write platform-divergence unit tests early using SemanticsServiceFacade mocks. Validate announcement delivery on a physical iPhone (VoiceOver) and Android device (TalkBack) at the end of each sprint. Document known platform differences in the facade's inline API comments.

Contingency: If a platform difference cannot be abstracted cleanly, expose a platform-specific override path in the facade and implement targeted workarounds per platform, accepting the added complexity in exchange for correct behaviour.

medium impact medium prob scope

Accessibility preferences stored in local storage may need new fields as higher-tier epics are implemented (e.g., announcement verbosity, sensitive-field guard toggle). Schema changes to an already-persisted store risk data migration failures or silent defaults on existing installs, breaking user preferences.

Mitigation & Contingency

Mitigation: Design the AccessibilitySettingsRepository with a versioned JSON schema from the start, using merge-with-defaults on read so new fields fall back gracefully. Define the full expected field list upfront based on all downstream epic requirements before writing the first record.

Contingency: If migration fails on a live install, fall back to full reset-to-defaults with a one-time in-app notification informing the user that accessibility preferences have been reset and inviting them to reconfigure.