Skip to content

feat(experimentation): experiment metadata on feature states - #8532

Merged
Zaimwa9 merged 8 commits into
mainfrom
feat/experiment-feature-state-metadata
Sep 16, 2026
Merged

Zaimwa9 merged 8 commits into
mainfrom
feat/experiment-feature-state-metadata

Conversation

@Zaimwa9

@Zaimwa9 Zaimwa9 commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Thanks for submitting a PR! Please check the boxes below:

  • I have read the Contributing Guide.
  • I have added information to docs/ if required so people know about the feature.
  • I have filled in the "Changes" section below.
  • I have filled in the "How did you test this code" section below.

Changes

Feature states gain an optional metadata dict on the wire.
Its first key is experiment { id, name, in_experiment }, present only while the feature's experiment is running.
in_experiment is true on the rollout-segment override and false on the feature's other states, so the object survives whichever override wins evaluation.
Other features are untouched and metadata is omitted when empty.
Identity overrides never carry it: a hand-picked identity is not part of the experiment, on any evaluation route.

  • Engine model: FeatureStateModel.metadata, excluded when empty.
  • Document mapper: stamps the experimented feature's default and segment-override states, one prefetch of running experiments in filter_for_document_builder.
  • Experiment hook: republishes the environment document on pause / resume / rename, which did not touch feature states before.
  • Non-edge /identities: SDKIdentityFeatureStateSerializer emits the same object, in_experiment from the identity's segment evaluation. /flags unchanged.
  • Schemas: flagsmith-common 3.15.0 for FeatureStateMetadata, sdk/openapi.yaml regenerated.

Query counts on /identities and the environment document go up by one.

How did you test this code?

Unit tests for the mapper, compressed document, /identities, environment document endpoint and the hook.
Covers in / out of cohort, identity override, non-running statuses and the single experiment query with many experimented flags.
Staging QA against Edge #719 to follow.

@vercel

vercel Bot commented Sep 15, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

3 Skipped Deployments
Project Deployment Actions Updated
docs Ignored Ignored Preview Sep 16, 2026 8:19am UTC
flagsmith-frontend-preview Ignored Ignored Preview Sep 16, 2026 8:19am UTC
flagsmith-frontend-staging Ignored Ignored Preview Sep 16, 2026 8:19am UTC

Request Review

@coderabbitai

coderabbitai Bot commented Sep 15, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 591ece6f-9014-43c1-80e7-8a4e2a33560e

📥 Commits

Reviewing files that changed from the base of the PR and between 44d7bf0 and 45f25d7.

📒 Files selected for processing (2)
  • api/experimentation/feature_state_metadata.py
  • api/tests/unit/environments/identities/test_unit_identities_views.py

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

The change adds metadata for matching running experiments to feature states. Environment documents and identity responses expose the experiment ID, name, and in_experiment status. Metadata is omitted when no experiment matches or an identity override exists. Experiment status and name changes schedule an environment-document rebuild after commit. Engine models and API schemas support the metadata structure.

Priority: ➖ Normal

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk: 🔵 Low · up to 45f25

The generated schema may expose experiment metadata through /flags, contrary to the intended unchanged endpoint. Confirm the schema binding before merge.

Warning

Git: CodeRabbit could not clone the repository, so clone-backed analysis was skipped and this review may be incomplete. Verify repository clone access, such as SSH credentials, before requesting another full review. If clone access is intentionally unavailable, use path_filters to narrow the review scope.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added api Issue related to the REST API feature New feature or request labels Sep 15, 2026
@codecov

codecov Bot commented Sep 15, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.81%. Comparing base (9180452) to head (45f25d7).
⚠️ Report is 14 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8532      +/-   ##
==========================================
- Coverage   98.82%   98.81%   -0.01%     
==========================================
  Files        1622     1620       -2     
  Lines       66727    66185     -542     
==========================================
- Hits        65942    65400     -542     
  Misses        785      785              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions github-actions Bot added feature New feature or request and removed feature New feature or request labels Sep 15, 2026
@github-actions github-actions Bot added feature New feature or request and removed feature New feature or request labels Sep 15, 2026
@Zaimwa9

Zaimwa9 commented Sep 15, 2026

Copy link
Copy Markdown
Contributor Author

@themis-blindfold review

