high priority low complexity frontend pending frontend specialist Tier 2

Acceptance Criteria

When LabelKeyResolver.resolve returns null AND a `fallback` string is provided, the widget renders the fallback string
When LabelKeyResolver.resolve returns null AND no `fallback` is provided, the widget renders the labelKey converted to human-readable text (e.g., 'peer_mentor_label' → 'Peer Mentor Label')
Human-readable conversion replaces underscores and hyphens with spaces and applies title-case or sentence-case formatting
In debug mode (kDebugMode == true), a debug-level log message is emitted identifying the missing labelKey and the active organization ID
In release/profile mode, no log output is produced for missing keys — the fallback renders silently
The widget never throws, crashes, or displays an empty string due to a missing key
Fallback rendering is visually distinguishable only in debug mode (optional: a subtle debug indicator such as a tooltip or border, disabled in release)
Existing resolved keys are unaffected by the fallback logic — the fallback path is only reached when resolve returns null
The `fallback` parameter accepts an empty string, in which case an empty string is displayed (the caller explicitly chose this)

Technical Requirements

frameworks
Flutter
Riverpod
data models
OrganizationLabelMap
LabelKey
performance requirements
Fallback string computation (_humanize) must be a pure synchronous function — no async, no I/O
Debug logging must be guarded by kDebugMode to be tree-shaken in release builds — zero overhead in production
security requirements
Debug log must not include the full label map contents — only the missing key name and org identifier
Do not expose internal org configuration details through visible UI in production builds
ui components
TerminologyAwareTextWidget (enhanced with fallback logic)
Optional: DebugMissingKeyBorder (debug-only decoration widget, stripped in release)

Execution Context

Execution Tier
Tier 2

Tier 2 - 518 tasks

Can start after Tier 1 completes

Implementation Notes

Implement a private static helper `_humanize(String key)` that replaces `_` and `-` with spaces, then applies `toUpperCase()` on the first letter of each word (title case). Example: `'peer_mentor_label'.replaceAll(RegExp(r'[_-]'), ' ')` followed by a simple capitalize-words pass. The resolution priority chain is: (1) resolved from map, (2) explicit fallback, (3) humanized key. Guard the debug log with `assert(() { debugPrint('[Terminology] Missing key: $labelKey (org: $orgId)'); return true; }())` — the assert body is stripped in release builds.

Avoid using `if (kDebugMode)` for the log if it introduces a non-trivial code path; the assert pattern is preferred. Do not add a visible debug decorator unless the team explicitly requests it — the log is sufficient for development.

Testing Requirements

Unit tests using flutter_test: (1) Provide a label map where the tested key is absent — assert the rendered text equals the provided `fallback` string. (2) Provide a label map where the key is absent AND no fallback is given — assert the rendered text equals the humanized key ('peer_mentor_label' → 'Peer Mentor Label'). (3) Verify that in debug mode a log warning is captured (use a custom log listener or zone override). (4) Verify no exception is thrown for any null/missing combination.

(5) Test with fallback set to empty string '' — assert empty string is rendered, not the humanized key. Aim for 100% coverage of the fallback resolution branches.

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.