Skip to content

fix(features): preserve multivariate bucketing salt across feature state recreation#7914

Merged
gagantrivedi merged 9 commits into
mainfrom
fix/7913-mv-hashing-salt
Jul 14, 2026
Merged

fix(features): preserve multivariate bucketing salt across feature state recreation#7914
gagantrivedi merged 9 commits into
mainfrom
fix/7913-mv-hashing-salt

Conversation

@gagantrivedi

@gagantrivedi gagantrivedi commented Jun 30, 2026

Copy link
Copy Markdown
Member
  • 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

Closes #7913

Multivariate bucketing is salted on the feature state id, so any flow that
recreates a feature state (version publish, weight edits, change request
commits) re-bucketed already-enrolled identities.

  • Add FeatureState.mv_hashing_salt (nullable, internal — not exposed via API
    or audit logs). Bucketing seeds on the new mv_hashing_seed property
    (salt or id); no backfill needed.
  • A BEFORE_CREATE hook makes any new multivariate feature state inherit the
    seed from the live state it supersedes, so every creation path (change
    request drafts, direct recreates, version edits) keeps bucketing stable
    without knowing the salt exists. clone() copies it like any other field.
  • Engine mapper emits the seed as django_id, so Core, Edge and local-eval
    SDKs bucket identically with no document schema change.

Known gap: v1 change request drafts already open when this deploys predate the
salt and will re-bucket once when committed — that is today's behaviour, one
last time; not worth a backfill migration.

How did you test this code?

Unit tests: seed fallback, clone preservation (50 identities keep their
variant), engine mapper output, seed inheritance for v1/v2 direct recreates
and fresh lineages, and change request commits keeping variant assignment
stable end to end.

@vercel

vercel Bot commented Jun 30, 2026

Copy link
Copy Markdown

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

3 Skipped Deployments
Project Deployment Actions Updated (UTC)
docs Ignored Ignored Preview Jul 14, 2026 6:37am
flagsmith-frontend-preview Ignored Ignored Preview Jul 14, 2026 6:37am
flagsmith-frontend-staging Ignored Ignored Preview Jul 14, 2026 6:37am

Request Review

@github-actions github-actions Bot added the api Issue related to the REST API label Jun 30, 2026
@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

No new commits to review since the last review.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 9e232511-486e-480f-8ee3-e6013bcca604

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • ✅ Review completed - (🔄 Check again to review again)
📝 Walkthrough

Walkthrough

Adds a nullable mv_hashing_salt to feature-state models and historical records. Multivariate bucketing and engine mapping now use this salt, falling back to the feature-state ID, while cloning preserves the selected value. Serializer and audit output exclude the field. Creation logic inherits the seed from superseded live states, and unit tests cover hashing, cloning, mapping, and versioning behaviour.

Estimated code review effort: 3 (Moderate) | ~25 minutes


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

@codecov

codecov Bot commented Jul 13, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.63%. Comparing base (1c73453) to head (00eb496).
⚠️ Report is 6 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff            @@
##             main    #7914    +/-   ##
========================================
  Coverage   98.63%   98.63%            
========================================
  Files        1496     1497     +1     
  Lines       59072    59261   +189     
========================================
+ Hits        58266    58455   +189     
  Misses        806      806            

☔ 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.

…ate recreation

Multivariate variant bucketing is salted on the feature state id, so any flow
that recreates a feature state (publishing a new v2 version, editing
multivariate weights) changed the salt and re-bucketed already-enrolled
identities.

Add an mv_hashing_salt field that get_multivariate_feature_state_value seeds on
(falling back to the id), preserved across clone() so recreation keeps the
original seed. The engine mapper feeds the salt through django_id, so edge and
local evaluation stay stable without an engine document schema change.

Also add a BEFORE_CREATE guard that raises when a v2 feature state is recreated
outside clone() (the previous version already had it but the new row carries no
salt), to catch future regressions in tests.

Closes #7913
@gagantrivedi gagantrivedi force-pushed the fix/7913-mv-hashing-salt branch from 71ba4ee to 0822078 Compare July 13, 2026 08:45
@gagantrivedi gagantrivedi force-pushed the fix/7913-mv-hashing-salt branch from 0822078 to a32e197 Compare July 13, 2026 08:59
@gagantrivedi gagantrivedi changed the title WIP: fix(features): preserve multivariate bucketing salt across feature state recreation fix(features): preserve multivariate bucketing salt across feature state recreation Jul 13, 2026
@gagantrivedi gagantrivedi marked this pull request as ready for review July 13, 2026 09:11
@gagantrivedi gagantrivedi requested a review from a team as a code owner July 13, 2026 09:11
@gagantrivedi gagantrivedi requested review from emyller and removed request for a team July 13, 2026 09:11
@github-actions github-actions Bot added the fix label Jul 13, 2026
@github-actions

