critical priority low complexity frontend pending frontend specialist Tier 0

Acceptance Criteria

When the driver feature flag is enabled for the current org, the guard renders its child widget tree without any visual modification or extra layout
When the driver feature flag is disabled (or missing) for the current org, the guard renders SizedBox.shrink() — zero size, zero layout impact
When the feature flag state is loading (AsyncValue.loading), the guard renders SizedBox.shrink() by default to avoid flash of suppressed content; an optional loadingBuilder parameter can override this
When the feature flag state is error, the guard renders SizedBox.shrink() and logs the error — it does not surface an error widget to the end user
The guard reads the current org ID from the existing Riverpod auth/session provider — it does not accept orgId as a constructor parameter
The guard uses OrgFeatureFlagService via Riverpod (ConsumerWidget or Consumer) and the DriverFeatureFlagConfig.driverManagement constant as the feature key
The widget is const-constructible with only a required child parameter and an optional loadingBuilder
Wrapping any widget subtree with DriverFeatureFlagGuard does not cause the parent layout to reserve space for the suppressed subtree
A widget test verifies: enabled flag → child is present in widget tree; disabled flag → child is absent and SizedBox.shrink is rendered
No direct Supabase calls in the widget — all data access is through the Riverpod provider

Technical Requirements

frameworks
Flutter
Riverpod
Dart
apis
OrgFeatureFlagService.isFeatureEnabled (via Riverpod provider)
data models
DriverFeatureFlagConfig (feature key constant)
OrgFeatureFlag
performance requirements
Guard must not trigger unnecessary rebuilds when unrelated Riverpod state changes
Use select() on the provider to watch only the specific flag value, not the entire service state
security requirements
Guard must never render driver UI for an org where the flag is false, even briefly — no optimistic rendering before the flag is confirmed
Guard must not expose any indication to the user that a feature exists but is disabled (no placeholder, no tooltip, no empty space)
ui components
ConsumerWidget (or Consumer wrapper) for Riverpod integration
SizedBox.shrink() as the suppressed-state widget
Conditional child rendering via ternary or if-guard in build method

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Implement as a ConsumerWidget. In the build method, use ref.watch(orgFeatureFlagProvider(DriverFeatureFlagConfig.driverManagement)) where orgFeatureFlagProvider is a family provider taking the feature key and internally reading the current orgId from the session provider. In the AsyncValue.when callback: data(enabled) → enabled ? child : SizedBox.shrink(); loading → loadingBuilder?.call(context) ??

SizedBox.shrink(); error → (log error) + SizedBox.shrink(). Define the family provider in feature_flag_providers.dart alongside the service provider. Place the widget at lib/features/driver/widgets/driver_feature_flag_guard.dart and export from the barrel. Document in the widget's dartdoc that the guard is the single enforcement point for the driver feature flag in the UI layer — all driver navigation entries, screens, and nav bar items must be wrapped in this guard.

Testing Requirements

Write widget tests in test/widgets/driver_feature_flag_guard_test.dart. Use ProviderScope with overrides to inject a mock OrgFeatureFlagService. Test case 1: override returns AsyncValue.data(true) → find(child widget type) succeeds. Test case 2: override returns AsyncValue.data(false) → find(child widget type) fails, find(SizedBox) succeeds with zero size.

Test case 3: override returns AsyncValue.loading() → child is absent. Test case 4: override returns AsyncValue.error(...) → child is absent and no error widget is rendered. Use pumpAndSettle after each state change. Verify layout with tester.getSize(find.byType(DriverFeatureFlagGuard)) returns Size.zero when suppressed.

Epic Risks (3)
high impact medium prob technical

The declaration acknowledgement screen has the most complex accessibility requirements of any screen in this feature: scrollable long-form legal text, a conditional checkbox that is only enabled after reading, and a timestamp capture. Incorrect focus management or missing semantics annotations could fail VoiceOver navigation or cause the screen reader to announce the checkbox as available before the driver has scrolled, undermining the legal validity of the acknowledgement.

Mitigation & Contingency

Mitigation: Build the acknowledgement screen against the WCAG 2.2 AA checklist from the start, not as a post-hoc audit. Use semantics-wrapper-widget and live-region-announcer from the platform's accessibility toolkit. Include a VoiceOver test session in the acceptance criteria with a tester using the screen reader.

Contingency: If WCAG compliance cannot be fully achieved within the sprint, ship the screen with a documented list of accessibility gaps and a follow-up sprint commitment. Do not block the declaration workflow launch if the core interaction works but a non-critical semantics annotation is missing.

medium impact medium prob integration

Drivers receive a push notification with a deep link to the declaration acknowledgement screen for a specific assignment. If the deep link handler does not correctly route to the right screen and assignment context — particularly when the app is launched cold from the notification — the driver may see a blank screen or the wrong declaration.

Mitigation & Contingency

Mitigation: Implement and test all three notification scenarios: app foregrounded, app backgrounded, and cold start. Use the platform's existing deep-link-handler infrastructure. Add integration tests that simulate notification tap events and assert correct screen and data loading.

Contingency: If cold-start deep link routing proves unreliable, implement a notification-centre fallback where the driver can find the pending declaration from the notification centre screen, ensuring the workflow can always complete even if the direct deep link fails.

medium impact low prob technical

If the driver-feature-flag-guard has any rendering edge case — such as a brief flash of driver UI before the flag value is loaded, or a guard that fails open on a flag service error — driver-specific UI elements could be momentarily visible to coordinators in organizations that have not opted in, causing confusion and potentially a support escalation.

Mitigation & Contingency

Mitigation: Default the guard to rendering nothing (not a loading indicator) until the flag value is definitively resolved. Treat flag service errors as flag-disabled to fail closed. Write widget tests covering the loading, disabled, and enabled states including the error case.

Contingency: If fail-closed cannot be guaranteed within the sprint, add a server-side RLS check on the driver assignment endpoints so that even if the UI guard leaks, the data layer refuses to return driver data for organizations without the flag enabled.