evaluate

package
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 11, 2026 License: BSD-3-Clause Imports: 8 Imported by: 0

Documentation

Overview

Package evaluate provides local flag evaluation logic for the Flagmint Go SDK. It ports the flag-evaluator.ts logic from the JS SDK, enabling server-side applications to evaluate flags without a network round-trip.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrMissingRolloutKey is returned when a rollout requires a stable user
	// key (kind+key or user_id) but none is present in the context.
	ErrMissingRolloutKey = errors.New("rollout requires stable user key (kind+key or user_id)")

	// ErrPercentageNonBoolean is returned when a percentage rollout is applied
	// to a non-boolean flag. Use variant rollout for multi-value flags.
	ErrPercentageNonBoolean = errors.New("percentage rollout is boolean-only; use variant rollout for multi-value flags")

	// ErrGradualNonBoolean is returned when a gradual rollout is applied to a
	// non-boolean flag.
	ErrGradualNonBoolean = errors.New("gradual rollout is boolean-only; use variant rollout for multi-value flags")

	// ErrMissingSegment is returned when a targeting rule references a segment
	// ID that is not present in FlagConfig.SegmentsByID.
	ErrMissingSegment = errors.New("targeting rule references unknown segment")

	// ErrMissingVariation is returned when a targeting rule or off-variation
	// ID references a variation that is not present in FlagConfig.VariationsByID.
	ErrMissingVariation = errors.New("targeting rule references unknown variation")

	// ErrMissingRollout is returned when a targeting rule references a rollout
	// ID that is not present in FlagConfig.Rollouts.
	ErrMissingRollout = errors.New("targeting rule references unknown rollout")

	// ErrInvalidVariantWeights is returned when variant rollout weights do not
	// sum to 100.
	ErrInvalidVariantWeights = errors.New("variant weights must sum to 100")
)

Sentinel errors returned by the local evaluator. All evaluation errors are non-fatal; the caller should return the flag's fallback value and log the error rather than propagating it.

Functions

func CoerceBool

func CoerceBool(v any) (bool, error)

CoerceBool coerces v to a bool.

func CoerceFloat64

func CoerceFloat64(v any) (float64, error)

CoerceFloat64 coerces v to a float64.

func CoerceString

func CoerceString(v any) (string, error)

CoerceString coerces v to a string.

func HashPercent

func HashPercent(input string) int

HashPercent returns a stable bucket value in [0, 99] for rollout bucketing. Two callers with the same input always receive the same bucket.

func InRollout deprecated

func InRollout(key string, percentage float64) bool

InRollout returns true when the 0-based hash bucket for key falls within the [0, percentage) range (percentage expressed as 0–100).

Deprecated: uses FNV-1a (StableHash). New callers should use the Evaluator with a RolloutPercentage strategy, which uses StringHash for cross-SDK parity.

func MatchAll

func MatchAll(rules []Condition, attrs map[string]any) bool

MatchAll returns true when every condition in rules matches attrs. Kept for backward compatibility; new code should use evaluateConditions.

func StableHash deprecated

func StableHash(s string) uint32

StableHash returns a deterministic 32-bit hash for s using FNV-1a.

Deprecated: use StringHash for cross-SDK hash parity with the JS evaluator. StableHash is retained for callers that rely on InRollout / VariantForKey.

func StringHash

func StringHash(s string) uint32

StringHash produces a 32-bit hash identical to the npm `string-hash` package (djb2 variant). This is the hash used for rollout bucketing to guarantee cross-SDK consistency: a user bucketed at 30% in the JS SDK must land in the same bucket in the Go SDK.

func VariantForKey deprecated

func VariantForKey(key string, variants []string) string

VariantForKey maps key to one of the provided variant names using a stable hash. The variants slice must be non-empty.

Deprecated: uses FNV-1a (StableHash). New callers should use the Evaluator with a RolloutVariant strategy, which uses StringHash for cross-SDK parity.

Types

type Condition

type Condition struct {
	Attribute string   `json:"attribute"`
	Operator  Operator `json:"operator"`
	Value     any      `json:"value"`
}

Condition is a single attribute comparison in a targeting rule.

func (Condition) Match

func (c Condition) Match(attrs map[string]any) bool

Match returns true when the flat context attributes satisfy the condition.

type Evaluator

type Evaluator struct {
	// contains filtered or unexported fields
}

Evaluator evaluates feature flags locally against FlagConfig objects. It is safe for concurrent use by multiple goroutines.

func NewEvaluator

func NewEvaluator() *Evaluator

NewEvaluator returns a new Evaluator using the default slog logger.

func NewEvaluatorWithLogger

func NewEvaluatorWithLogger(logger *slog.Logger) *Evaluator

NewEvaluatorWithLogger returns a new Evaluator with the provided logger.

func (*Evaluator) Evaluate

func (e *Evaluator) Evaluate(config *FlagConfig, flatCtx map[string]any) (any, error)

Evaluate evaluates config against the pre-flattened context map flatCtx and returns the resulting flag value. flatCtx should be produced by calling EvaluationContext.Flatten() before passing here.

On any evaluation error (missing segment, bad config, etc.) the method returns the coerced default value and the error so the caller can log it. Evaluation never panics.

