high priority medium complexity testing pending testing specialist Tier 6

Acceptance Criteria

All unit tests pass in CI with `flutter test` — zero failures
FeatureFlagInitializer: network success path test verifies resolved map is populated from network response
FeatureFlagInitializer: network failure test verifies fallback to cached flags and stale indicator set to true
FeatureFlagInitializer: empty cache cold-start test verifies all flags default to false/hidden and no crash occurs
FeatureFlagProvider: isEnabled test verifies correct boolean returned for enabled flag
FeatureFlagProvider: isEnabled test verifies false returned for disabled flag
FeatureFlagProvider: isEnabled test verifies false returned for unknown flag key
FeatureFlagProvider: rollout phase condition test verifies false returned when phase not yet active
FeatureFlagProvider: rollout phase condition test verifies true returned when phase is active
FeatureFlagProvider: reactive update test verifies provider state updates when mock repository emits change
FeatureFlagProvider: organization switch test verifies re-initialization triggered with new org's flags
Test code coverage for runtime services: minimum 85% line coverage
All mock dependencies injected via Riverpod ProviderScope overrides — no global state in tests
Tests are isolated and can run in any order without shared mutable state

Technical Requirements

frameworks
Flutter
Riverpod
flutter_test
data models
FeatureFlag
FeatureFlagKeys (enum)
ResolvedFlagState
RolloutCondition
performance requirements
Full test suite for runtime services completes in under 30 seconds
No real network calls in unit tests — all mocked
security requirements
Test fixtures must not contain real API keys or Supabase credentials
Use placeholder/test organization IDs in all test data

Execution Context

Execution Tier
Tier 6

Tier 6 - 158 tasks

Can start after Tier 5 completes

Implementation Notes

Create test files mirroring the source structure: `test/feature_flags/feature_flag_initializer_test.dart` and `test/feature_flags/feature_flag_provider_test.dart`. Define shared test fixtures in a `test/feature_flags/fixtures.dart` file (sample flag maps, mock org IDs, rollout conditions). For Riverpod provider tests, prefer `ProviderContainer` over `WidgetTester` to keep tests lightweight. Use `addTearDown(container.dispose)` in each test to prevent provider leaks.

For the rollout phase condition tests, freeze time using a `FakeRolloutEvaluator` that accepts a configurable `DateTime` — do not rely on real `DateTime.now()`. For the org-switch re-initialization test, simulate by overriding `activeOrganizationProvider` mid-test and verifying the flag provider disposes and re-creates its stream subscription.

Testing Requirements

Pure unit tests using flutter_test. Use mocktail (preferred for Dart null-safety) or mockito for mocking FeatureFlagRepository, LocalFlagCache, and RolloutEvaluator dependencies. Structure tests in three groups: `group('FeatureFlagInitializer', ...)`, `group('FeatureFlagProvider.isEnabled', ...)`, `group('FeatureFlagProvider.reactive', ...)`. Each test should follow Arrange-Act-Assert pattern with descriptive test names.

Inject mocks via Riverpod `ProviderContainer` with `overrides` parameter for provider-level tests. For stream-based reactive tests, use `StreamController` to simulate repository events. Assert state changes using `container.read(provider)` after stream emission with `await Future.delayed(Duration.zero)` to flush microtasks.

Component
Feature Flag Provider
infrastructure low
Epic Risks (2)
high impact medium prob technical

The feature-flag-initializer must complete before any screen that checks feature flags renders. If the navigation shell is pushed concurrently with initialization (e.g., via a parallel Riverpod provider chain), some screens may query flags before they are loaded and incorrectly receive all-disabled defaults.

Mitigation & Contingency

Mitigation: Gate the main navigation shell render behind the feature-flag-initializer's Future by using a splash/loading screen that awaits the initialization provider. Use Riverpod's ref.watch on an initialization state enum (loading/ready/error) to block rendering.

Contingency: If race conditions are observed in testing, introduce an explicit initialization barrier using a ChangeNotifier or a dedicated `featureFlagsReadyProvider` that the router guard checks before allowing navigation.

medium impact low prob technical

If feature-flag-provider is watched by many widgets simultaneously and a flag map refresh triggers all of them to rebuild at once (e.g., after an organization switch), the app could experience a significant UI jank or dropped frames.

Mitigation & Contingency

Mitigation: Use select() on the provider to have each widget watch only the specific flag key it needs rather than the entire map. Ensure the provider uses equality checks so rebuilds only propagate when the specific flag value changes.

Contingency: If rebuild storms are measured via Flutter DevTools, refactor to a family provider keyed by flag key, so each widget subscribes only to its own flag's changes.