Ctrl K
ComunidadGuías…

internal/rollout/bucketing.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
// Package rollout implements the deterministic device bucketing behind progressive
// rollouts. Manifest and asset resolution share these functions so the two paths can
// never disagree about which cohort a device belongs to. No per-device state is stored:
// the bucket is a salted hash of the persistent EAS-Client-ID.
package rollout

import (
	"crypto/sha256"
	"encoding/binary"
	"math"
)

// Bucket maps a device to a stable position in [0, 1) for the given salt. An empty
// clientID returns 1.0 so a device that sends no EAS-Client-ID is never in a rollout.
func Bucket(clientID string, salt string) float64 {
	if clientID == "" {
		return 1.0
	}
	sum := sha256.Sum256([]byte(clientID + ":" + salt))
	return float64(binary.BigEndian.Uint64(sum[:8])) / float64(math.MaxUint64)
}

// InBucket reports whether the device falls inside a rollout serving percentage% of
// devices. Monotonic in percentage: a device inside at N stays inside at every M > N,
// so increasing a rollout never flips an already-served device back out.
func InBucket(clientID string, salt string, percentage int) bool {
	return Bucket(clientID, salt) < float64(percentage)/100
}

// UpdateSalt derives the fixed bucketing salt of a per-update rollout. Channel rollouts
// use the rollout row's UUID instead; the "update:" prefix keeps the two salt spaces
// structurally disjoint so the mechanisms draw independent cohorts.
func UpdateSalt(appId string, branchName string, runtimeVersion string, updateId string) string {
	return "update:" + appId + ":" + branchName + ":" + runtimeVersion + ":" + updateId
}