>_bandit
changelog

Traffic share

What the Traffic share column means in the bandit arms table: a plan for future visits, or a record of past traffic?


TL;DR

Traffic share is an expected plan, not “what percent of visits this arm already got”.

The bandit estimates: how likely is the next /go visitor to land on this article or outbound? A number from 0 to 1 (shown as %). Active arms roughly sum to 100% (after share constraints: exact / min / max).

For historical volume, use the Journeys column — not Traffic share.


Share constraints (min / max / exact)

On an article or outbound you can set:

FieldMeaningBadge
Exact (strict_share)Exactly N% of traffic=N%
Min (min_share)At least N% (if no exact)≥N%
Max (max_share)At most N% (if no exact)≤N%

If exact is set, min and max for that arm are ignored. The entity fields are the source of truth; locking share from the dashboard writes strict_share.

On save, the sum of exact shares plus min floors (without exact) across active arms cannot exceed 100% — otherwise save is blocked.


Where it appears in the UI

PlaceWhat you see
“Articles & outbounds in rotation” tableCurrent computed share (bandit_arm_state.traffic_share)
Donut / distributionSame current shares for active arms
Dynamics chart → traffic metricHistory of those computed shares over time

In all three cases this is the allocation plan (or its history), not measured past traffic.


Expected vs actual share

Expected (“Traffic share”)Actual
QuestionWhere will the next visits go?Where did visits already go?
SourceMonte-Carlo over Thompson / policy + lock/maxCount of journeys per arm
In UITraffic share column, Dynamics (traffic)Journeys, funnel, period metrics
UpdatesOn share recompute (decision / settings / ComputeShares)As tracking events arrive

Example: an arm at 40% with few journeys means the bandit intends to send ~40% of new visits there. Over a short period, the realized share can differ a lot due to randomness and small sample size.


How it is calculated

1. Inputs

For each active arm, metrics come from analytics over analysis_window (often 7 days, product setting):

  • alpha / beta (from the reward mode: depth, revenue, conversion…);
  • journeys / mean_reward as needed;
  • manual rules: strict_share / locked_share, min_share, max_share, pin.

Cold start (few total journeys) → closer to uniform allocation.

If Min visits before allocation (min_allocation_journeys > 0) is set, each arm is first warmed up on lifetime journeys: until it hits the threshold it gets uniform fill, ignoring the score. A single warmed-up arm does not start the algorithm — traffic goes to the others. Once two or more are warm, Thompson (or the selected algorithm) runs among them while remaining arms still get fill (|warmup|/|free|). 0 turns the setting off.

2. Monte-Carlo (share estimate)

The policy (usually Thompson Sampling) repeatedly simulates which arm would win. An arm’s win rate ≈ its expected selection probability.

Then caps apply:

  • strict / locked — exactly that percent;
  • min_share — floor; deficit taken from other free arms;
  • max_share — ceiling; surplus redistributed to others.

Results (0…1) are stored in bandit_arm_state.traffic_share and snapshotted to analytics_arm_snapshots for the chart.

3. On a real /go hit

Each visit is chosen fresh (Beta sample / categorical over shares), not by a fixed round-robin of the percentage table.

On average the stream converges to the displayed shares; a single click is random. With few visits, plan and reality diverge.


How to read the table

  • High share + high effectiveness — the bandit is confident and sending a lot of traffic.
  • High share + “Insufficient data” — the plan is still noisy; don’t overreact.
  • Low share despite strong metrics — check max_share, competitors’ locks, pins, archived peers.
  • Locked share — the column should stay near that %; the free pool is split by the algorithm.

Outbounds use the same column as articles.


Dynamics chart

The traffic metric is not “% of visits in that hour”. It is the history of traffic_share snapshots (about every few minutes while the worker runs).

You see how the bandit’s plan changed over time (after recomputes, archives, new arms).


FAQ

Why don’t shares sum to exactly 100%?
UI rounding, archived rows in the list, or a stale snapshot after arm set changes. Focus on active arms.

Why is share high but journeys low?
Future plan ≠ accumulated history. The arm was activated recently, or /go volume is low.

Does the table date range change traffic share?
Journeys / purchases / CR can follow the selected period. Traffic share comes from current bandit state (last recompute), not “journey share over the period”.

How do I see the actual share?
Compare journeys: arm_journeys / sum(journeys). That is realized visit share — a different metric, not shown in the Traffic share column.


  • Reward modes (depth / revenue / conversion) — they drive alpha/beta, hence shares.
  • Outbounds — same shares, different arm kind.