juspay / juspay/decision-engine
Sticky routing: decide-time override with health veto
- Dominant language
- Rust
- Stars
- 128
- Forks
- 36
- Avg merge
- 1d 15h
- Merged PRs (30d)
- 34
Description
Part of #393 (sticky routing). **Status: implemented** in #412 (commit `4d396d2`), pending review/merge.
The decide-time override runs **last** in `run_decider_flow` — after SR scoring, outage/elimination penalties, and the cost/volume post-steps — and pins the customer's highest-success-count connector for the exact `PM:PMT` combo (one `HGETALL`). It applies only when ALL of:
- merchant kill switch `sticky_routing_enabled` is on, and `paymentInfo.customerId` is present (already in the public decide-gateway contract);
- the current approach is in the **SR-selection family** — priority logic, merchant preference, downtime relabels, and hedging exploration are never overridden;
- the request's optional `stickyRouting` override isn't `false` (absent = eligible, mirroring `enableMultiObjective`);
- **health veto**: the pinned connector is in the caller's `eligibleGatewayList` (the V2 flow's entire eligibility set) and its post-elimination score is ≥ `STICKY_ROUTING_MIN_SCORE_RATIO` (default 0.5) × top score — a pin can never resurrect a connector the outage/elimination passes just buried.
Label semantics (load-bearing for scoring):
- Every applied pin reports `routing_approach: STICKY_ROUTING` (agreeing or diverging); a divergent pin additionally clears superseded multi-objective/volume-steer claims so cost analytics can't credit a pick that never reached the customer. Agree-vs-diverge stays visible in the sticky decision metrics.
- `STICKY` is admitted by the SRv3 producer-isolation and explore/exploit gates (same precedent as `SR_SELECTION_MULTI_OBJECTIVE`), so pinned outcomes keep feeding the SR windows and the health veto stays live — without this, a pinned connector's score would freeze and sticky would keep pinning a degrading connector forever.
Sticky is independent of the euclid rule store: no static-outcome gating — precedence is PL/euclid explicit orders first (they bound the candidate set), then sticky, then SR, then the default ordering (the gate admits the Default approach so a pin still wins when SR is off). Everything fails open to the plain SR pick.
Contributor guide
Assessment
This issue has not been assessed yet.