From 42ab91e4f2f6c1912cfc044ecade8b074c231f0d Mon Sep 17 00:00:00 2001 From: Prithpal Sooriya Date: Fri, 6 Mar 2026 10:25:23 +0000 Subject: [PATCH 1/2] Fix unordered threshold scope selection Co-authored-by: Prithpal Sooriya --- .../CHANGELOG.md | 4 ++ .../remote-feature-flag-controller.test.ts | 38 +++++++++++++++++++ .../src/remote-feature-flag-controller.ts | 15 +++----- 3 files changed, 48 insertions(+), 9 deletions(-) diff --git a/packages/remote-feature-flag-controller/CHANGELOG.md b/packages/remote-feature-flag-controller/CHANGELOG.md index b6984cfce3e..152c46dcc17 100644 --- a/packages/remote-feature-flag-controller/CHANGELOG.md +++ b/packages/remote-feature-flag-controller/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed + +- Sort threshold-scoped variations by ascending scope value before selecting a group, so unordered threshold arrays are evaluated correctly. ([#8120](https://github.com/MetaMask/core/pull/8120)) + ## [4.1.0] ### Added diff --git a/packages/remote-feature-flag-controller/src/remote-feature-flag-controller.test.ts b/packages/remote-feature-flag-controller/src/remote-feature-flag-controller.test.ts index 2ea779a4ae9..1a47c5b58b9 100644 --- a/packages/remote-feature-flag-controller/src/remote-feature-flag-controller.test.ts +++ b/packages/remote-feature-flag-controller/src/remote-feature-flag-controller.test.ts @@ -422,6 +422,44 @@ describe('RemoteFeatureFlagController', () => { }); }); + it('selects the lowest matching threshold when threshold scopes are unordered', async () => { + const mockFlags = { + unorderedThresholdFlag: [ + { + name: 'control', + scope: { type: 'threshold', value: 1.0 }, + value: 'control', + }, + { + name: 'treatment', + scope: { type: 'threshold', value: 0.1 }, + value: 'treatment', + }, + ], + }; + const clientConfigApiService = buildClientConfigApiService({ + remoteFeatureFlags: mockFlags, + }); + const controller = createController({ + clientConfigApiService, + getMetaMetricsId: () => MOCK_METRICS_ID, + state: { + thresholdCache: { + [`${MOCK_METRICS_ID}:unorderedThresholdFlag`]: 0.05, + }, + }, + }); + + await controller.updateRemoteFeatureFlags(); + + expect( + controller.state.remoteFeatureFlags.unorderedThresholdFlag, + ).toStrictEqual({ + name: 'treatment', + value: 'treatment', + }); + }); + it('preserves non-threshold feature flags unchanged', async () => { const clientConfigApiService = buildClientConfigApiService({ remoteFeatureFlags: MOCK_FLAGS_WITH_THRESHOLD, diff --git a/packages/remote-feature-flag-controller/src/remote-feature-flag-controller.ts b/packages/remote-feature-flag-controller/src/remote-feature-flag-controller.ts index f05d3147ab1..936b250f96e 100644 --- a/packages/remote-feature-flag-controller/src/remote-feature-flag-controller.ts +++ b/packages/remote-feature-flag-controller/src/remote-feature-flag-controller.ts @@ -11,7 +11,6 @@ import type { AbstractClientConfigApiService } from './client-config-api-service import type { FeatureFlags, ServiceResponse, - FeatureFlagScopeValue, } from './remote-feature-flag-controller-types'; import { calculateThresholdForFlag, @@ -372,15 +371,13 @@ export class RemoteFeatureFlagController extends BaseController< thresholdCacheUpdates[cacheKey] = thresholdValue; } + const thresholdScopedFlags = processedValue + .filter(isFeatureFlagWithScopeValue) + .sort((a, b) => a.scope.value - b.scope.value); + const threshold = thresholdValue; - const selectedGroup = processedValue.find( - (featureFlag): featureFlag is FeatureFlagScopeValue => { - if (!isFeatureFlagWithScopeValue(featureFlag)) { - return false; - } - - return threshold <= featureFlag.scope.value; - }, + const selectedGroup = thresholdScopedFlags.find( + (featureFlag) => threshold <= featureFlag.scope.value, ); if (selectedGroup) { processedValue = { From 0c53f9c4710d58a438bba48450cfdc209d46dab2 Mon Sep 17 00:00:00 2001 From: Prithpal Sooriya Date: Fri, 6 Mar 2026 10:30:05 +0000 Subject: [PATCH 2/2] Fix changelog PR reference for CI Co-authored-by: Prithpal Sooriya --- packages/remote-feature-flag-controller/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/remote-feature-flag-controller/CHANGELOG.md b/packages/remote-feature-flag-controller/CHANGELOG.md index 152c46dcc17..6333ccffef8 100644 --- a/packages/remote-feature-flag-controller/CHANGELOG.md +++ b/packages/remote-feature-flag-controller/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed -- Sort threshold-scoped variations by ascending scope value before selecting a group, so unordered threshold arrays are evaluated correctly. ([#8120](https://github.com/MetaMask/core/pull/8120)) +- Sort threshold-scoped variations by ascending scope value before selecting a group, so unordered threshold arrays are evaluated correctly. ([#8128](https://github.com/MetaMask/core/pull/8128)) ## [4.1.0]