critical priority medium complexity testing pending testing specialist Tier 4

Acceptance Criteria

A written audit report is produced listing every WCAG 2.2 AA criterion checked, result (pass/fail/na), and severity for each violation
All critical and serious violations are fixed before epic sign-off; moderate and minor violations are documented in backlog issues
VoiceOver (iOS): all form fields announce their label when focused; required fields are announced as 'required'; error messages are announced immediately when they appear
TalkBack (Android): same as VoiceOver — label, required, and error announcements verified
Speech recording state change (idle → recording → processing) is announced via live region (SemanticsProperties.liveRegion) — verified on both platforms
Focus order follows top-to-bottom visual order through all fields; verified by navigating the full form with VoiceOver and TalkBack swipe navigation only
No keyboard trap: focus can always exit the SpeechToTextFieldOverlay and WayForwardAddEditBottomSheet using the standard system back gesture or escape equivalent
All interactive elements (buttons, fields, chips, badges) have a tappable area of at least 44×44 dp — verified via Flutter widget test tester.getSize()
All text elements have a contrast ratio ≥4.5:1 against their background (verified using a color contrast analyzer tool with design token values)
Large text (≥18pt or ≥14pt bold) has contrast ratio ≥3:1
No information is conveyed by color alone — status badges include a text label alongside the color
The audit covers all 8 field types rendered by DynamicFieldRenderer, the WayForwardSectionWidget, and the SpeechToTextFieldOverlay

Technical Requirements

frameworks
Flutter
flutter_test (Semantics assertions)
VoiceOver (iOS)
TalkBack (Android)
apis
Flutter Semantics API
SemanticsProperties.liveRegion
security requirements
Audit must verify that sensitive field labels (e.g., health status fields) announce only the label and not the value when navigated by screen reader, respecting user privacy
ui components
DynamicFieldRenderer (all 8 field type variants)
WayForwardSectionWidget
WayForwardItemCard
WayForwardAddEditBottomSheet
SpeechToTextFieldOverlay

Execution Context

Execution Tier
Tier 4

Tier 4 - 323 tasks

Can start after Tier 3 completes

Implementation Notes

This task is split: ~3h audit (device + automated) and ~5h fixing violations. Common Flutter accessibility pitfalls to check: (1) Icon buttons missing Semantics label — fix with Semantics(label: '...', child: IconButton(...)). (2) Custom widgets not inheriting Semantics from children — fix by ensuring MergeSemantics or ExcludeSemantics is used correctly. (3) Live region not firing — in Flutter, set SemanticsProperties(liveRegion: true) on the container that changes, not a static parent.

(4) Bottom sheet focus trap: verify that FocusScope wraps the sheet and that the first focusable element receives focus on open. (5) Color contrast: check design token values for error red, status badge colors, and placeholder text against all background colors using the WebAIM contrast checker. For the Blindeforbundet-specific requirement: recording state announcements are especially critical — this organization has visually impaired users for whom VoiceOver is primary input.

Testing Requirements

Two-track testing: (1) Automated: flutter_test Semantics assertions verifying every field has a non-empty label, error fields have error semantics set, live region is present on recording state widget. Use tester.getSemantics(find.byType(X)) and verify SemanticsData properties. (2) Manual: device testing on a physical iPhone (VoiceOver) and physical Android (TalkBack). Use a structured manual test script covering: full form navigation, error state navigation, overlay focus trap check, and recording state announcement.

Document manual test results in a checklist. Both tracks must pass before task closure.

Component
Dynamic Field Renderer
ui high
Dependencies (3)
Implement the multi-entry way-forward section UI widget. Render a scrollable list of WayForwardItem cards with add, edit, and remove actions. Each item card shows action text, optional assignee chip, and status badge. Include an Add Item bottom sheet with a text field supporting speech-to-text input via SpeechToTextFieldOverlay. Apply WCAG 2.2 AA: all interactive elements have 44×44dp touch targets, semantic labels, and focus order. Wire to WayForwardTaskService via the form orchestrator. epic-structured-post-session-report-form-engine-task-011 Implement the per-field microphone trigger overlay widget. Render a microphone IconButton that transitions through idle, listening (animated waveform), processing, and error states. Display partial transcription in a floating preview card above the field. Announce recording state transitions via Flutter Semantics live regions for WCAG 2.2 AA compliance. Tap outside or press ESC to cancel recording. On final transcription, invoke onTranscribed callback to fill the parent field. epic-structured-post-session-report-form-engine-task-009 Implement the core dynamic field renderer that maps a FieldConfig schema object to the appropriate Flutter widget at runtime. Support all field types: TextField (single/multi-line), CheckboxListTile, RadioGroup, DropdownButton, NumberField, DatePicker, and WayForwardSectionWidget. Each rendered field must include a SpeechToTextFieldOverlay trigger, proper Semantics label derived from field schema, and error text display bound to ValidationResult. Read current value and onChange from the form orchestrator state. Apply org-specific field visibility and ordering from OrgFieldConfigLoader. epic-structured-post-session-report-form-engine-task-012
Epic Risks (3)
high impact medium prob technical

Dynamically rendered form fields built from runtime JSON schema are significantly harder to make accessible than statically declared widgets — Flutter's Semantics tree must be correct for every possible field type and every validation state. Failures here block the entire feature for Blindeforbundet's visually impaired peer mentors.

Mitigation & Contingency

Mitigation: Define WCAG 2.2 AA semantics requirements for each field type before implementation and write widget tests using Flutter's SemanticsController for every type. Include a real-device VoiceOver test session in the acceptance gate for this epic before marking it done.

Contingency: If dynamic semantics prove too difficult to get right generically, implement field-type-specific Semantics wrappers (one per supported field type) instead of a single generic renderer, accepting slightly more code duplication in exchange for reliable accessibility.

high impact medium prob technical

The report-form-orchestrator must manage a complex state machine — schema loading, draft persistence, per-field validation, submission retries, and error recovery — across multiple async operations. Incorrect state transitions could result in lost user data, double submissions, or UI freezes.

Mitigation & Contingency

Mitigation: Define all Bloc states and events explicitly as sealed classes before writing any logic. Use a state machine diagram reviewed by the team before implementation. Write exhaustive Bloc unit tests covering every state transition, including concurrent events and network interruption mid-submission.

Contingency: If Bloc complexity becomes unmanageable, extract draft persistence into a separate DraftManagerCubit and keep report-form-orchestrator focused solely on the submit workflow. The additional granularity makes each component independently testable.

medium impact low prob scope

Organisations may require field types beyond the five currently specified (text, multiline, checkbox group, radio, date). If a new type is discovered during pilot testing, the dynamic-field-renderer must be extended, potentially requiring changes across multiple layers.

Mitigation & Contingency

Mitigation: Design dynamic-field-renderer as a registry of field-type renderers with a clear extension point. Document the pattern for adding a new field type so that it can be done in one file without touching existing renderers.

Contingency: If an unhandled field type is encountered at runtime, dynamic-field-renderer renders a labelled plain-text fallback widget and logs a warning so the missing type is surfaced in monitoring, preventing a crash while making the gap visible.