From 4bc87f34b8935f8b8e29ed447f651c6f9ede0f38 Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Thu, 7 May 2026 15:59:30 -0700 Subject: [PATCH] fix: include experiment key on local-eval exposure events Local evaluation exposure events emit `metadata.experimentKey` inside the metadata blob but never lift it onto a top-level event property. Custom reports keying off `[Experiment] Experiment Key` therefore see no value for customers using local evaluation. When `variant.metadata['experimentKey']` is present, set `event_properties['[Experiment] Experiment Key']`. Mirrors the equivalent fix in the Node SDK (amplitude/experiment-node-server#83). Co-Authored-By: Claude Opus 4.7 --- .../exposure/exposure_service.py | 3 +++ tests/local/exposure/exposure_service_test.py | 18 ++++++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/amplitude_experiment/exposure/exposure_service.py b/src/amplitude_experiment/exposure/exposure_service.py index 6c50c7e..c940f2c 100644 --- a/src/amplitude_experiment/exposure/exposure_service.py +++ b/src/amplitude_experiment/exposure/exposure_service.py @@ -41,6 +41,9 @@ def to_exposure_events(exposure: Exposure, ttl_millis: int) -> List[BaseEvent]: event_properties['[Experiment] Variant'] = variant.key elif variant.value: event_properties['[Experiment] Variant'] = variant.value + experiment_key = variant.metadata.get('experimentKey') if variant.metadata is not None else None + if experiment_key: + event_properties['[Experiment] Experiment Key'] = experiment_key if variant.metadata: event_properties['metadata'] = variant.metadata diff --git a/tests/local/exposure/exposure_service_test.py b/tests/local/exposure/exposure_service_test.py index 6cea37e..af56619 100644 --- a/tests/local/exposure/exposure_service_test.py +++ b/tests/local/exposure/exposure_service_test.py @@ -50,6 +50,13 @@ def test_to_exposure_events(self): }) empty_metadata = Variant(key='on', value='on') empty_variant = Variant() + with_experiment_key = Variant(key='treatment', value='treatment', metadata={ + 'segmentName': 'All Other Users', + 'flagType': 'experiment', + 'flagVersion': 10, + 'default': False, + 'experimentKey': 'exp-1', + }) results = { 'basic': basic, 'different_value': different_value, @@ -59,12 +66,13 @@ def test_to_exposure_events(self): 'partial_metadata': partial_metadata, 'empty_metadata': empty_metadata, 'empty_variant': empty_variant, + 'with_experiment_key': with_experiment_key, } exposure = Exposure(user, results) events = to_exposure_events(exposure, DAY_MILLIS) # Should exclude default (default=True) only - # basic, different_value, mutex, holdout, partial_metadata, empty_metadata, empty_variant = 7 events - self.assertEqual(7, len(events)) + # basic, different_value, mutex, holdout, partial_metadata, empty_metadata, empty_variant, with_experiment_key = 8 events + self.assertEqual(8, len(events)) # Verify empty_variant is included empty_variant_events = [e for e in events if e.event_properties.get('[Experiment] Flag Key') == 'empty_variant'] @@ -95,6 +103,12 @@ def test_to_exposure_events(self): # If variant has no key or value (empty_variant), variant property may not be set if variant.metadata: self.assertEqual(variant.metadata, event.event_properties.get('metadata')) + + # Validate experiment key is lifted to top-level event property when present + if flag_key == 'with_experiment_key': + self.assertEqual('exp-1', event.event_properties.get('[Experiment] Experiment Key')) + else: + self.assertNotIn('[Experiment] Experiment Key', event.event_properties) # Validate user properties user_properties = event.user_properties