Skip to content

fix: RemoteFeatureFlagController client version change cache invalidation#7827

Open
Prithpal-Sooriya wants to merge 6 commits intomainfrom
cursor/client-version-cache-invalidation-4c09
Open

fix: RemoteFeatureFlagController client version change cache invalidation#7827
Prithpal-Sooriya wants to merge 6 commits intomainfrom
cursor/client-version-cache-invalidation-4c09

Conversation

@Prithpal-Sooriya
Copy link
Contributor

@Prithpal-Sooriya Prithpal-Sooriya commented Feb 3, 2026

Explanation

  • What is the current state of things and why does it need to change?
    The RemoteFeatureFlagController did not invalidate its cache when the client application version changed. This could lead to users receiving stale feature flags after an application upgrade, as the controller would continue to use cached flags from the previous version. This is detailed in [Bug]: Explore feature is not available when upgrading from 7.62.2/7.63.0 to 7.64.0 metamask-mobile#25474.

  • What is the solution your changes offer and how does it work?
    This PR introduces a previousClientVersion property to the controller's persisted state. On initialization, the controller compares the current clientVersion (passed in the constructor) with the stored previousClientVersion. If these versions differ (or if previousClientVersion is invalid/missing), the cache is invalidated, forcing a fresh fetch of feature flags. The previousClientVersion is then updated to the current clientVersion in the state.

  • Are there any changes whose purpose might not obvious to those unfamiliar with the domain?
    No.

References

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've communicated my changes to consumers by updating changelogs for packages I've changed
  • I've introduced breaking changes in this PR and have prepared draft pull requests for clients and consumer packages to resolve them

Note

Medium Risk
Changes cache-invalidation behavior in RemoteFeatureFlagController based on app version, which can increase fetches or alter which flags users receive immediately after upgrades. Risk is limited to this controller’s initialization path and is covered by new unit tests.

Overview
Remote feature flag caching now invalidates on app upgrades. RemoteFeatureFlagController accepts an optional prevClientVersion and resets cacheTimestamp to 0 when it differs from the current clientVersion, forcing a fresh fetch instead of using potentially stale cached flags.

Adds unit coverage for the version-change scenario and documents the fix in CHANGELOG.md.

Written by Cursor Bugbot for commit 6dfa4ae. This will update automatically on new commits. Configure here.

@cursor
Copy link

cursor bot commented Feb 3, 2026

Cursor Agent can help with this pull request. Just @cursor in comments and I'll start working on changes in this branch.
Learn more about Cursor Agents

@Prithpal-Sooriya Prithpal-Sooriya force-pushed the cursor/client-version-cache-invalidation-4c09 branch from c1f8201 to 016bbe9 Compare February 4, 2026 11:59
@Prithpal-Sooriya Prithpal-Sooriya marked this pull request as ready for review February 4, 2026 12:04
@Prithpal-Sooriya Prithpal-Sooriya requested review from a team as code owners February 4, 2026 12:04
@Prithpal-Sooriya Prithpal-Sooriya changed the title Client version cache invalidation fix: RemoteFeatureFlagController client version change cache invalidation Feb 4, 2026
sahar-fehri
sahar-fehri previously approved these changes Feb 4, 2026
Copy link
Contributor

@sahar-fehri sahar-fehri left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

* @param opts - The options for the arrangeActAssertClientVersionChange test
* @param opts.clientVersion - The client version to use
* @param opts.controllerState - The controller state to use
* @param opts.expectedFeatureFlagState - The expected feature flag state\
Copy link
Contributor

Choose a reason for hiding this comment

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

Minor typo

Suggested change
* @param opts.expectedFeatureFlagState - The expected feature flag state\
* @param opts.expectedFeatureFlagState - The expected feature flag state

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks, resolved in daa2655

).toStrictEqual({
enabled: expectedFeatureFlagState,
});

Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: we could assert cachedTimestamp also here expect(controller.state.cacheTimestamp).toBe(0);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good callout, added this additional assertion in daa2655

- clean up jsdoc comments
- add additional assertion that cache is set.
localOverrides: {},
rawRemoteFeatureFlags: {},
cacheTimestamp: 0,
previousClientVersion: undefined,
Copy link
Member

Choose a reason for hiding this comment

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

This should be causing a type error 🤔 undefined is strictly disallowed in controller state, we only allow JSON.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh wow interesting! Thanks for tagging, will clean up!

includeInDebugSnapshot: false,
usedInUi: false,
},
previousClientVersion: {
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure that we need an extra copy of this, we already have it in the AppMetadataController. Maybe we could get it from there instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm good callout!

Wondering if there is a controller race condition action issue?

Will do some testing!

Copy link
Member

Choose a reason for hiding this comment

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

It wouldn't be a race condition, but it would mean we'd strictly need to construct the AppMetadataController before this one. We try to avoid using actions/events in the constructor for this exact reason, to avoid initialization order requirements.

Could we fetch the AppMetadataController state lazily instead, rather than in the constructor? That would avoid any init order issues.

disabled = false,
getMetaMetricsId,
clientVersion,
prevClientVersion,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Now stateless. We can pass in the constructor parameter for the previous version.

Example on clients:

// the persisted current app ver is the new prevClientVersion we will pass into the `RemoteFeatureFlagController`.
const prevClientVersion =
    persistedState.AppMetadataController?.currentAppVersion;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll spin up preview builds on mobile and extension to validate.

…ersion

- Introduced optional prevClientVersion to manage feature flag cache invalidation.
- Updated JSDoc comments for clarity on new parameter usage.
@Prithpal-Sooriya Prithpal-Sooriya force-pushed the cursor/client-version-cache-invalidation-4c09 branch from a4e549b to 6dfa4ae Compare February 4, 2026 19:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Explore feature is not available when upgrading from 7.62.2/7.63.0 to 7.64.0

5 participants