Skip to content

Commit fa94b95

Browse files
feat(nimbus): default to group_id for desktop (#12540)
Because * In anticipation of the release of multiprofile support in desktop, it is time to switch the default randomization unit for desktop to group_id for all new experiments * We need to support both normandy_id and group_id for a period while currently live experiments still exist using normandy_id because when they pause they need to be reserialized and we need to preserve the normandy_id path * When there are no more live experiments using normandy_id we can remove the code for it entirely This commit * Changes use_group_id to default to True * Filters the cases where group_id is used to only include desktop * Updates tests fixes #12537
1 parent 3f4fa8f commit fa94b95

File tree

4 files changed

+77
-26
lines changed

4 files changed

+77
-26
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Generated by Django 5.1.8 on 2025-04-28 15:47
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
dependencies = [
8+
("experiments", "0280_nimbusexperiment_equal_branch_ratio"),
9+
]
10+
11+
operations = [
12+
migrations.AlterField(
13+
model_name="nimbusexperiment",
14+
name="use_group_id",
15+
field=models.BooleanField(default=True),
16+
),
17+
]

experimenter/experimenter/experiments/models.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ class NimbusExperiment(NimbusConstants, TargetingConstants, FilterMixin, models.
370370
blank=True,
371371
verbose_name="Subscribers",
372372
)
373-
use_group_id = models.BooleanField(default=False)
373+
use_group_id = models.BooleanField(default=True)
374374
objects = NimbusExperimentManager()
375375
is_firefox_labs_opt_in = models.BooleanField(
376376
"Is Experiment a Firefox Labs Opt-In?", default=False
@@ -1136,7 +1136,7 @@ def bucket_namespace(self):
11361136
keys.append(self.targeting_config_slug)
11371137
keys.append("rollout")
11381138

1139-
if self.use_group_id:
1139+
if self.is_desktop and self.use_group_id:
11401140
keys.append(BucketRandomizationUnit.GROUP_ID)
11411141

11421142
return "-".join(keys)
@@ -1795,7 +1795,10 @@ def __str__(self): # pragma: no cover
17951795

17961796
@property
17971797
def randomization_unit(self):
1798-
if self.bucket_ranges.filter(experiment__use_group_id=True).exists():
1798+
if self.bucket_ranges.filter(
1799+
experiment__use_group_id=True,
1800+
experiment__application=NimbusExperiment.Application.DESKTOP,
1801+
).exists():
17991802
return BucketRandomizationUnit.GROUP_ID
18001803
return NimbusExperiment.APPLICATION_CONFIGS[self.application].randomization_unit
18011804

experimenter/experimenter/experiments/tests/test_changelog_utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ def test_outputs_expected_schema_for_empty_experiment(self):
117117
"takeaways_summary": None,
118118
"targeting_config_slug": NimbusExperiment.TargetingConfig.NO_TARGETING,
119119
"total_enrolled_clients": 0,
120-
"use_group_id": False,
120+
"use_group_id": True,
121121
"vp_signoff": False,
122122
"warn_feature_schema": False,
123123
"published_date": None,
@@ -231,7 +231,7 @@ def test_outputs_expected_schema_for_complete_experiment(self):
231231
"takeaways_summary": None,
232232
"targeting_config_slug": experiment.targeting_config_slug,
233233
"total_enrolled_clients": experiment.total_enrolled_clients,
234-
"use_group_id": False,
234+
"use_group_id": True,
235235
"vp_signoff": False,
236236
"warn_feature_schema": False,
237237
"published_date": experiment.published_date,

experimenter/experimenter/experiments/tests/test_models.py

Lines changed: 52 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1246,7 +1246,10 @@ def test_launch_month_returns_enrollment_start_date(self):
12461246
self.assertEqual(experiment.launch_month, experiment.release_date.strftime("%B"))
12471247

12481248
@parameterized.expand(
1249-
[[NimbusExperiment.Status.LIVE], [NimbusExperiment.Status.COMPLETE]]
1249+
[
1250+
[NimbusExperiment.Status.LIVE],
1251+
[NimbusExperiment.Status.COMPLETE],
1252+
]
12501253
)
12511254
def test_start_date_uses_most_recent_start_change_without_cache(self, status):
12521255
experiment = NimbusExperimentFactory.create(status=status)
@@ -1265,7 +1268,10 @@ def test_start_date_uses_most_recent_start_change_without_cache(self, status):
12651268
self.assertEqual(experiment.start_date, start_change.changed_on.date())
12661269

12671270
@parameterized.expand(
1268-
[[NimbusExperiment.Status.LIVE], [NimbusExperiment.Status.COMPLETE]]
1271+
[
1272+
[NimbusExperiment.Status.LIVE],
1273+
[NimbusExperiment.Status.COMPLETE],
1274+
]
12691275
)
12701276
def test_start_date_uses_cached_start_date(self, status):
12711277
cached_date = datetime.date(2022, 1, 1)
@@ -2205,7 +2211,7 @@ def test_allocate_buckets_generates_bucket_range(self):
22052211
self.assertEqual(experiment.bucket_range.count, 5000)
22062212
self.assertEqual(
22072213
experiment.bucket_range.isolation_group.name,
2208-
"firefox-desktop-feature-release",
2214+
"firefox-desktop-feature-release-group_id",
22092215
)
22102216

22112217
def test_allocate_buckets_creates_new_bucket_range_if_population_changes(self):
@@ -2235,7 +2241,7 @@ def test_allocate_buckets_for_live_approved_rollout(self):
22352241
self.assertEqual(experiment.bucket_range.count, 5000)
22362242
self.assertEqual(
22372243
experiment.bucket_range.isolation_group.name,
2238-
"firefox-desktop-feature-release-mac_only-rollout",
2244+
"firefox-desktop-feature-release-mac_only-rollout-group_id",
22392245
)
22402246

22412247
def test_allocate_buckets_deletes_buckets_and_empty_isolation_group(self):
@@ -2318,7 +2324,7 @@ def test_bucket_namespace_changes_for_rollout(self):
23182324
self.assertNotEqual(original_namespace, experiment.bucket_namespace)
23192325
self.assertEqual(
23202326
experiment.bucket_namespace,
2321-
"firefox-desktop-feature-release-mac_only-rollout",
2327+
"firefox-desktop-feature-release-mac_only-rollout-group_id",
23222328
)
23232329

23242330
def test_required_experiments_branches(self):
@@ -3742,10 +3748,16 @@ def test_empty_isolation_group_creates_isolation_group_and_bucket_range(self):
37423748
self.assertEqual(bucket.isolation_group.name, experiment.slug)
37433749
self.assertEqual(bucket.isolation_group.instance, 1)
37443750
self.assertEqual(bucket.isolation_group.total, NimbusExperiment.BUCKET_TOTAL)
3745-
self.assertEqual(
3746-
bucket.isolation_group.randomization_unit,
3747-
experiment.application_config.randomization_unit,
3748-
)
3751+
if experiment.is_desktop:
3752+
self.assertEqual(
3753+
bucket.isolation_group.randomization_unit,
3754+
BucketRandomizationUnit.GROUP_ID,
3755+
)
3756+
else:
3757+
self.assertEqual(
3758+
bucket.isolation_group.randomization_unit,
3759+
experiment.application_config.randomization_unit,
3760+
)
37493761

37503762
def test_existing_isolation_group_adds_bucket_range(self):
37513763
"""
@@ -3764,10 +3776,16 @@ def test_existing_isolation_group_adds_bucket_range(self):
37643776
self.assertEqual(bucket.end, 99)
37653777
self.assertEqual(bucket.count, 100)
37663778
self.assertEqual(bucket.isolation_group, isolation_group)
3767-
self.assertEqual(
3768-
bucket.isolation_group.randomization_unit,
3769-
experiment.application_config.randomization_unit,
3770-
)
3779+
if experiment.is_desktop:
3780+
self.assertEqual(
3781+
bucket.isolation_group.randomization_unit,
3782+
BucketRandomizationUnit.GROUP_ID,
3783+
)
3784+
else:
3785+
self.assertEqual(
3786+
bucket.isolation_group.randomization_unit,
3787+
experiment.application_config.randomization_unit,
3788+
)
37713789

37723790
def test_existing_isolation_group_with_buckets_adds_next_bucket_range(self):
37733791
"""
@@ -3789,10 +3807,16 @@ def test_existing_isolation_group_with_buckets_adds_next_bucket_range(self):
37893807
self.assertEqual(bucket.end, 199)
37903808
self.assertEqual(bucket.count, 100)
37913809
self.assertEqual(bucket.isolation_group, isolation_group)
3792-
self.assertEqual(
3793-
bucket.isolation_group.randomization_unit,
3794-
experiment.application_config.randomization_unit,
3795-
)
3810+
if experiment.is_desktop:
3811+
self.assertEqual(
3812+
bucket.isolation_group.randomization_unit,
3813+
BucketRandomizationUnit.GROUP_ID,
3814+
)
3815+
else:
3816+
self.assertEqual(
3817+
bucket.isolation_group.randomization_unit,
3818+
experiment.application_config.randomization_unit,
3819+
)
37963820

37973821
def test_full_isolation_group_creates_next_isolation_group_adds_bucket_range(
37983822
self,
@@ -3819,10 +3843,17 @@ def test_full_isolation_group_creates_next_isolation_group_adds_bucket_range(
38193843
self.assertEqual(bucket.count, 100)
38203844
self.assertEqual(bucket.isolation_group.name, isolation_group.name)
38213845
self.assertEqual(bucket.isolation_group.instance, isolation_group.instance + 1)
3822-
self.assertEqual(
3823-
bucket.isolation_group.randomization_unit,
3824-
experiment.application_config.randomization_unit,
3825-
)
3846+
3847+
if experiment.is_desktop:
3848+
self.assertEqual(
3849+
bucket.isolation_group.randomization_unit,
3850+
BucketRandomizationUnit.GROUP_ID,
3851+
)
3852+
else:
3853+
self.assertEqual(
3854+
bucket.isolation_group.randomization_unit,
3855+
experiment.application_config.randomization_unit,
3856+
)
38263857

38273858
def test_isolation_group_with_group_id(
38283859
self,

0 commit comments

Comments
 (0)