This document details the feature flag gating and user self-serve beta opt-in (“Beta Labs”) architecture implemented for the Signals-First MVP Scope (tracking GitHub Issue #239).
As Robinhood Options Mobile scales towards app store releases and broad public distribution, complex features (such as autonomous agentic order execution, social copy trading, AI assistant dialogues, multi-leg spreads, and alternative brokerage bridges) must be strictly decoupled from the core “Signals-First” baseline.
The core public MVP focus comprises:
All non-core or high-liability features are partitioned into Feature Bundles controlled by Firebase Remote Config and surfaced through the in-app Beta Labs dashboard. When a user is signed in, preferences are synchronized across local SharedPreferences, the in-memory User, and the Firestore user document.
FeatureAccessService.isFeatureEnabled applies these checks in order:
disabled denies access to everyone, including admins.User.featureFlags overrides rollout defaults and role checks. This permits an explicit Firestore grant or denial, except when the global disable switch is active.beta_self_opt_in_enabled master switch blocks opt-ins for non-admins when disabled; admins can still opt in.Users manage local opt-ins and public-mode opt-outs in Beta Labs (UserWidget -> Profile & Community -> Beta Labs). Changes update local SharedPreferences and the in-memory User immediately, and synchronize to the Firestore user document when one is available.
| Parameter Key | Bundle Identifier | Default Remote Value | Scope & Functionality |
|---|---|---|---|
beta_self_opt_in_enabled |
Master Switch | true |
Master kill-switch controlling whether user self-serve opt-in is allowed. |
beta_advanced_research |
FeatureBundle.advancedResearch |
betaOptIn |
Options flow, GEX charts, stock screeners, and SEC filings research. |
beta_ai_research |
FeatureBundle.aiResearch |
betaOptIn |
Market Assistant Copilot, macro sentiment analyzers, AI trade coaches, and Investment Profile settings. |
beta_advanced_trading |
FeatureBundle.advancedTrading |
betaOptIn |
Multi-leg spread builder, complex option strategy templates, and combo orders. |
beta_backtesting |
FeatureBundle.backtesting |
betaOptIn |
Historical strategy backtesting, performance analytics, and simulation. |
beta_risk_guardrails |
FeatureBundle.riskGuardrails |
betaOptIn |
Autonomous account loss limits, peak-to-trough drawdown protection, rapid-cancel loop detection, and tilt cooling-off locks. |
beta_automated_trading |
FeatureBundle.automatedTrading |
betaOptIn |
Automated order execution and algorithmic trading strategies. |
beta_social_copy |
FeatureBundle.socialCopy |
betaOptIn |
Investor discovery, shared trade logs, discussion threads, copy trading, and Portfolio & Social Privacy settings. |
beta_account_tools |
FeatureBundle.accountTools |
betaOptIn |
Wash sale tracking, tax lot optimization, and retirement planning tools. |
beta_extended_brokerages |
FeatureBundle.extendedBrokerages |
betaOptIn |
Alternative brokerage accounts (Fidelity CSV import, Plaid). Core platforms (Robinhood, Charles Schwab, Paper Trading, Demo) are never gated. |
[!IMPORTANT] Core Brokerage Scope: Charles Schwab and Paper Trading are core, production-ready platforms in Robinhood Options Mobile alongside Robinhood and Demo. They are never subject to
extendedBrokeragesor beta flags. TheextendedBrokeragesbundle strictly applies to auxiliary or experimental integrations like Fidelity manual CSV imports and Plaid.
Remote config keys accept one of four case-insensitive strings: disabled, adminOnly, betaOptIn, or public.
lib/enums.dart)FeatureRolloutMode: Enum representing rollout states: disabled, adminOnly, betaOptIn, public.FeatureBundle: Enum representing the 9 partitioned feature groups. Each entry provides:
remoteConfigKey: Associated Firebase Remote Config string key.displayName: Human-readable label displayed in UI.description: Explanatory subtitle of the features included in the bundle.lib/services/remote_config_service.dart)isBetaSelfOptInEnabled and getFeatureRollout(key).lib/services/feature_access_service.dart)ChangeNotifier to allow real-time UI rebuilds when flags or opt-in states change.isFeatureEnabled(bundle, {userRole, user}): Resolves access using the precedence above.getRolloutMode(bundle): Returns current FeatureRolloutMode.isUserOptedIn(bundle) / isUserOptedOut(bundle): Checks the in-memory preference cache and local SharedPreferences.setUserPreference(bundle, enabled, {user, userDocRef}): Updates local preference, the in-memory User.featureFlags, and Firestore when supplied.resetAllOptIns({user, userDocRef}): Clears local choices and the corresponding in-memory and Firestore flags.setOverrideMode(bundle, mode): In-memory override for automated testing and sandbox previews.lib/widgets/beta_labs_widget.dart)UserWidget).Public, Beta, Admin Only, Disabled).FeatureBundle.advancedTrading) with a confirmation dialog explaining execution risks and liability before toggling on.resetAllOptIns) in the top app bar.lib/widgets/navigation_widget.dart)FeatureAccessService.instance.isFeatureEnabled(FeatureBundle.socialCopy, userRole: userRole) is true.FeatureBundle.aiResearch.lib/widgets/user_widget.dart)Icons.science_outlined), navigating directly to BetaLabsWidget._buildFeatureTile checks FeatureAccessService.instance.isFeatureEnabled(featureBundle, userRole: userRole).
Automated Trading: Gated behind FeatureBundle.advancedTrading.Backtesting: Gated behind FeatureBundle.advancedTrading.Comprehensive tests verify both unit logic and UI behaviors:
test/feature_access_service_test.dart:
disabled) enforcement and explicit user-flag precedence.public rollout mode granting access to all users.test/beta_labs_widget_test.dart:
test/user_widget_features_availability_test.dart:
BetaLabsWidget from profile.