critical priority low complexity frontend pending frontend specialist Tier 0

Acceptance Criteria

TerminologyAwareTextWidget is declared as a ConsumerWidget and compiles without errors
Widget constructor accepts a required `labelKey` (String) parameter and an optional `fallback` (String?) parameter
Widget reads from organizationLabelsNotifierProvider (or labelProvider family) via ref.watch()
When labels are loaded and the key is present, the widget renders the resolved label string in a Text widget
When labels are loading, the widget renders the fallback string if provided, otherwise renders the raw labelKey
When the key is absent from the loaded map, the widget renders the fallback string if provided, otherwise renders the raw labelKey
Widget does NOT throw or show an error widget in any of the above states
Widget accepts an optional `style` (TextStyle?) parameter and forwards it to the inner Text widget
Widget is exported from the terminology feature's public barrel file
The widget is fully functional as a drop-in replacement for Text() for any label string — no additional setup required by calling code
Widget passes WCAG 2.2 AA accessibility requirements: the rendered text has sufficient contrast and is readable by screen readers (no Semantics overrides that hide text)

Technical Requirements

frameworks
Flutter
Riverpod
data models
OrganizationLabelsState
labelProvider family
performance requirements
Widget rebuild is scoped to the watched label key only — does not rebuild when unrelated labels change (use labelProvider family with select)
No layout jank: loading state renders a stable-size placeholder (same text as fallback/key) rather than an empty or differently-sized widget
security requirements
Label strings must be HTML-escaped if ever rendered in a WebView context — document this constraint in the widget's doc comment
Widget must not expose internal provider state or error messages to the end user — always show safe fallback text
ui components
Text
ConsumerWidget

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Prefer watching `labelProvider(labelKey)` family provider (from task-008) rather than the full organizationLabelsNotifierProvider to get granular rebuild behavior. Constructor signature: `const TerminologyAwareTextWidget({super.key, required this.labelKey, this.fallback, this.style})`. The build method should be a single expression: `Text(ref.watch(labelProvider(labelKey)), style: style)` — the fallback logic lives in the provider, not the widget. If labelProvider is not yet available (task-008 not merged), use a local select on the notifier as a temporary implementation and leave a TODO comment.

Follow the project's design token system for any default text style — do not hardcode font sizes or colors.

Testing Requirements

Widget tests using flutter_test and WidgetTester: (1) pump widget with mocked provider returning a loaded map containing the key — assert correct label is displayed; (2) pump widget with loading state — assert fallback or raw key is displayed; (3) pump with loaded map where key is absent — assert fallback is displayed; (4) pump with explicit fallback provided and key absent — assert the explicit fallback (not raw key) is displayed; (5) assert widget does not throw in error state; (6) verify that TextStyle is forwarded correctly; (7) verify screen reader semantics using tester.getSemantics(). All tests use ProviderContainer overrides to inject controlled state.

Epic Risks (3)
high impact medium prob integration

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.

medium impact medium prob technical

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.

medium impact low prob security

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.