File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change 1+ import { describe , it , expect } from "vitest" ;
2+ import { hashBucket } from "./computeBucket" ;
3+
4+ describe ( "hashBucket" , ( ) => {
5+ it ( "returns a stable value in [0, 100) for the same id" , ( ) => {
6+ const a = hashBucket ( "org_abc" ) ;
7+ const b = hashBucket ( "org_abc" ) ;
8+ expect ( a ) . toBe ( b ) ;
9+ expect ( a ) . toBeGreaterThanOrEqual ( 0 ) ;
10+ expect ( a ) . toBeLessThan ( 100 ) ;
11+ } ) ;
12+
13+ it ( "is nested: the set enrolled at 1% is a subset of the set at 5%" , ( ) => {
14+ const ids = Array . from ( { length : 5000 } , ( _ , i ) => `org_${ i } ` ) ;
15+ const at1 = new Set ( ids . filter ( ( id ) => hashBucket ( id ) < 1 ) ) ;
16+ const at5 = ids . filter ( ( id ) => hashBucket ( id ) < 5 ) ;
17+ for ( const id of at1 ) {
18+ expect ( at5 ) . toContain ( id ) ;
19+ }
20+ } ) ;
21+
22+ it ( "distributes roughly uniformly" , ( ) => {
23+ const ids = Array . from ( { length : 10000 } , ( _ , i ) => `org_${ i } ` ) ;
24+ const under10 = ids . filter ( ( id ) => hashBucket ( id ) < 10 ) . length ;
25+ expect ( under10 ) . toBeGreaterThan ( 700 ) ;
26+ expect ( under10 ) . toBeLessThan ( 1300 ) ;
27+ } ) ;
28+ } ) ;
Original file line number Diff line number Diff line change 1+ /**
2+ * Deterministic 0-99 bucket for an org id, stable across processes and deploys.
3+ * FNV-1a (non-crypto): we only need determinism + uniform spread, not collision
4+ * resistance. Used for nested percentage rollout: `hashBucket(orgId) < percentage`.
5+ * Ramping the percentage down keeps a strict subset (the low buckets), so an org
6+ * never flaps in and out as the dial moves.
7+ */
8+ export function hashBucket ( orgId : string ) : number {
9+ let hash = 0x811c9dc5 ; // FNV offset basis
10+ for ( let i = 0 ; i < orgId . length ; i ++ ) {
11+ hash ^= orgId . charCodeAt ( i ) ;
12+ hash = Math . imul ( hash , 0x01000193 ) >>> 0 ;
13+ }
14+ return hash % 100 ;
15+ }
You can’t perform that action at this time.
0 commit comments