fix(routing): dedup decision engine connectors by merchant_connector_id - #13758
Open
prajjwalkumar17 wants to merge 2 commits into
Open
fix(routing): dedup decision engine connectors by merchant_connector_id#13758prajjwalkumar17 wants to merge 2 commits into
prajjwalkumar17 wants to merge 2 commits into
Conversation
`transform_de_output_for_router` keyed its dedup set on the connector name alone, so a merchant holding several MCAs for the same connector kept only the first one. A rule that spans two of them — e.g. a volume split across two paypal MCAs — collapsed to a single connector, dropping the fallback. Key the set on the full (connector, merchant_connector_id) pair instead. The second loop now builds the `RoutableConnectorChoice` before keying off it, which also drops a duplicate `RoutableConnectors::from_str` — the `TryFrom<ConnectorInfo>` impl already performs that parse with the same error logging. Co-Authored-By: Claude <noreply@anthropic.com>
Three cases around `transform_de_output_for_router`: - two MCAs of the same connector both survive, winner first (fails before the dedup-key fix, with left: 1 / right: 2 — the exact shape seen in the sandbox shadow diff) - an exact duplicate still collapses to one entry - evaluated-first ordering for distinct connectors is unchanged The last two pass both before and after the fix, pinning the behaviour the change is not meant to alter. Co-Authored-By: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Type of Change
Description
transform_de_output_for_routerbuilds the router-facing connector list from a decision engine/routing/evaluateresponse:evaluated_outputfirst, then the remaining connectors fromoutputas fallbacks, deduplicated.The dedup set was keyed on the connector name alone:
RoutableConnectorChoicecarries bothconnectorandmerchant_connector_id, but onlyconnectorwent into the set. So for a merchant holding several MCAs of the same connector, every MCA after the first is silently dropped.This shows up on any rule that spans two MCAs of one connector — e.g. a volume split across two paypal MCAs. DE returns the sampled winner in
evaluated_outputand both arms inoutput; the second paypal MCA is then discarded, so the router loses its fallback and the list length disagrees with the legacy euclid result.Found while investigating a persistent shadow-diff (
is_equal_length=false) on a sandbox profile with exactly that shape.Change
Key the set on the full
(connector, merchant_connector_id)pair.The second loop now builds the
RoutableConnectorChoicebefore keying off it, which also removes a duplicatedRoutableConnectors::from_str— theTryFrom<ConnectorInfo>impl already performs that parse with equivalent error logging.Note: entries with
merchant_connector_id: Noneno longer collapse into a same-named entry withSome(id). Both lists are serialized from the sameConnectorInfoobjects in the same rule, so this is not expected to trigger in practice.Motivation and Context
Static routing via the decision engine must preserve MCA-level granularity; collapsing by connector name loses both the routing target and its fallbacks for multi-MCA merchants.
How did you test it?
Unit tests added in
crates/router/src/core/payments/routing/utils.rs(the file had no test module before):Verified the coverage is meaningful by reverting the fix and re-running with the tests in place — the regression test fails exactly as the bug predicts, while the two guard tests still pass:
left: 1 / right: 2is the same shape as the sandbox shadow diff that led here (DE one connector, HS two).Also run:
cargo check -p router,cargo clippy -p router,cargo +nightly fmt -p router --check— all clean.Checklist
cargo +nightly fmt --allcargo clippy🤖 Generated with Claude Code
Closes #13759