Skip to content

fix!: bucket per experiment and run in browsers (0.2.0) - #1

Merged
pranav2012 merged 2 commits into
mainfrom
fix/per-experiment-bucketing
Oct 16, 2026
Merged

pranav2012 merged 2 commits into
mainfrom
fix/per-experiment-bucketing

Conversation

@pranav2012

Copy link
Copy Markdown
Owner

Bug

getABExperimentBucket hashed only uniqueId; experimentName was never used. A user got the same variant in every experiment. Over 100k simulated users, the variant matched across two experiments 100% of the time, and 50% were in treatment for both (independent assignment gives 25%). Experiments running at the same time skewed each other's results.

Changes

  • Per-experiment hashing: the hash input is experimentName:uniqueId. legacyHashing: true buckets by uniqueId alone and reproduces 0.1.x exactly: 0 differences against the published 0.1.8 over 1M IDs with random splits and exposures.
  • Runs in browsers and edge runtimes: a small synchronous SHA-256 replaces node:crypto and Buffer, and the API stays sync. I ran the built ESM file in a browser and it gave the same assignments as Node.
  • Throws on invalid input (empty IDs, NaN or non-number percentages) instead of returning resolvedVariant: null.
  • Packaging: ships ESM and CJS with an exports map. The module field used to point at a file that didn't exist.
  • Tests: they pin exact buckets and check that experiments are independent, that raising exposure moves no one, and that raising the split only moves control to treatment. Coverage is 100%.
  • Release workflow: a version in package.json newer than the last release is used as-is, so this ships as 0.2.0 instead of an automatic 0.1.9 patch.

Breaking

Users are reassigned unless legacyHashing: true is passed, and invalid input now throws. The README has an "Upgrading from 0.1.x" section.

The hash ignored experimentName, so a user got the same variant in every
experiment: anyone in treatment for one experiment was in treatment for all
of them, and concurrent experiments skewed each other's results.

- Hash `experimentName:uniqueId`. `legacyHashing: true` buckets by uniqueId
  alone and reproduces 0.1.x exactly (checked against 0.1.8 over 1M IDs).
- Replace node:crypto and Buffer with a small synchronous SHA-256, so the
  package works in browsers and edge runtimes and the API stays sync.
- Throw on invalid input (empty IDs, NaN or non-number percentages) instead
  of returning resolvedVariant: null.
- Ship CommonJS as well as ES modules, with an exports map; the module field
  pointed at a file that didn't exist.
- Tests pin exact buckets and check independence across experiments and
  stability when exposure or the split is raised.

BREAKING CHANGE: users are reassigned unless legacyHashing is set. Invalid
input throws.
…t release

The workflow only ever bumped the patch number, so a breaking change
would have shipped as 0.1.9 to everyone on ^0.1.x.
@pranav2012
pranav2012 merged commit 390e636 into main Oct 16, 2026
1 check passed
@pranav2012
pranav2012 deleted the fix/per-experiment-bucketing branch October 16, 2026 22:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant