What this solves
Different product categories often want different ranking priorities. Cards offers are usually conversion-driven (push the highest-converting card to the top). Loans offers in regulated markets need fairness-led ranking (every qualified borrower sees an offer, regardless of model preferences). Without per-category overrides, you’d need a separate flow per category and split traffic at the router — operationally painful and breaks Hungarian uniqueness across the slot set.Why this works
The Score node’sstrategyOverrides[] array lets you map a candidate’s category (or productType, or channelId) to a specific RankingProfile. The PRIE engine reads the profile’s weights and maps them to the PRIE exponents: conversion → Wp (propensity), recency → Wr (relevance), margin → Wi (impact), fairness → We (emphasis), with optional uplift and clv exponent terms (default 0). It then recomputes the geometric-mean score per candidate. Same flow execution, three different weight regimes if you want three. Any other keys in weights (e.g. fatigue) are stored but ignored by the scoring math.
The pattern
Three ingredients:- A flow whose Score node has
method: "formula"and a defaultstrategyProfileId. - Two or more
RankingProfilerows with the weight regimes you want. strategyOverrides[]on the Score node mappingscope: "category"(or"productType"or"channel") +value(the category name, exactly as it appears on the Offer) → the profile id.
Step 1 — Create the ranking profiles
Step 2 — Configure the flow’s Score node
PUT the decision flow’sdraftConfig, targeting the Score node:
POST /api/v1/decision-flows/publish to ship it.
Step 3 — Verify
Fire the same recommend against the same customer twice — once with the override array empty (control), once with the override above. You should see Mortgage’s score shift by a known delta (its Loans candidate now scored under the fairness-led weights) while Cashback’s stays constant (it never leaves the Cards default).What the trace will show
The override is not stamped by name on the trace — the engine resolves the profile per candidate and applies its weights silently. What you read off the trace is the score: run the recommend once with the override array empty, once with it populated, and the Loans candidate’sscore shifts under the new weight regime while the Cards candidate (still on the default profile) stays put.
score off scoringResults[] (top-10 scored candidates, with modelType and any SHAP explanations) or selectedOffers[] on the decision trace. The applied ranking profile itself is resolved at scoring time and is not persisted as a trace field.
Gotchas
- Use the category NAME, not the UUID. The engine matches on
offer.categoryRef.name. Passing the category id silently no-ops; the engine falls back to the default profile. - Same-customer A/B is the cleanest comparison. The maturity ramp’s per-customer deterministic-random roll means two new customers comparing the same offer can see different drop patterns. Use one customer across both stages.
- Override priority is array order. First match wins; later entries don’t merge. If you want a fallback, put it last with the broadest scope.