Module: Feat::Bucketing
- Defined in:
- lib/feat/bucketing.rb
Overview
Deterministic bucketing for percentage rollouts. Algorithm matches @feathq/feat-eval (JS), feat-go-sdk (Go), and feat (Python) bit-for-bit:
sha1(salt + "." + flag_key + "." + context_key)
-> first 8 bytes as big-endian uint64
-> shift right 4 (drop low bits) for exactly 60 bits
-> modulo 100_000
Constant Summary collapse
- BUCKET_SCALE =
100_000
Class Method Summary collapse
- .bucket(salt:, flag_key:, context_key:) ⇒ Object
-
.pick_by_weight(bucket_value, variations) ⇒ Object
Walk cumulative weights; return the variation whose range contains bucket_value.
Class Method Details
.bucket(salt:, flag_key:, context_key:) ⇒ Object
17 18 19 20 21 22 |
# File 'lib/feat/bucketing.rb', line 17 def bucket(salt:, flag_key:, context_key:) digest = Digest::SHA1.digest("#{salt}.#{flag_key}.#{context_key}") first8 = digest[0, 8].unpack1("Q>") # big-endian unsigned 64-bit sixty = first8 >> 4 sixty % BUCKET_SCALE end |
.pick_by_weight(bucket_value, variations) ⇒ Object
Walk cumulative weights; return the variation whose range contains bucket_value. Defensive fallback to the last variation if upstream weights underflow the scale.
27 28 29 30 31 32 33 34 |
# File 'lib/feat/bucketing.rb', line 27 def pick_by_weight(bucket_value, variations) cumulative = 0 variations.each do |v| cumulative += v.weight return v.variationId if bucket_value < cumulative end variations.empty? ? nil : variations.last.variationId end |