@Zaimwa9
Zaimwa9 marked this pull request as ready for review September 15, 2026 15:16
@Zaimwa9
Zaimwa9 requested review from a team as code owners September 15, 2026 15:16
@Zaimwa9
Zaimwa9 requested review from emyller and removed request for a team September 15, 2026 15:16
@github-actions github-actions Bot added feature New feature or request and removed feature New feature or request labels Sep 15, 2026
@github-actions

github-actions Bot commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Docker builds report

Image Build Status Security report
ghcr.io/flagsmith/flagsmith-e2e:pr-8532 Finished ✅ Skipped
ghcr.io/flagsmith/flagsmith-frontend:pr-8532 Finished ✅ Results
ghcr.io/flagsmith/flagsmith-api-test:pr-8532 Finished ✅ Skipped
ghcr.io/flagsmith/flagsmith-api:pr-8532 Finished ✅ Results
ghcr.io/flagsmith/flagsmith:pr-8532 Finished ✅ Results
ghcr.io/flagsmith/flagsmith-private-cloud:pr-8532 Finished ✅ Results

Comment thread api/util/mappers/engine.py
@themis-blindfold

Copy link
Copy Markdown
Contributor

⚖️ Themis review: 🟠 Fix before merge

The new experiment metadata reaches default and segment states, but not identity overrides in local-evaluation documents. That makes the metadata disappear precisely when an identity override wins evaluation. Completed API unit tests across Python 3.11–3.13 and static analysis checks passed; one third-party review check was still running.

Area Score
🎯 Correctness 3/5
🧪 Test coverage 3/5
📐 Code quality 4/5
🚀 Product impact 3/5

🟠 Majors

  • api/util/mappers/engine.py:306 — local evaluation omits experiment metadata when an identity override wins.
📝 Walkthrough
  • Metadata builder — indexes running experiments once per environment and classifies rollout overrides.
  • Environment documents — attach metadata to default and segment feature states, then persist or compress the document.
  • Identity endpoint — adds the optional object to evaluated identity flags and removes it when empty.
  • Lifecycle — republishes the environment document when an experiment's status or name changes.
🧪 How to verify
  1. Start an experiment, create an identity override for its feature, and request the local-evaluation environment document with identity overrides enabled.
  2. Evaluate that identity through the local-evaluation or Edge path and confirm the winning flag includes metadata.experiment.in_experiment: false.
  3. Pause, resume, and rename the experiment; confirm default, segment, and identity-override responses all update or remove the metadata consistently.
  4. Run cd api && uv run pytest tests/unit/util/mappers tests/unit/environments/identities/test_unit_identities_views.py.
    Automate: add a local-evaluation document test covering an experiment feature with an identity override.

Product take: This is a solid observability improvement for experiments, but its value drops for identities with explicit overrides until the local-evaluation path matches remote evaluation.

🧭 Assumptions & unverified claims

No unverified assumptions or claims.

One metadata field, two evaluation routes — they should agree. · reviewed at 44d7bf0

@github-actions

github-actions Bot commented Sep 15, 2026

Copy link
Copy Markdown
Contributor
✅ oss · depot-ubuntu-latest-arm-16 — run #20478 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-arm-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  45.9 seconds
commit  45f25d7
info  🔄 Run: #20478 (attempt 1)

🗂️ Previous results
✅ private-cloud · depot-ubuntu-latest-16 — run #20478 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-16)

passed  2 passed

Details

stats  2 tests across 2 suites
duration  48.4 seconds
commit  45f25d7
info  🔄 Run: #20478 (attempt 1)

✅ private-cloud · depot-ubuntu-latest-arm-16 — run #20478 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)

passed  25 passed
skipped  1 skipped

Details

stats  26 tests across 19 suites
duration  1 minute, 24 seconds
commit  45f25d7
info  🔄 Run: #20478 (attempt 1)

Skipped tests

firefox › tests/onboarding-tests.pw.ts › Onboarding › New user connects via the single-page onboarding flow @oss

✅ oss · depot-ubuntu-latest-16 — run #20478 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  33.5 seconds
commit  45f25d7
info  🔄 Run: #20478 (attempt 1)

✅ private-cloud · depot-ubuntu-latest-arm-16 — run #20465 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-arm-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  1 minute, 11 seconds
commit  44d7bf0
info  🔄 Run: #20465 (attempt 1)

✅ private-cloud · depot-ubuntu-latest-16 — run #20465 (attempt 1)

