Repository navigation
Conversation
This was referenced Oct 21, 2026
Open
vazarkevych
reviewed
Oct 21, 2026
vazarkevych
left a comment
Collaborator
There was a problem hiding this comment.
Reviewed: LGTM.
Correctness
- After this change
getBucketRangesmatches the JS SDK (util.ts) exactly: same weight/coverage arithmetic, equal weights1/n, andchooseVariationuses the samen >= start && n < endtest. isCompareBucketnow compares atfloor(n * 1e8) / 1e8, the same tolerance asjson.test.tsin the JS SDK. Exact comparison can't hold for unrounded doubles (0.2 + 0.06 != 0.26), so this is the right fix rather than a loosened test.- Verified that the new
runcases fail with the oldgb_utils.dartand pass with the fix. CI is green. - No other SDK code calls
DoubleExt.roundTo: theroundToingb_utils.dartis a separate extension onnum. So the deprecation won't tripdeprecated_member_use_from_same_packageon the CI's Flutter 3.27 analyzer.
Compatibility
- No API break:
roundTois deprecated, not removed. - Behavior: only users whose hash lies within 0.0001 below a range boundary change variation (about 0.01% per boundary), and they move to the variation the JS SDK and other SDKs already assign. Users with a sticky-bucket assignment are unaffected. We treat this as a
fix(minor), but suggest one line in the release notes: "bucket range boundaries now match the JS SDK exactly".
Notes
- The 7
runcases, 2featurecases and 9 hash pins are not incases.json0.9.0 yet; they come from growthbook/growthbook#7375, which is still open. If that PR changes, these cases need to be resynced. - The 2 rollout-boundary
featurecases also pass on the old code (rollouts don't go throughgetBucketRanges). That's fine as regression pins. - Merge order: see #192. This PR conflicts with #178 and #174 in
test/test_cases/test_case.dart; when those are resolved, these cases must be kept, since they are not in the 0.9.0 spec.
andywhite37
approved these changes
Oct 21, 2026
andywhite37
left a comment
Contributor
There was a problem hiding this comment.
No findings; the boundary cases pass and GitHub CI passes. All 341 tests pass serially; the parallel run failed the unchanged 304 cache test while tests shared a cache directory. Device testing was not performed.
andywhite37
added a commit
that referenced
this pull request
Oct 26, 2026
…ypes Brings in growthbook-flutter#184 by gazzdingo: bucket ranges are no longer truncated to 4 decimals, so users whose hash lands on a range end are assigned like the JS SDK (spec 0.11.2 range-end cases from growthbook/growthbook#7375). test/test_cases/test_case.dart keeps this branch's verbatim spec 0.11.2 snapshot. #184's added "rollout includes the user at exactly coverage" cases are superseded by growthbook/growthbook#7425 (n < coverage). BREAKING CHANGE: users whose hash falls between a truncated and an exact bucket range end can be assigned a different variation.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
getBucketRangespassed every range start and end throughroundTo(4), which is(x * 10000).toInt() / 10000, so it truncates rather than rounds: 0.344 became 0.3439 and 0.172 became 0.1719. The JS SDK (the reference) keeps the raw doubles. A user whose hash lands on or just inside a range end therefore got a different variation than in JS.This came out of a cross-SDK bucketing audit. The shared spec is getting 7 new
runcases for users whose hash lands exactly on a range end (growthbook/growthbook#7375); 4 of them failed here.gb_utils.dart: push[start, end]unrounded.test/test_cases/test_case.dart: the 7 new run cases, 2 rollout-boundary feature cases and 9 hash pins appended.DoubleExt.roundTois deprecated (public API, no longer used by the SDK).gb_utils_test.dart:isCompareBucketcompared exactly, which can't hold for raw doubles (0.2 + 0.06 ≠ the spec's0.26); it now mirrors the JS spec test (floor(n * 1e8) / 1e8on both sides).Testing (
flutter testinghcr.io/cirruslabs/flutter:stable): main is 341 passed. With the new cases on the old code, the run spec test fails with 4 failing cases. With the fix: 341 passed, 0 failed.