github-actions Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Docker builds report

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

@github-actions

github-actions Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

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

passed  4 passed

Details

stats  4 tests across 3 suites
duration  33.9 seconds
commit  04a287e
info  🔄 Run: #18185 (attempt 1)

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

passed  4 passed

Details

stats  4 tests across 3 suites
duration  47.6 seconds
commit  04a287e
info  🔄 Run: #18185 (attempt 1)

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

passed  7 passed

Details

stats  7 tests across 5 suites
duration  12.7 seconds
commit  04a287e
info  🔄 Run: #18185 (attempt 1)

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

failed  1 failed
passed  1 passed

Details

stats  2 tests across 2 suites
duration  46.8 seconds
commit  04a287e
info  📦 Artifacts: View test results and HTML report
🔄 Run: #18185 (attempt 1)

Failed tests

firefox › tests/environment-permission-test.pw.ts › Environment Permission Tests › Environment-level permissions control access to features, identities, and segments @enterprise

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

passed  4 passed

Details

stats  4 tests across 4 suites
duration  34.6 seconds
commit  04a287e
info  🔄 Run: #18185 (attempt 2)

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

passed  4 passed

Details

stats  4 tests across 3 suites
duration  41.9 seconds
commit  1d015c5
info  🔄 Run: #18222 (attempt 1)

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

passed  4 passed

Details

stats  4 tests across 3 suites
duration  44.4 seconds
commit  1d015c5
info  🔄 Run: #18222 (attempt 1)

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

passed  4 passed

Details

stats  4 tests across 3 suites
duration  1 minute, 2 seconds
commit  1d015c5
info  🔄 Run: #18222 (attempt 1)

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

passed  2 passed

Details

stats  2 tests across 2 suites
duration  46.3 seconds
commit  1d015c5
info  🔄 Run: #18222 (attempt 1)

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

passed  4 passed

Details

stats  4 tests across 3 suites
duration  41.8 seconds
commit  00eb496
info  🔄 Run: #18227 (attempt 1)

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

passed  4 passed

Details

stats  4 tests across 3 suites
duration  47.2 seconds
commit  00eb496
info  🔄 Run: #18227 (attempt 1)

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

passed  5 passed

Details

stats  5 tests across 3 suites
duration  36.4 seconds
commit  00eb496
info  🔄 Run: #18227 (attempt 1)

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

passed  1 passed

Details

stats  1 test across 1 suite
duration  53.2 seconds
commit  00eb496
info  🔄 Run: #18227 (attempt 1)

@gagantrivedi gagantrivedi requested review from Zaimwa9 and removed request for emyller July 13, 2026 09:19
@github-actions

github-actions Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Visual Regression

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

@github-actions github-actions Bot added fix and removed fix labels Jul 14, 2026
@gagantrivedi gagantrivedi marked this pull request as draft July 14, 2026 06:07
@github-actions github-actions Bot added fix and removed fix labels Jul 14, 2026
@github-actions github-actions Bot added fix and removed fix labels Jul 14, 2026
@github-actions github-actions Bot added fix and removed fix labels Jul 14, 2026
@github-actions github-actions Bot added fix and removed fix labels Jul 14, 2026
@gagantrivedi gagantrivedi marked this pull request as ready for review July 14, 2026 06:38
@github-actions github-actions Bot added fix and removed fix labels Jul 14, 2026
@Zaimwa9

Zaimwa9 commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

@CodeRabbit review

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@Zaimwa9 Zaimwa9 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ok great, good call to have pushed back and rethink the implementation.

I couldn't find flaws in it and it simplified a lot the mental model. Approving with one nit that shouldn't happen normally so feel free to resolve and ignore

Comment thread api/features/models.py
Comment thread api/util/mappers/engine.py
@gagantrivedi gagantrivedi merged commit 62a8143 into main Jul 14, 2026
51 checks passed
@gagantrivedi gagantrivedi deleted the fix/7913-mv-hashing-salt branch July 14, 2026 08:31
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 fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MV variant bucketing reshuffles when feature state is recreated (v2 versioning)

2 participants