Playwright Test Results (private-cloud - depot-ubuntu-latest-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  56.5 seconds
commit  44d7bf0
info  🔄 Run: #20465 (attempt 1)

✅ oss · depot-ubuntu-latest-arm-16 — run #20465 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-arm-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  41.3 seconds
commit  44d7bf0
info  🔄 Run: #20465 (attempt 1)

✅ oss · depot-ubuntu-latest-16 — run #20465 (attempt 1)

Playwright Test Results (oss - depot-ubuntu-latest-16)

passed  1 passed

Details

stats  1 test across 1 suite
duration  34.6 seconds
commit  44d7bf0
info  🔄 Run: #20465 (attempt 1)

@coderabbitai coderabbitai 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.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 412362eb-b73b-41b4-8c6b-89afbd4002e8

📥 Commits

Reviewing files that changed from the base of the PR and between fb60f42 and 44d7bf0.

⛔ Files ignored due to path filters (1)
  • api/uv.lock is excluded by !**/*.lock
📒 Files selected for processing (16)
  • api/experimentation/feature_state_metadata.py
  • api/experimentation/models.py
  • api/features/serializers.py
  • api/pyproject.toml
  • api/tests/conftest.py
  • api/tests/integration/environments/identities/test_integration_identities.py
  • api/tests/unit/environments/identities/test_unit_identities_views.py
  • api/tests/unit/environments/test_unit_environments_models.py
  • api/tests/unit/environments/test_unit_environments_views_sdk_environment.py
  • api/tests/unit/experimentation/test_models.py
  • api/tests/unit/util/mappers/test_unit_mappers_dynamodb.py
  • api/tests/unit/util/mappers/test_unit_mappers_engine.py
  • api/util/engine_models/features/models.py
  • api/util/mappers/engine.py
  • openapi.yaml
  • sdk/openapi.yaml

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.

Comment thread openapi.yaml
@github-actions

github-actions Bot commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Visual Regression

19 screenshots compared. See report for details.
View full report

@Zaimwa9

Zaimwa9 commented Sep 15, 2026

Copy link
Copy Markdown
Contributor Author

@themis-blindfold review

@themis-blindfold

Copy link
Copy Markdown
Contributor

⚖️ Themis review: ✅ Ship it

The remote identity response and environment-state mappings attach experiment metadata with lifecycle updates rebuilding the document when it can change. Completed API unit tests (Python 3.12 and 3.13) and E2E checks passed; one Python 3.11 unit job was still running.

Focused local tests could not run because required dependencies could not be downloaded in this environment.

Area Score
🎯 Correctness 5/5
🧪 Test coverage 4/5
📐 Code quality 5/5
🚀 Product impact 4/5

⚖️ Acknowledged

  • The generated /flags schema advertises metadata although that endpoint leaves it out at runtime — thread resolved by @Zaimwa9
📝 Walkthrough
  • Metadata builder - looks up running experiments once per environment and marks only the rollout-segment state as enrolled.
  • Identity responses - add optional metadata while preserving omission for unaffected flags.
  • Environment documents - carry metadata through the engine model, SDK document, and compressed Dynamo document paths.
  • Experiment lifecycle - rebuilds the environment document after status or name changes.
🧪 How to verify
  1. Start an experiment with a rollout segment and request /api/v1/identities/ for identities inside and outside that segment.
  2. Fetch the environment document and confirm default and rollout-segment states carry the same experiment metadata with the appropriate in_experiment value.
  3. Pause, resume, and rename the experiment; confirm the rebuilt document removes, restores, or updates metadata accordingly.
  4. Run cd api && uv run pytest tests/unit/environments/identities/test_unit_identities_views.py tests/unit/util/mappers/test_unit_mappers_engine.py tests/unit/experimentation/test_models.py.
    Automate: assert an experiment status transition invalidates a conditional environment-document response.

Product take: Solid improvement for experiment consumers: exposure context now travels with evaluated states without changing evaluation itself.
This matters to SDK and Edge integrations, while leaving ordinary flag responses unchanged.

🧭 Assumptions & unverified claims

No unverified assumptions or claims.

Experiment metadata now has a passport for its trip through evaluation. · reviewed at 44d7bf0

@github-actions github-actions Bot added feature New feature or request and removed feature New feature or request labels Sep 16, 2026
@Zaimwa9
Zaimwa9 merged commit 6def014 into main Sep 16, 2026
35 checks passed
@Zaimwa9
Zaimwa9 deleted the feat/experiment-feature-state-metadata branch September 16, 2026 08:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api Issue related to the REST API feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants