Skip to content

feat: support Mutex and Holdout groups for web experiment#324

Merged
tyiuhc merged 7 commits into
mainfrom
web/mutex-holdout
Jun 4, 2026
Merged

feat: support Mutex and Holdout groups for web experiment#324
tyiuhc merged 7 commits into
mainfrom
web/mutex-holdout

Conversation

@tyiuhc

@tyiuhc tyiuhc commented May 19, 2026

Copy link
Copy Markdown
Collaborator

Summary

Support Mutex and Holdout groups for web experiment.

Flags that transitively depend on a remote-evaluated flag (e.g. a Mutex or Holdout parent) are now promoted to remote evaluation via a fixed-point dependency walk. This ensures child flags wait for their remote dependencies to be fetched before bucketing runs, preventing incorrect variant assignment.

Checklist

  • Does your PR title have the correct title format?
  • Does your PR have a breaking change?: No

Note

Medium Risk
Changes flag evaluation ordering and startup timing for experiments with flag dependencies or holdout/mutex flags, which can affect which variants users see on first paint.

Overview
Web experiment startup now treats local flags that depend on a remote flag (including transitive chains) as remote so variant application waits until remote parents are fetched, avoiding wrong mutex/holdout bucketing from stale parent state. Only flags promoted via that dependency walk are removed from the early local apply pass; directly remote flags that are session-cached as local still get the fast-path local apply.

When any initial flag key starts with holdout- or mutex-, start() awaits integrationManager.ready() before applying variants so bucketing has user_id / device_id from the Amplitude integration setup.

Adds a test that a depth-2 local→local→remote dependency chain is not applied on the first local applyVariants call and is applied after remote fetch.

Reviewed by Cursor Bugbot for commit d232bbf. Bugbot is set up for automated code reviews on this repo. Configure here.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

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.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Local flags with remote dependencies applied prematurely
    • Added filter to exclude remoteFlagKeys members from localFlagKeys at line 218, ensuring flags with transitive remote dependencies wait for fetchRemoteFlags() before being applied.

Create PR

Or push these changes by commenting:

@cursor push 59cf49554e
Preview (59cf49554e)
diff --git a/packages/experiment-tag/src/experiment.ts b/packages/experiment-tag/src/experiment.ts
--- a/packages/experiment-tag/src/experiment.ts
+++ b/packages/experiment-tag/src/experiment.ts
@@ -214,9 +214,12 @@
       ...this.config,
     });
     // Get all the locally available flag keys from the SDK.
+    // Exclude flags that were moved to remoteFlagKeys due to transitive dependencies.
     const variants = this.experimentClient.all();
     this.localFlagKeys = Object.keys(variants).filter(
-      (key) => variants[key]?.metadata?.evaluationMode === 'local',
+      (key) =>
+        variants[key]?.metadata?.evaluationMode === 'local' &&
+        !this.remoteFlagKeys.includes(key),
     );
     this.messageBus = new MessageBus();
   }

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit 7b7dba7. Configure here.

Comment thread packages/experiment-tag/src/experiment.ts
@tyiuhc tyiuhc requested a review from a team May 21, 2026 21:50
Comment thread packages/experiment-tag/src/experiment.ts
@tyiuhc tyiuhc merged commit 95bd81a into main Jun 4, 2026
9 checks passed
@tyiuhc tyiuhc deleted the web/mutex-holdout branch June 4, 2026 21:16
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.

3 participants