Scoring
Score candidates on a blend of signals — priority, multi-objective, SLA deadline, yield, portfolio balance, and predicted value.
Scoring strategies compute a number for every candidate and route to the top score. Unlike balance strategies, they weigh multiple signals — load, capacity, deadline, geography, fairness, margin, conversion — and most of them are explainable: they return a per-dimension breakdown so you can see exactly why a candidate won.
Five scoring strategies are built in; predicted_value is provided by the
optional predicted module.
| Strategy | Modes | Capabilities | Notes |
|---|---|---|---|
| Priority score | scoring | weighted, explain | Blends weight, load, availability. |
| Multi-objective score | scoring, weighted | weighted, explain | The flagship tunable scorer. |
| SLA deadline | scoring | explain | Deadline- and catchall-aware. |
| Yield optimized | scoring, weighted | weighted, explain | Maximizes expected value. |
| Portfolio balance | weighted, scoring | weighted, explain | Caps recent share. |
| Predicted value | scoring | explain | Optional predicted module. |
Fallbacks are first-class
Every scoring strategy takes a fallback_strategy (or base_strategy) param
naming another registered strategy — usually smooth_weighted_round_robin. It
is used to break ties and to route when the primary scorer has no confident
answer. The fallback name is resolved through the registry.
Priority score
Modes: scoring · Capabilities: weighted, explain
Scores each candidate by a blend of weight, current load, and availability, then routes to the top score. Ties break via smooth weighted round-robin, and it returns explainable per-candidate scores.
Why use it. A step up from plain balance when you want load and availability to nudge the weighted split but you don't need the full multi-objective knob set. It's the "weighted, but load-aware and explainable" option.
How to configure it. No exposed sliders in the product surface — it derives
its blend internally from Candidate.Weight, CurrentLoad, and availability
facts. Enable explain on the route to capture the per-candidate breakdown.
Where it fits. The Select stage. Reach for
multi-objective score when you need to tune the weights.
Multi-objective score
Modes: scoring, weighted · Capabilities: weighted, explain
The flagship business-objective strategy. It blends capacity, deadline pressure, geography (distance), load, fairness, margin, and confidence into one tunable composite score, and returns a per-dimension breakdown for full explainability. If you only adopt one scorer, this is it.
Why use it. When "the best recipient" depends on several competing goals at once — you want the fast, nearby, high-margin, not-overloaded recipient, and you want to control the relative pull of each factor. Every dimension has a weight slider, so you tune the objective without writing code.
How to configure it.
Prop
Type
{
"strategy": "multi_objective_score",
"options": {
"capacity_weight": 2,
"deadline_weight": 3,
"distance_penalty_weight": 1,
"min_confidence": 0.2
}
}Where it fits. The Select stage. It consumes the typed
feature snapshot
(capacity ratio, margin, confidence, and more), which makes its decisions
replayable.
SLA deadline
Modes: scoring · Capabilities: explain
Deadline-aware routing. Scores recipients by deadline pressure, SLA quality,
response time, load, and capacity, preferring those likely to beat the
routable's ExpiresAt. A CatchallAt threshold sets fall-through behavior when
no candidate can comfortably meet the SLA.
Why use it. When time-to-serve is the objective — support tickets that must be answered within an SLA, leads that must be worked before they go cold, jobs with a hard deadline. It explicitly prefers recipients whose predicted response beats the clock.
How to configure it.
Prop
Type
The catchall_mode enum is the key control:
best_effort— still route to the best available candidate even if none beats the SLA.fallback— hand off tofallback_strategy.fail_closed— return no assignment rather than route to a recipient that will miss the SLA.
Where it fits. The Select stage, reading SLA-compliance and response-time
features from the snapshot.
Yield optimized
Modes: scoring, weighted · Capabilities: weighted, explain
The revenue strategy for lead and order routing. It maximizes expected yield — conversion rate × outcome value × quality × margin — while penalizing return rate and SLA risk, and it gates on a minimum-outcomes confidence floor so it doesn't over-trust recipients with thin history.
Why use it. When routing decisions have a dollar value and you want to send each opportunity to whoever will extract the most from it. It is the strategy for marketplaces, lead distribution, and order assignment where conversion and margin matter more than even load.
How to configure it.
Prop
Type
Cold-start protection
min_outcomes matters: a brand-new recipient with one lucky conversion looks
infinitely good. Set a floor so yield scoring only trusts recipients with enough
history, and let the fallback distribute to the rest.
Where it fits. The Select stage, driven by conversion, outcome-value,
quality, return-rate, and margin features from the snapshot.
Portfolio balance
Modes: weighted, scoring · Capabilities: weighted, explain
Keeps each recipient's (or metadata group's) recent assignment share under a configured cap, rebalancing toward under-served recipients. Concentration control for routing.
Why use it. When no single recipient — or no single group of recipients (one region, one vendor, one team) — should dominate recent volume, regardless of how attractive they score. It wraps a base strategy and simply vetoes candidates that are already over their share.
How to configure it.
Prop
Type
Where it fits. The Select stage. Its batch-scale counterpart is the
portfolio quota allocator,
which enforces caps across a whole batch instead of per-decision.
Predicted value
Modes: scoring · Capabilities: explain · Module: predicted
Scores candidates by predicted outcome value learned from outcome and quality history, routing to the highest predicted payoff.
Why use it. When you want a learned estimate of what each recipient will deliver, rather than a hand-tuned blend. It's the supervised sibling of yield optimized: instead of you weighting the factors, it predicts the value directly from history.
How to configure it. It is an optional module and must be registered with
the outcome and quality stores it learns from (RegisterPredicted in
modules/strategies/predicted/register.go). Without those repositories it is not
available. It has no product-surface sliders — its behavior comes from the
learned model.
Optional module
predicted_value (with Thompson sampling
and LinUCB) ships in the predicted module,
not the built-in pack. It requires the outcome and quality repositories and, for
the bandits, the strategy state store for durable posteriors.
Where it fits. The Select stage. See Learning
for the bandit strategies in the same module.
Behavior change: per-candidate outcome features
Each candidate is now scored on its own outcome history. Previously the
per-recipient outcome stats query ignored the recipient filter and returned the
pool's highest-total-value recipient, so every candidate received identical
conversion_rate, avg_outcome_value, and total_outcomes features — the
predicted score could not tell recipients apart by track record. Those features
now differ per candidate, so predicted-value rankings will shift toward
recipients with genuinely stronger histories. The same corrected features feed
the learning bandits, which read them as context.
Related
Balance
The seven workhorse distribution strategies — smooth weighted round-robin, random weighted, power of two choices, least loaded, consistent hash, failover, and fair catch-up.
Learning
Multi-armed and contextual bandits — Thompson sampling and LinUCB — that learn which recipient wins from outcomes.