Scaffold WcagSemanticsLabelResolver class
epic-dynamic-terminology-and-labels-ui-and-accessibility-task-005 — Create the WcagSemanticsLabelResolver as a Flutter infrastructure component (plain Dart class or StatelessWidget wrapper) that accepts a labelKey for the semantics label, an optional hintKey for the hint, and a child widget. Define the public API and stub the resolution logic, preparing for integration with the OrganizationLabelsNotifier.
Acceptance Criteria
Technical Requirements
Implementation Notes
Prefer ConsumerWidget over StatelessWidget from the start — retrofitting Riverpod onto a StatelessWidget later requires adding the `ref` parameter to build(), which is a breaking API change for callers. The scaffold pattern: `class WcagSemanticsLabelResolver extends ConsumerWidget { const WcagSemanticsLabelResolver({super.key, required this.labelKey, this.hintKey, required this.child}); final String labelKey; final String? hintKey; final Widget child; @override Widget build(BuildContext context, WidgetRef ref) { return Semantics(label: labelKey, hint: hintKey, child: child); } }`. The stub intentionally uses raw keys as labels — this will be replaced in task-006.
Place the file at the agreed accessibility widget path and add an export to the barrel. Do not implement provider reads in this task — that is task-006's scope.
Testing Requirements
A single smoke test using flutter_test: pump WcagSemanticsLabelResolver with a known labelKey and a Text child, assert the widget tree contains a Semantics node and the child Text widget renders. This confirms the scaffold compiles and wraps correctly. Full semantic validation is deferred to task-007. The test should run in under 100ms.
WcagSemanticsLabelResolver's Semantics wrappers may conflict with Semantics nodes already defined by existing accessible widgets (e.g., accessible-bottom-navigation, activity-wizard-semantics), causing duplicate or contradictory screen reader announcements that fail WCAG 2.2 AA criteria.
Mitigation & Contingency
Mitigation: Audit all existing Semantics-annotated widgets in the accessibility feature before implementing WcagSemanticsLabelResolver. Define a clear hierarchy rule: WcagSemanticsLabelResolver always merges with, never replaces, existing Semantics nodes. Use Flutter's debugSemantics output in CI to detect conflicts automatically.
Contingency: If conflicts are discovered in testing, introduce a resolverMode parameter to WcagSemanticsLabelResolver allowing it to operate in 'override' or 'merge' mode per call site; coordinate with the Screen Reader Support feature team to align Semantics strategies.
If TerminologyAwareTextWidget subscribes to the full terminology map provider rather than the per-key labelProvider family, a single label update will trigger a full widget-tree rebuild across all screens simultaneously, causing jank on devices used by older peer mentors.
Mitigation & Contingency
Mitigation: Implement TerminologyAwareTextWidget using ref.watch(labelProvider(key)) on the per-key family provider from TerminologyRiverpodProviders so that only widgets bound to the changed key rebuild. Verify with Flutter DevTools 'rebuild tracking' in widget tests.
Contingency: If full-map subscriptions slip through code review, add a Riverpod lint rule that flags direct organizationLabelsNotifierProvider subscriptions inside widget build methods and enforces the per-key family pattern.
The TerminologyAdminPreviewScreen requires coordinator-level access, but if role checks rely solely on client-side guard logic without matching Supabase RLS policies, a peer mentor could potentially access the admin preview by manipulating navigation state.
Mitigation & Contingency
Mitigation: Protect the admin preview route with a server-validated role guard that re-fetches the user's role from Supabase on screen initialization, not just from local state. Add a Supabase RLS policy that restricts label map read access for the admin preview endpoint to coordinator and admin roles only.
Contingency: If unauthorized access is discovered in testing, immediately add a middleware role assertion that redirects non-coordinators to the no-access screen and logs the unauthorized navigation attempt for audit.