# Capability Spec: feature-flags **Package**: `@suaveplan/feature-flags` **Version**: 0.0.0 (genesis) **Status**: ADDED --- ## ADDED Requirements ### FF-01 — Provider contract `BaseFlagProvider` MUST implement `getFlag(key): FlagDefinition | undefined`, `listFlags(): FlagDefinitionMap`, `subscribe(listener): () => void`, and `close(): void`. Concrete providers (`MemoryProvider`, `JsonProvider`) MUST satisfy the same contract test suite. ### FF-02 — Evaluator contract `Evaluator.evaluate(key, context)` MUST resolve the flag definition, run its strategy chain in declared order, short-circuit on the first non-`none` `StrategyResult`, and return a `FlagEvaluationResult` carrying `{ value, reason, flag, context, duration_ms }`. Unknown flag keys MUST throw or return a fallback per `EvaluatorOptions.fallbackMode`. ### FF-03 — Deterministic bucketing `PercentageStrategy` MUST use `hashToPercentage(combineKeys(flagKey, userKey))` and bucket `[0, rolloutPercentage)`. For fixed inputs it MUST return the same result across processes and platforms; the implementation MUST NOT depend on `Math.random`. ### FF-04 — Composite strategy semantics `CompositeStrategy` MUST evaluate children left-to-right. `AND` MUST short-circuit on the first `none`/`no-match`. `OR` MUST short-circuit on the first `match`. Errors in a child strategy MUST surface as `FEATURE_FLAGS.STRATEGY_ERROR` with the child's index in context. ### FF-05 — Attribute targeting `AttributeStrategy` MUST support `AttributeOperator` values `eq`, `neq`, `in`, `nin`, `gt`, `gte`, `lt`, `lte`, `contains`, `startsWith`, `endsWith`, `regex`. `getNestedValue(ctx, path)` MUST walk dot-notation paths safely, returning `undefined` for missing segments rather than throwing. ### FF-06 — Change notification Any change pushed through a provider (`updateFlag`, remote poll) MUST emit a `FlagChangeEvent` on the shared `EventBus`. `FlagManager` MUST expose `subscribe(listener)` that forwards these events to consumers. ### FF-07 — Observability Every `Evaluator.evaluate` call MUST record a histogram `ff.evaluate.duration_ms` and increment `ff.evaluate.total` with labels `flag` and `result` (`match | no-match | fallback | error`). ### FF-08 — Definition validation All flag definitions registered via `FlagRegistry` MUST pass `FlagDefinitionSchema.parse`. Invalid shapes MUST surface as `FEATURE_FLAGS.INVALID_DEFINITION`.