qbrixqbrix

Feature Gates

A feature gate sits in front of an experiment and decides who sees the bandit and what they see when they don't. Gates give you the safety rails you'd expect from a production rollout system — percentage rollouts, targeting rules, schedules, and a default arm for everyone outside the experiment.

Every experiment can have at most one gate. Without a gate, every selection request goes straight to the bandit policy.

What a Gate Controls

ControlDescription
Rollout %Fraction of traffic routed to the bandit. The remainder gets the default arm. Hashed by request ID for sticky assignment.
Default armThe arm served when a request is excluded by the gate (rollout, schedule, or unmatched rules).
Targeting rulesMatch on context metadata fields (country, device, plan_tier, etc.) and route matching traffic to a specific arm or to the bandit.
ScheduleStart/end dates and active hours of day. Outside the window, the gate serves the default arm.
Enabled flagMaster switch — flipping it off bypasses the bandit entirely.

Create an Experiment with a Gate

from qbrix import Qbrix
 
client = Qbrix()
 
experiment = client.experiment.create(
    name="checkout-banner",
    pool_id=pool.id,
    policy="auto",
    policy_params={"reward_type": "binary"},
    feature_gate={
        "enabled": True,
        "rollout_percentage": 25.0,
        "default_arm_id": pool.arms[0].id,
        "rules": [
            {
                "key": "country",
                "operator": "in",
                "value": ["US", "GB", "DE"],
                "arm_id": pool.arms[1].id,
            },
        ],
    },
)

How Selection Resolves

When a select request hits a gated experiment, qbrix walks the gate in this order:

  1. Enabled? If the gate is off, return the default arm.
  2. Schedule check. If outside the configured window, return the default arm.
  3. Rule match. Iterate rules in order. The first matching rule with an arm_id wins (returns that arm directly). A rule without arm_id opts the request into the bandit.
  4. Rollout hash. Hash the request ID and bucket into [0, rollout_percentage). In-bucket requests get the bandit's selection; out-of-bucket get the default arm.

The response includes an is_default: true flag so your client can distinguish bandit picks from gate fall-throughs.

Targeting Operators

OperatorExample
eq / neq{"key": "plan", "operator": "eq", "value": "pro"}
in / not_in{"key": "country", "operator": "in", "value": ["US", "CA"]}
contains / not_contains{"key": "user_agent", "operator": "contains", "value": "Mobile"}
gt / gte / lt / lte{"key": "tenure_days", "operator": "gte", "value": 30}

Rules read context fields from Context.metadata, so make sure your select() calls include the keys your rules reference.

Common Patterns

Canary launch. Start at rollout_percentage=5, watch insights, ramp to 25 → 50 → 100.

Holdout group. Set the default arm to control and rollout to 90% — 10% of traffic always sees the control regardless of what the bandit learns.

Geography-scoped experiments. Use a single country in [...] rule with arm_id unset, so only matching traffic enters the bandit; everyone else gets the default arm.

Scheduled flash test. Set start_date / end_date and active_hours_start / active_hours_end to constrain the experiment to a marketing window.

Info

Gates can be created and updated independently of the experiment via /api/v1/gates. See the API Reference for the full schema.

Next Steps