Documentation
¶
Overview ¶
Package features is a small runtime feature-flag layer for Overkill (Phase 1.5 #4). Lighter than LaunchDarkly — no network, no dependencies — but richer than static config because flags can gate on USER, CHANNEL, or a PERCENTAGE rollout per request.
Three layers (highest precedence first):
- Per-user override (Flag.UserOverrides[userID])
- Per-channel override (Flag.ChannelOverrides[channelID])
- Percentage rollout (Flag.Percent, deterministic hash of context)
- Default (Flag.Default)
All flags are evaluated against an EvalContext. A missing flag is treated as disabled (safe default — code paths gated behind a flag shouldn't activate just because the flag name was typo'd).
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type EvalContext ¶
type EvalContext struct {
UserID string
Channel string
// Subject is the optional unit-of-rollout key. When set, percent
// rollout hashes against this string so a given subject (e.g.
// session ID, project name) gets a STABLE bucket. When empty,
// UserID is used as the subject. When both empty, percent rollout
// is treated as disabled (no stable bucket = unsafe to flip).
Subject string
}
EvalContext supplies the inputs the layered rules evaluate against. All fields optional — an empty context evaluates only the Default.
type Flag ¶
type Flag struct {
Name string `toml:"-" json:"name"`
Default bool `toml:"default" json:"default"`
Percent int `toml:"percent" json:"percent"` // 0..100; 0 = disabled rollout
UserOverrides map[string]bool `toml:"users" json:"users,omitempty"` // userID → enabled
ChannelOverrides map[string]bool `toml:"channels" json:"channels,omitempty"`
Tags map[string]string `toml:"tags" json:"tags,omitempty"` // free-form metadata for UI
}
Flag is a single named gate.
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager holds a set of flags and evaluates them concurrently.
func NewManager ¶
func NewManager() *Manager
NewManager returns an empty manager. Use Register / LoadDefaults / LoadFromTOML to populate.
func (*Manager) Enabled ¶
func (m *Manager) Enabled(name string, ctx EvalContext) bool
Enabled evaluates the named flag against ctx and returns the decision. Unknown flag → false (safe default).
Layering (highest precedence first):
- UserOverrides[ctx.UserID] if entry present
- ChannelOverrides[ctx.Channel] if entry present
- Percent rollout if Percent > 0 AND subject available. Subject is the primary roll-out key (e.g. a user ID). When Subject is empty, UserID is used as a fallback. When both are empty the percent check is silently skipped — no one gets the flag via percent rollout. This is intentional: a flag with Percent > 0 but no identifiable user simply won't roll out to that context. Set a ChannelOverride or Default=true if you need anonymous contexts to receive the flag.
- Default
func (*Manager) LoadFromTOML ¶
LoadFromTOML reads a features.toml and registers every flag it contains. Missing file is OK. Malformed file returns the parse error so the caller can surface it to the user.