Skip to content

Conversation

@asalsys
Copy link
Contributor

@asalsys asalsys commented Dec 1, 2025

Description

This PR adds comprehensive override functionality to the RemoteFeatureFlagController that was added in this PR, allowing developers and users to locally override remote feature flags for testing and debugging purposes. The implementation also includes enhanced A/B test visibility features that provide access to available test groups.

What is the reason for the change?
The need to override remote feature flags locally for development, testing, and debugging scenarios without modifying the remote configuration.

What is the improvement/solution?

  • Added local override system that takes precedence over remote flags
  • Enhanced state management to track both remote flags and local overrides separately
  • Added A/B test raw flag storage to provide visibility into available test groups
  • Implemented comprehensive API methods for managing overrides and accessing flag information

Changelog

CHANGELOG entry: Added override functionality to remote feature flags with methods to set, get, clear overrides and access A/B test groups

Related issues

Fixes:

Manual testing steps

Feature: Remote Feature Flag Override Functionality

Scenario: user sets a local override for a feature flag
Given the RemoteFeatureFlagController is initialized with remote flags
When user calls setFlagOverride('testFlag', true)
Then testFlag selector should return the override value true
And getFlagOverride('testFlag') should return true

Scenario: user clears a specific flag override
Given a feature flag has a local override set
When user calls clearFlagOverride('testFlag')
Then testFlag selector should return the original remote value
And getFlagOverride('testFlag') should return undefined

Scenario: user accesses A/B test groups
Given remote flags contain A/B test configurations
When user calls rawProcessedRemoteFeatureFlags selector
Then it should return an array of available test groups with names and values

Screenshots/Recordings

Before

After

Pre-merge author checklist

Pre-merge reviewer checklist

  • I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed).
  • I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.

@github-actions
Copy link
Contributor

github-actions bot commented Dec 1, 2025

CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes.

@metamaskbot metamaskbot added the team-mobile-platform Mobile Platform team label Dec 1, 2025
@github-actions github-actions bot added the size-M label Dec 1, 2025
@asalsys asalsys changed the title import local remote feature flag feat: import newremote feature flag controller with override functionality Dec 2, 2025
Copy link
Contributor

@Cal-L Cal-L left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The engine ready checks might not be necessary assuming this context is used in the right place. We already have a ControllersGate that blocks the majority of components from rendering before the engine is initialized. Can we rely on that instead?

@asalsys
Copy link
Contributor Author

asalsys commented Dec 3, 2025

The engine ready checks might not be necessary assuming this context is used in the right place. We already have a ControllersGate that blocks the majority of components from rendering before the engine is initialized. Can we rely on that instead?

Yes, correct, I don't think it is necessary at all. I had that logic because I was having trouble getting it to start I thought the issue was that the controller wasn't loading but it was because the controller was broken and wasn't building

@asalsys asalsys force-pushed the use-updated-remote-feature-flag-to-handle-overrides branch from 8003948 to 06336f2 Compare December 10, 2025 21:28
@asalsys asalsys requested a review from Cal-L December 10, 2025 21:29
@github-actions
Copy link
Contributor

🔍 Smart E2E Test Selection

  • Selected E2E tags: SmokeCore, SmokeConfirmationsRedesigned, SmokeWalletPlatform, SmokeWalletUX, SmokeTrade, SmokeSwaps, SmokeStake, SmokeNotifications, SmokePerps, SmokeRamps, SmokePredictions, SmokeAssets, SmokeNetworkAbstractions, SmokeMultiChainPermissions
  • Risk Level: high
  • AI Confidence: 85%
click to see 🤖 AI reasoning details

This PR modifies the core feature flag infrastructure, specifically the selectRemoteFeatureFlags selector which is used in 50+ places across the codebase controlling behavior of virtually every major feature.

Key changes:

  1. Modified selectRemoteFeatureFlags to merge localOverrides with remoteFeatureFlags - this is a fundamental behavioral change affecting how all feature flags are resolved
  2. Added new selectors: selectLocalOverrides, selectRawFeatureFlags, selectrawRemoteFeatureFlags
  3. Refactored FeatureFlagOverrideContext to use controller methods instead of local React state
  4. Added A/B test flag type support
  5. CRITICAL ISSUE: package.json points to a local file path (file:/Users/sallem/Desktop/...) which would break builds for anyone else - this appears to be an unintended development-time change

The selectRemoteFeatureFlags selector directly impacts:

  • Confirmations (signatures, staking, contract interactions, transfers, approves)
  • Bridge functionality
  • Notifications
  • Perps/Perpetuals trading
  • Predictions market
  • Earn/Staking
  • Ramps (buy/sell)
  • Network blacklists
  • Asset DeFi positions
  • Token search/discovery
  • Card features
  • Homepage carousel
  • And many more

Because this selector is foundational infrastructure that gates nearly every major feature, any subtle bugs in how overrides are merged could cause unexpected behavior across the entire app. The comprehensive tag selection ensures we catch any regressions in feature-flag-controlled functionality.

View GitHub Actions results

Copy link
Contributor

@Cal-L Cal-L left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some comments

/>
);
case 'abTest': {
interface AbTestType {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move type outside of component

ios_backgroundColor={theme.colors.border.muted}
/>
);
case 'abTest': {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While extracting types, also cleaner to extract these into enums

// Local state for overrides
const [overrides, setOverrides] = useState<FeatureFlagOverrides>({});
// Subscribe to controller state changes to ensure we stay in sync
useEffect(() => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't seem like it should do anything since it's triggering an empty function from inside of the useEffect. What's the intended purpose here - is it to get the latest state every time the feature flag changes?

}

// Helper to safely access the RemoteFeatureFlagController with proper typing
const getRemoteFeatureFlagController = ():
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not need to be a function since it's just returning a reference

| undefined;

// Helper to safely execute controller methods with error handling
const withRemoteFeatureFlagController = (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the with naming convention is usually used for higher order wrappers, which typically used to wrap classes or functional components. Following the logic, it looks like this is intended to handle catching error on method calls for the remote feature flag controller. A few suggestions to make this cleaner:

  • Create a remote feature flag hook instead, useRemoteFeatureFlagController
  • In the hook, return remote feature flag functions that gracefully handle method call failures

export const selectRemoteFeatureFlags = createSelector(
selectRemoteFeatureFlagControllerState,
(remoteFeatureFlagControllerState) => {
(remoteFeatureFlagControllerState: unknown) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should use the state type from RemoteFeatureFlagController

| 'array'
| 'boolean with minimumVersion'
| 'boolean nested'
| 'abTest'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cleaner to abstract these into an enum

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size-M team-mobile-platform Mobile Platform team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants