high priority medium complexity frontend pending frontend specialist Tier 4

Acceptance Criteria

Search field is wrapped in a Semantics widget with a descriptive label (e.g., 'Search chapters') readable by VoiceOver and TalkBack
Each chapter list item announces its combined chapter name and affiliation status (e.g., 'Oslo chapter, Active') as a single merged semantics node
End Affiliation button has both a Tooltip with descriptive text and a Semantics widget with label and hint properties set
The maximum-chapters-exceeded banner is rendered with liveRegion: true so screen readers announce it automatically when it appears
All interactive touch targets (buttons, list items, search field) measure at least 44×44 logical pixels; verified programmatically via RenderBox.size in tests
Flutter accessibility inspector (flutter analyze --flutter-help) reports zero accessibility warnings for ChapterAssignmentEditor
Tab/focus order traverses: search field → chapter list items top-to-bottom → End Affiliation buttons → banner in logical reading order
ExcludeSemantics is applied to purely decorative icons and dividers to reduce screen reader noise
All semantic labels are in the correct locale language (Norwegian) matching the org labels system
No regression in existing widget behavior after semantics annotations are applied

Technical Requirements

frameworks
Flutter
flutter_test
BLoC
data models
ChapterAffiliation
ChapterAssignmentState
performance requirements
Semantics tree construction must not add measurable frame time overhead (target: <1ms additional per frame)
List items with Semantics must not trigger unnecessary rebuilds — use const constructors where possible
security requirements
Semantic labels must not expose internal IDs or raw database values to assistive technology output
ui components
Semantics widget (Flutter core)
Tooltip widget (Flutter core)
MergeSemantics widget for combined list-item labels
ExcludeSemantics widget for decorative elements
SizedBox / ConstrainedBox for minimum touch target enforcement (44×44 logical px)

Execution Context

Execution Tier
Tier 4

Tier 4 - 323 tasks

Can start after Tier 3 completes

Implementation Notes

Use MergeSemantics sparingly — prefer setting label/hint directly on the outermost GestureDetector or InkWell. For the live region banner, wrap the AnimatedSwitcher or Visibility widget with Semantics(liveRegion: true, label: bannerText) and rebuild the node when the banner appears so TalkBack/VoiceOver announces it. For 44×44 touch targets, prefer setting minimumSize on ButtonStyle or wrapping with SizedBox(width: 44, height: 44) rather than adding padding, to avoid layout shifts. Use the debugSemantics flag during development: flutter run --dart-define=SEMANTICS_DEBUG=true.

Check the Flutter accessibility inspector in DevTools (Semantics tab) after each annotation pass. Be careful not to double-announce interactive state — if BLoC already provides status text in the list item label, do not also set value: on the Semantics node.

Testing Requirements

Widget tests using flutter_test and SemanticsChecker.check() must pass with zero warnings for the ChapterAssignmentEditor widget tree. Write a test that pumps ChapterAssignmentEditor, calls tester.ensureSemantics(), and asserts: (1) a node with label containing 'Search chapters' exists, (2) each chapter item node merges name + status, (3) End Affiliation button nodes have non-empty hint, (4) the max-chapters banner node has liveRegion set. Use tester.tap() on each interactive element and assert no exception is thrown for touch target size. Run flutter test --coverage and ensure the semantics annotation code paths reach >90% coverage.

Component
Chapter Assignment Editor
ui medium
Epic Risks (3)
high impact medium prob technical

The Duplicate Activity Warning Dialog must announce itself to VoiceOver and TalkBack immediately on appearance. Flutter's default modal semantics do not guarantee focus shift to the dialog on all platform versions, risking silent appearance for screen reader users — a WCAG 2.2 failure.

Mitigation & Contingency

Mitigation: Wrap the dialog content in a Semantics node with liveRegion: true and explicitly request focus via FocusScope.of(context).requestFocus() on the dialog's primary action button in the post-frame callback. Test on physical iOS (VoiceOver) and Android (TalkBack) devices, not only simulators.

Contingency: If automatic focus fails on a specific platform version, add a platform-specific fallback using SemanticsService.announce() to force a live region announcement of the dialog's headline text.

medium impact medium prob technical

The Chapter Membership Cubit tracks pending changes before commit to support the two-step add/confirm flow. If the user navigates away mid-edit or the app is backgrounded, uncommitted pending state could be replayed incorrectly on return, causing phantom affiliation additions or removals.

Mitigation & Contingency

Mitigation: Design the Cubit to hold pending changes only in transient in-memory state with no persistence. On any navigation-away event, emit a reset state that discards pending changes. Prevent accidental navigation during an active edit by showing a discard-changes confirmation dialog.

Contingency: If state desync is reported in production, add an explicit state reconciliation step in the Cubit's onResume handler that re-fetches the authoritative affiliation list from the repository and resets all pending state before re-rendering.

medium impact high prob technical

The Chapter Assignment Editor's searchable chapter list must load quickly. If the organisation has hundreds of chapters (NHF has 1,400 local chapters) and the full list is fetched on dialog open, the editor will be slow to display and the search will be sluggish.

Mitigation & Contingency

Mitigation: Scope the chapter list to only chapters within the coordinator's administrative scope (not all 1,400), leveraging the existing hierarchy access scope service. Implement server-side search with a minimum 2-character threshold and debounce to avoid excessive Supabase queries.

Contingency: If the scoped list is still too large, add local caching of the chapter list with a 15-minute TTL and an explicit refresh button, ensuring the editor is always responsive even on poor network conditions.