type FlagConfig

type FlagConfig struct {
	Key            string          `json:"key"`
	Type           FlagType        `json:"type"`
	IsActive       bool            `json:"is_active"`
	DefaultValue   any             `json:"default_value"`
	OffVariationID *string         `json:"off_variation_id,omitempty"`
	TargetingRules []TargetingRule `json:"targeting_rules,omitempty"`
	Variations     []Variation     `json:"variations,omitempty"`
	// Rollouts maps rollout ID → Rollout for targeting-rule lookups.
	Rollouts map[string]*Rollout `json:"rollouts,omitempty"`

	// VariationsByID is populated by HydrateVariations; not serialised.
	VariationsByID map[string]Variation `json:"-"`
	// SegmentsByID must be populated before calling Evaluate when any
	// targeting rule has kind="segment". Not serialised.
	SegmentsByID map[string]*Segment `json:"-"`
}

FlagConfig is the full flag configuration used for local evaluation. Deserialize from the server payload, then call HydrateVariations before passing to Evaluator.Evaluate.

func (*FlagConfig) HydrateVariations

func (fc *FlagConfig) HydrateVariations()

HydrateVariations populates VariationsByID from the Variations slice. Call this once after deserialising a FlagConfig from JSON.

type FlagType

type FlagType string

FlagType enumerates the supported flag value types.

const (
	FlagTypeBoolean FlagType = "boolean"
	FlagTypeString  FlagType = "string"
	FlagTypeNumber  FlagType = "number"
	FlagTypeJSON    FlagType = "json"
)

type LogicalOperator

type LogicalOperator string

LogicalOperator determines how conditions are combined.

const (
	LogicalAND LogicalOperator = "AND"
	LogicalOR  LogicalOperator = "OR"
	LogicalNOT LogicalOperator = "NOT"
)

type Operator

type Operator string

Operator is a comparison operator used in targeting-rule conditions.

const (
	OpEquals      Operator = "eq"
	OpNotEquals   Operator = "neq"
	OpContains    Operator = "contains"
	OpNotContains Operator = "not_contains"
	OpGreaterThan Operator = "gt"
	OpLessThan    Operator = "lt"
	OpIn          Operator = "in"
	// OpNin is the "not in" operator. Values is expected to be []any.
	OpNin        Operator = "nin"
	OpStartsWith Operator = "startsWith"
	OpEndsWith   Operator = "endsWith"
	// OpExists is true when the attribute is present in the context and not nil.
	OpExists Operator = "exists"
	// OpNotExists is true when the attribute is absent from the context or nil.
	OpNotExists Operator = "not_exists"
)

type Rollout

type Rollout struct {
	ID               string          `json:"id,omitempty"`
	Strategy         RolloutKind     `json:"strategy"`
	Percentage       float64         `json:"percentage,omitempty"`
	Salt             string          `json:"salt"`
	Variants         []VariantWeight `json:"variants,omitempty"`
	TargetPercentage float64         `json:"target_percentage,omitempty"`
	Increment        float64         `json:"increment,omitempty"`
	IntervalHours    float64         `json:"interval_hours,omitempty"`
	StartAt          *time.Time      `json:"start_at,omitempty"`
}

Rollout defines how flag values are distributed across users.

type RolloutKind

type RolloutKind string

RolloutKind enumerates the supported rollout strategies.

const (
	// RolloutOff disables the rollout; the flag returns its default value.
	RolloutOff RolloutKind = "off"
	// RolloutPercentage enables a flag for a stable percentage of users (boolean-only).
	RolloutPercentage RolloutKind = "percentage"
	// RolloutVariant distributes traffic across named variations using weighted buckets.
	RolloutVariant RolloutKind = "variant"
	// RolloutGradual slowly ramps a boolean flag from 0% to TargetPercentage over time.
	RolloutGradual RolloutKind = "gradual"
)

type Segment

type Segment struct {
	ID        string          `json:"id"`
	Rules     []Condition     `json:"rules"`
	LogicalOp LogicalOperator `json:"logical_op"`
	// Force, when true, causes the segment to always match regardless of conditions.
	Force bool `json:"force"`
}

Segment is a reusable group of conditions evaluated as a unit.

type TargetingRule

type TargetingRule struct {
	ID          string          `json:"id"`
	Kind        string          `json:"kind"` // "segment" | "custom"
	OrderIndex  int             `json:"order_index"`
	SegmentID   string          `json:"segment_id,omitempty"`
	Conditions  []Condition     `json:"conditions,omitempty"`
	LogicalOp   LogicalOperator `json:"logical_op,omitempty"`
	VariationID *string         `json:"variation_id,omitempty"`
	RolloutID   *string         `json:"rollout_id,omitempty"`
}

TargetingRule is a single rule in the targeting chain. Rules are evaluated in ascending OrderIndex order; the first match wins.

type VariantWeight

type VariantWeight struct {
	VariationID string  `json:"variation_id"`
	Weight      float64 `json:"weight"`
}

VariantWeight pairs a variation with its traffic allocation weight (0–100).

type Variation

type Variation struct {
	ID    string `json:"id"`
	Value any    `json:"value"`
}

Variation is a possible flag value.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL