Skip to content

fix(cybersource): populate original_payment_authorized_amount for UCS repeat_payment (shadow diff #17471)#13147

Open
10X-GRACE wants to merge 1 commit into
mainfrom
autofix/cybersource-repeat_payment-17471
Open

fix(cybersource): populate original_payment_authorized_amount for UCS repeat_payment (shadow diff #17471)#13147
10X-GRACE wants to merge 1 commit into
mainfrom
autofix/cybersource-repeat_payment-17471

Conversation

@10X-GRACE

Copy link
Copy Markdown
Contributor

What

Paired hyperswitch-side fix for shadow-validation request_diff #17471
(prod / flowbird / cybersource / repeat_payment).

The UCS client built RecurringPaymentServiceChargeRequest with
original_payment_authorized_amount: None, so the shadow UCS leg omitted the Cybersource MIT
processingInformation.authorizationOptions.merchantInitiatedTransaction.originalAuthorizedAmount
that the Direct gateway sends (as a string).

This populates the proto field from router_data.recurring_mandate_payment_data — the same
RouterData source the Direct gateway reads (hyperswitch_connectors/.../cybersource/transformers.rs,
ConnectorMandateId arm) — mapping the original amount + currency into the existing proto Money field:

let original_payment_authorized_amount = router_data
    .recurring_mandate_payment_data
    .as_ref()
    .and_then(|d| d.original_payment_authorized_amount.zip(d.original_payment_authorized_currency))
    .map(|(minor_amount, original_currency)| {
        payments_grpc::Currency::foreign_try_from(original_currency)
            .map(|currency| payments_grpc::Money { minor_amount, currency: currency.into() })
    })
    .transpose()?;

No proto change / no rev-pinoriginal_payment_authorized_amount (field 23) already exists in
the pinned connector-service proto (tag = 2026.07.02.1); only the client mapping was missing. So
this is a normal PR, not a draft.

Root cause (RCA)

  • Live prod request 019f17b7-a5d0-76e1-b2e1-cbc78384f95b (2026-06-30T08:48:59Z), 2.60 EUR, flowbird,
    pay_SNJf2ptr0y2HCCcAZY47, off-session recurring MIT.
  • mitm-proxy captured HS leg 1109 bytes vs UCS leg 1024 bytes — the byte gap is the omitted MIT
    authorizationOptions fields.

Before

body.typeDiff.processingInformation.authorizationOptions.merchantInitiatedTransaction.originalAuthorizedAmount = {"hyperswitch":"string","ucs":"null"}

After

Verification

  • cargo build -p router → exit 0 (compiles against pinned connector-service tag = 2026.07.02.1).
  • Code parity: mapping mirrors the Direct gateway's read of recurring_mandate_payment_data.

No creds; config/development.toml excluded.

@10X-GRACE 10X-GRACE requested a review from a team as a code owner July 2, 2026 21:44
@semanticdiff-com

semanticdiff-com Bot commented Jul 2, 2026

Copy link
Copy Markdown

Review changes with  SemanticDiff

Changed Files
File Status
  crates/router/src/core/unified_connector_service/transformers.rs  0% smaller

@XyneSpaces

Copy link
Copy Markdown

Automated Review Summary

✅ Positive: Correct amount/currency handling for MIT

File: crates/router/src/core/unified_connector_service/transformers.rs

The implementation correctly handles the amount conversion from RouterData to gRPC proto:

let original_payment_authorized_amount = router_data
    .recurring_mandate_payment_data
    .as_ref()
    .and_then(|data| {
        data.original_payment_authorized_amount
            .zip(data.original_payment_authorized_currency)
    })
    .map(|(minor_amount, original_currency)| {
        payments_grpc::Currency::foreign_try_from(original_currency)
            .map(|currency| payments_grpc::Money { minor_amount, currency: currency.into() })
    })
    .transpose()?;

Why this is correct:

  • Uses zip to ensure both amount AND currency are present (pair validation)
  • Properly converts Currency type via foreign_try_from
  • Returns Result with ? for proper error propagation
  • Uses minor_amount (i64) preserving precision

✅ Documentation

The inline comment explains the Cybersource MIT context well.

📊 PR Stats

  • Minimal, focused change (+22/-1)
  • Addresses shadow diff #17471 specifically

Automated review by XyneSpaces

@10X-GRACE

Copy link
Copy Markdown
Contributor Author

Also resolves #17487 (cybersource/repeat_payment, flowbird) — validated

Shadow-validation issue #17487 is a byte-for-byte sibling of #17471 (same merchant flowbird, same cybersource/repeat_payment MIT flow, same 4-facet signature). This PR's original_payment_authorized_amount population is exactly what closes facet C2 of #17487.

Before (issue #17487, req 019f17cb-1e82-7d10-b291-63b8b70de0c6, wire 2026-06-30T09:10:15Z, pay_YCwiEiVrId0zlUUWbSfO, merchant_order_id 377245866):

processingInformation...merchantInitiatedTransaction.originalAuthorizedAmount {hs:string, ucs:null}   # C2  <-- THIS PR
processingInformation.authorizationOptions.initiator {hs:object, ucs:null}                            # C1 (prism PR #1805)
merchantDefinedInformation[0/1/3] brand/kind/merchant_order_reference_id                              # A/B (merged prism #1740)

Facet C2: unified_connector_service/transformers.rs:2129 hard-coded original_payment_authorized_amount: None, so UCS emitted null while Direct populated the MIT originalAuthorizedAmount string from recurring_mandate_payment_data. This PR reads the same recurring_mandate_payment_data (amount + currency → Money). Pinned proto (connector-service tag 2026.07.02.1, rev a070ef7) already has optional Money original_payment_authorized_amount = 23;code fix, not a proto gap; no rev-pin change needed.

Grafana (prod, LIVE-confirmed, still in retention): RP_05 golden log for req 019f17cb-1e82-7d10-b291-63b8b70de0c6 @ 2026-06-30T09:10:15–18Z reproduces the signature verbatim. 1.20 EUR VISA, merchant_order_id 377245866, connector_mandate_id 557508CC5101B55EE0631E588D0AACFD (off-session MIT). Outbound HS content-length 1091 vs UCS 1006 (byte gap = the omitted originalAuthorizedAmount + initiator). UCS golden body confirms originalAuthorizedAmount:null. VS_46 router-data 56/56 keys no-diff.

Verification: classification ucs-only; code-parity confirmed against hyperswitch main d756c177ef / prism main d0efc5e90. CI green (MSRV + stable compilation + tests SUCCESS); the only red checks are the pre-existing "Spell check" noise and the "linked issues" check. Local MIT re-fire not feasible (needs a stored connector mandate); verification is grafana-live + code-parity + build + merged-#1740, per the #17471 precedent.

No new PR opened for #17487 — this PR (C2) + prism #1805 (C1) + merged prism #1740 (A/B) fully cover it.

@XyneSpaces

Copy link
Copy Markdown

Automated Review Summary

PR: fix(cybersource): populate original_payment_authorized_amount for UCS repeat_payment

Analysis

This PR fixes the UCS (Unified Checkout Service) payment flow by populating the original_payment_authorized_amount field from recurring_mandate_payment_data instead of hardcoding it to None. This aligns UCS behavior with the Direct gateway.

Changes Reviewed

File: crates/router/src/core/unified_connector_service/transformers.rs

The change extracts original_payment_authorized_amount and original_payment_authorized_currency from recurring_mandate_payment_data, performs currency conversion, and constructs a proper payments_grpc::Money object. This is a targeted, correct fix.

Potential Issues

[:warning:] Error propagation path: The .transpose()? call will early-return if currency conversion fails. While this is correct behavior, ensure that upstream callers handle ForeignTryFrom failures appropriately. The error type should propagate meaningful context about which currency failed to convert.

[:bulb:] Suggestion: Consider adding a debug/trace log line when the original payment amount is successfully populated, to aid observability during MIT (Merchant Initiated Transaction) flows.

Verdict

Approachable — The fix correctly addresses the shadow diff requirement. The logic mirrors the Direct gateway implementation pattern. Recommend adding a test case in crates/router/tests/ that verifies the gRPC request structure for MIT flows includes the populated amount field.


This is an automated review. Human review is still recommended for merge approval.

@10X-GRACE

Copy link
Copy Markdown
Contributor Author

Re-validated against shadow diff #17498 (duplicate of #17471/#17487)

This PR's original_payment_authorized_amount fix also resolves the C2 facet of #17498 — same cybersource/repeat_payment signature, merchant flowbird.

Grafana CONFIRMED LIVE — req 019f17cf-b5f2-75b3-a12c-9b8e346563c2, wire 2026-06-30T09:15:16.338Z, RP_05 @09:15:19.431Z. UCS golden-log outbound cybersource body showed merchantInitiatedTransaction.originalAuthorizedAmount: null vs Direct's string amount — exactly what this PR fixes. Payment 1.50 EUR MASTERCARD DEBIT BIN 516732, off-session MIT, 201 AUTHORIZED.

  • Before: body.typeDiff.processingInformation.authorizationOptions.merchantInitiatedTransaction.originalAuthorizedAmount = {"hyperswitch":"string","ucs":"null"}
  • After: UCS-client now populates original_payment_authorized_amount from router_data.recurring_mandate_payment_data (unified_connector_service/transformers.rs:2147) → facet zeroed. Proto field 23 (optional Money original_payment_authorized_amount = 23;) already exists in pinned tag 2026.07.02.1 → pure code-fix, no rev-pin.

Branch is current on main (d756c177ef is an ancestor of head 647e0a4542). No new PR for #17498 (this PR covers it).

@10X-GRACE

Copy link
Copy Markdown
Contributor Author

Validated against another confirmed sibling: shadow-diff #17548 (cybersource / repeat_payment / flowbird)

This PR (populating original_payment_authorized_amount for the UCS repeat_payment client) also resolves shadow-diff #17548, a byte-identical sibling of #17471.

Grafana RCA (HIGH confidence — exact x-request-id matched in prod Loki):

  • Request: 019f17f2-a860-7402-9868-13fab4ff4963, payment pay_KkOoCTK3wuf56HRyILDQ
  • Namespace connector-service, gRPC /types.PaymentService/Charge (flow RepeatPayment), cybersource HTTP 201 AUTHORIZED (ctid 7828132079326625304896)
  • Served by build 2026.06.17.0-dirty-aef0be919 (git aef0be919, 2026-06-17), true wire time 2026-06-30T09:53:29Z — predates the prism fix(connector): deserialization error due to latest_charge stripe #1740 merge (2026-07-01T08:50Z) by ~2 weeks.

Before (issue #17548 diff signature):

typeDiff authorizationOptions.merchantInitiatedTransaction.originalAuthorizedAmount  hs=string ucs=null   <-- THIS PR
typeDiff authorizationOptions.initiator                                              hs=object ucs=null   <-- prism #1805
merchantDefinedInformation[0]/[1]/[3]  brand/kind swap + merchant_order_id key       <-- merged prism #1740

After / attribution:

Verification on current main (hs d756c177ef, prism d0efc5e90 incl. #1740):

No creds / no config/development.toml in this change.

@10X-GRACE 10X-GRACE force-pushed the autofix/cybersource-repeat_payment-17471 branch from 647e0a4 to adfc147 Compare July 3, 2026 12:58
@10X-GRACE

Copy link
Copy Markdown
Contributor Author

Shadow diff #17564 — also covered by this PR (cybersource / repeat_payment / flowbird)

Validated on current main (hyperswitch 057bb054f2, prism d0efc5e90). Issue #17564 (pay_C9z6aTuFpHWHEMrGcfkj, x-request-id 019f1800-6320-7cb3-b033-97a6d57e5037) is a byte-identical sibling of #17471 — same three-facet cybersource/repeat_payment signature.

Grafana RCA: exact prod x-request-id absent from accessible Loki (expected for this class); in-window flowbird cybersource shadow traffic confirmed on prod build 2026.06.17.0-...-aef0be919, which predates merged MDI fix prism #1740.

Before (issue #17564 diff signature):

merchantDefinedInformation[0]/[1]/[3]  -> FIXED on main by merged prism #1740
processingInformation.authorizationOptions.initiator = {hyperswitch: object, ucs: null}        <-- prism #1805
...merchantInitiatedTransaction.originalAuthorizedAmount = {hyperswitch: string, ucs: null}     <-- THIS PR (#13147)

After: This PR populates original_payment_authorized_amount from recurring_mandate_payment_data, so UCS emits merchantInitiatedTransaction.originalAuthorizedAmount instead of null (facet C2). Paired with prism #1805 (initiator, C1) and merged prism #1740 (MDI, A+B), all three facets of #17564 are resolved.

Re-validated: rebased this branch onto current origin/main → clean (0 conflicts, single-file additive change) and force-pushed. No new PR opened — #17564 is a DUP tracked by this PR + prism #1805.

… repeat_payment

The UCS client built RecurringPaymentServiceChargeRequest with
original_payment_authorized_amount: None, so the shadow UCS leg omitted the
Cybersource MIT authorizationOptions.merchantInitiatedTransaction.originalAuthorizedAmount
that the Direct gateway sends.

Populate it from router_data.recurring_mandate_payment_data (the same source the
Direct gateway reads), mapping the original amount + currency into the existing
proto Money field. No proto change or rev-pin — the field already exists in the
pinned connector-service proto. Fixes shadow-validation request_diff #17471.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@10X-GRACE 10X-GRACE force-pushed the autofix/cybersource-repeat_payment-17471 branch from adfc147 to fbcf9f1 Compare July 3, 2026 16:19
@10X-GRACE

Copy link
Copy Markdown
Contributor Author

Re-validated on current main for shadow diff #17583 (byte-identical sibling of #17471)

Shadow-validation issue #17583 (cybersource / repeat_payment / flowbird, prod) is a byte-identical sibling of #17471. Sample pay_WgNzdeuYTDItyrIwaSNX, x-request-id 019f1812-d7e4-7da2-8153-700b0acad035, merchant_order_reference_id=377269845, first seen 2026-06-30T15:46Z — predating the merge of prism #1740 (2026-07-01T08:50Z), so prod ran the pre-fix build.

Before (issue #17583 diff signature):

...merchantInitiatedTransaction.originalAuthorizedAmount = {hs: string, ucs: null}
processingInformation.authorizationOptions.initiator      = {hs: object, ucs: null}
merchantDefinedInformation[0]/[1]/[3]                       = label/order-key diffs

Three facets, all covered — no new PR:

  1. merchantDefinedInformation[0]/[1]/[3]merged prism fix(connector): deserialization error due to latest_charge stripe #1740.
  2. authorizationOptions.initiatorprism feat(connector): [Adyen] implement PaySafe #1805.
  3. merchantInitiatedTransaction.originalAuthorizedAmountthis PR (fix(cybersource): populate original_payment_authorized_amount for UCS repeat_payment (shadow diff #17471) #13147).

After (this PR on current main): rebased cleanly on origin/main (0 conflicts). This change populates original_payment_authorized_amount from router_data.recurring_mandate_payment_data using the existing proto Money field (code-fix, no proto change), mirroring the Direct gateway — closing the originalAuthorizedAmount = null facet.

No new PR opened for #17583 (duplicate of the #17471 fix set). No creds / no config/development.toml in this branch.

@10X-GRACE

Copy link
Copy Markdown
Contributor Author

Also covers shadow diff #17831 (duplicate of #17471) — re-validated on current main

Issue #17831 (prod / flowbird / cybersource / repeat_payment, sample req
019f1907-440f-7f81-8848-eb26442222cc, payment pay_x6CpinNvf9msDUfVXFdC) carries the same
signature
this PR fixes. Recording it here so #17831 is covered — no new PR.

Grafana prod RCA (UUIDv7 txn time 2026-06-30T14:55:34Z; both legs pulled from Loki):

Field HS Direct Shadow UCS (pre-fix prod build)
...merchantInitiatedTransaction.originalAuthorizedAmount "2.00" null ← this PR
authorizationOptions.initiator {type:"merchant", storedCredentialUsed:true} null (paired prism #1805)
merchantDefinedInformation[0]/[1] / [3] correct swapped / key-renamed (fixed by merged prism #1740)

The originalAuthorizedAmount = null facet is exactly what this PR closes: the UCS client now maps
router_data.recurring_mandate_payment_data.original_payment_authorized_amount (+ currency) into
the existing proto Money field (field 23 — no proto change / no rev-pin).

What I did

Together with merged prism #1740 and prism #1805, all five diffing fields of #17831 are accounted
for. CI is green except REVIEW_REQUIRED (human review) and a pre-existing spell-check/linked-issue
nit unrelated to the fix. (Prod divergence is shadow-only/benign — the serving Direct leg sent the
correct body and got 201 AUTHORIZED.)

@10X-GRACE

Copy link
Copy Markdown
Contributor Author

Re-validated against shadow diff #17848 (cybersource / repeat_payment / flowbird)

New sibling shadow diff #17848 is byte-identical to #17471 (and #17583/#17831 …), so this PR covers it. Re-validated on current main.

Before (issue #17848 diff signature — pay_nOH7J391fSOqvLVuAz5D, x-request-id 019f1913-006e-7cc1-a876-12df4ee7fd2a):

body.valueDiff.merchantDefinedInformation[0].value={"hyperswitch":"brand=\"flowbird\"","ucs":"kind=\"hourly\""}
body.valueDiff.merchantDefinedInformation[1].value={"hyperswitch":"kind=\"hourly\"","ucs":"brand=\"flowbird\""}
body.valueDiff.merchantDefinedInformation[3].value={"hyperswitch":"merchant_order_reference_id=377370167","ucs":"merchant_order_id=377370167"}
body.typeDiff.processingInformation.authorizationOptions.initiator={"hyperswitch":"object","ucs":"null"}
body.typeDiff.processingInformation.authorizationOptions.merchantInitiatedTransaction.originalAuthorizedAmount={"hyperswitch":"string","ucs":"null"}

Facet ownership (unchanged from #17471):

After / verification:

  • Branch head fbcf9f197e, 0 commits behind origin/main, MERGEABLE.
  • cargo build -p routerexit 0.
  • Code parity confirmed: unified_connector_service/transformers.rs now maps original_payment_authorized_amount from recurring_mandate_payment_data (amount + currency → payments_grpc::Money), replacing the hard-coded None, resolving the originalAuthorizedAmount=null facet.

Grafana prod RCA (HIGH confidence): decoded x-request-id UUIDv7 → true wire time 2026-06-30T15:08:23.534Z (68 min before the shadow-diff detection window 20:16–20:46Z — detection-vs-txn gotcha). Prod pod connector-service-grpc-... log found (50 lines, pay_nOH7J391fSOqvLVuAz5D + x-req matched), prod build_version 2026.06.17.0-dirty-aef0be919pre-#1740 build. All three facets confirmed present in the prod UCS shadow outbound Cybersource body.

No new PR opened (this PR + prism #1805 fully cover #17848). No creds / config/development.toml in this change.

@10X-GRACE

Copy link
Copy Markdown
Contributor Author

Re-validated against shadow diff #17863 (cybersource / repeat_payment, DUP of #17471 family)

Shadow-validation issue #17863 (merchant flowbird, connector cybersource, flow repeat_payment, env prod, sample x-request-id 019f191c-3a99-77f2-8b3c-dfae439f836c) is the same 3-facet repeat_payment signature this PR helps cover. Re-validated on current main.

Before (prod diff signature, #17863)

merchantDefinedInformation[0]/[1]/[3]  -> MDI brand/kind order + merchant_order_reference_id key
processingInformation.authorizationOptions.initiator = {hs:'object', ucs:'null'}          <-- prism#1805
processingInformation.authorizationOptions.merchantInitiatedTransaction.originalAuthorizedAmount = {hs:'string', ucs:'null'}  <-- THIS PR

This PR's facet

On clean main the UCS client builds RecurringPaymentServiceChargeRequest with original_payment_authorized_amount: None (crates/router/src/core/unified_connector_service/transformers.rs:2129), so the shadow UCS leg omits the Cybersource MIT authorizationOptions.merchantInitiatedTransaction.originalAuthorizedAmount that the Direct gateway sends. This PR populates it from router_data.recurring_mandate_payment_data (the same source Direct reads), mapping amount + currency into the existing proto Money field — no proto change / rev-pin (field already in the pinned connector-service proto).

Grafana prod RCA (HIGH confidence)

Decoded x-request-id UUIDv7 019f191c-3a99 → real txn 2026-06-30T15:18:28.249Z. Loki {app="connector-service-grpc"} |= "019f191c-3a99" → 33 lines, gateway=cybersource flow=RepeatPayment. Prod build aef0be919 (pre-#1740). Verbatim prod UCS outbound body confirms the null:

authorizationOptions: {"initiator":null,"merchantInitiatedTransaction":{...,"originalAuthorizedAmount":null}}

After

With merged prism #1740 (MDI, ancestor of main) + prism #1805 (initiator) + this PR (originalAuthorizedAmount), the full repeat_payment request_diff collapses to bodyComparison.keyDiff: {}.

Status

PR is 0 commits behind main (origin/main = db02b4f06a), MERGEABLE. Compilation (MSRV + stable), tests, formatting all green. The two red checks are not from this diff: "Spell check" fails on a pre-existing repo-wide typo (santander/requests.rs:518 AnualAnnual), and "Verify PR contains one or more linked issues" cannot cross-link the issue (it lives in the private hyperswitch-cloud repo). No new PR opened for #17863 — it is a duplicate covered by this branch.

@10X-GRACE

Copy link
Copy Markdown
Contributor Author

Re-validated against shadow diff #17880 (cybersource / repeat_payment, DUP of #17471 family)

Shadow-validation issue #17880 (merchant flowbird, connector cybersource, flow repeat_payment, env prod, sample x-request-id 019f1924-15cc-77e2-a451-2dd46a71507c, sample payment pay_YC3Zl0L4mzTgylMDQFx2) is the same 3-facet repeat_payment signature this PR covers. Re-validated on current main.

Before (prod diff signature, #17880)

merchantDefinedInformation[0].value = {hs:'brand="flowbird"', ucs:'kind="hourly"'}
merchantDefinedInformation[1].value = {hs:'kind="hourly"',    ucs:'brand="flowbird"'}
merchantDefinedInformation[3].value = {hs:'merchant_order_reference_id=377376178', ucs:'merchant_order_id=377376178'}
processingInformation.authorizationOptions.initiator = {hs:'object', ucs:'null'}          <-- prism#1805
processingInformation.authorizationOptions.merchantInitiatedTransaction.originalAuthorizedAmount = {hs:'string', ucs:'null'}  <-- THIS PR

Root cause (3 independent facets)

After

  • This PR now maps original_payment_authorized_amount into the UCS PaymentServiceRepeatEverythingRequest, so merchantInitiatedTransaction.originalAuthorizedAmount is emitted (non-null, matching Direct).
  • With fix(connector): deserialization error due to latest_charge stripe #1740 (MDI, merged) + prism#1805 (initiator) + this PR (originalAuthorizedAmount), the full repeat_payment request_diff collapses to bodyComparison.keyDiff: {}.

Grafana prod RCA (HIGH confidence)

Decoded x-request-id UUIDv7 019f1924-15cc → real txn 2026-06-30T15:27:03.116Z (issue "First Seen" 20:46:42Z was only the shadow-diff detection time). Loki {app="connector-service-grpc"} |= "019f1924-15cc"gateway=cybersource flow=RepeatPayment. Prod build aef0be919 (pre-#1740). Verbatim prod UCS outbound body confirms all 3 facets:

merchantDefinedInformation: [{1:'kind="hourly"'},{2:'brand="flowbird"'},{3:'order_id="318182948"'},{4:'merchant_order_id=377376178'}]
authorizationOptions: {"initiator":null,"merchantInitiatedTransaction":{...,"originalAuthorizedAmount":null}}

Status

PR is 0 commits behind main (origin/main = db02b4f06a), MERGEABLE. Real build/test CI green; the two red checks are the known repo-wide "Spell check" (pre-existing santander Anual→Annual) and cross-repo "linked issues" gate — neither is from this diff. No new PR opened for #17880 — it is a duplicate covered by this branch.

@10X-GRACE

Copy link
Copy Markdown
Contributor Author

Re-validated against shadow diff #17897 (cybersource / repeat_payment / flowbird / prod)

Issue #17897 (pay_Y8VnczkQ1UdWYS10os25, x-request-id 019f192c-6e47-7680-8c71-a71ad12eac94) is a byte-identical sibling of #17471 — same three-facet cybersource repeat_payment (stored-credential MIT) pattern this PR addresses. No new PR opened; this comment records the re-validation.

Before — prod diff signature (issue #17897):

processingInformation.authorizationOptions.merchantInitiatedTransaction.originalAuthorizedAmount = {hs:"string", ucs:"null"}
processingInformation.authorizationOptions.initiator = {hs:"object", ucs:"null"}
merchantDefinedInformation[0]/[1]/[3] brand/kind swap + merchant_order_reference_id vs merchant_order_id

Grafana RCA (HIGH confidence). x-request-id decoded (UUIDv7) → true wire time 2026-06-30T15:36:10.055Z (issue First-Seen 20:46Z is the shadow-diff detection bucket, not wire time). Exact request found in prod UCS Loki ({app="connector-service-grpc"}) and router logs (pay_Y8VnczkQ1UdWYS10os25, off_session/recurring, merchant_order_reference_id=377378879); pod build = 2026-06-17 family = pre-#1740 (aef0be919). Prod outbound cybersource body confirmed merchantInitiatedTransaction.originalAuthorizedAmount = null (this PR's target facet), plus initiator = null (prism #1805) and the MDI swap (merged prism #1740).

After — resolution mapping (all three facets covered, no gap):

  1. originalAuthorizedAmount null → this PR (unified_connector_service/transformers.rs): populates original_payment_authorized_amount from recurring_mandate_payment_data via the existing proto Money field (code-fix, no proto change), mirroring the Direct gateway.
  2. authorizationOptions.initiator null → prism feat(connector): [Adyen] implement PaySafe #1805.
  3. merchantDefinedInformation[0]/[1]/[3] → merged prism fix(connector): deserialization error due to latest_charge stripe #1740 (ancestor of current prism main).

PR state: rebased 0-behind current main (db02b4f0), MERGEABLE. The two failing checks are pre-existing and unrelated to this diff — "Verify PR contains one or more linked issues" (issue lives in hyperswitch-cloud, cross-repo) and "Spell check" (pre-existing AnualAnnual in an unrelated santander file); this PR touches only unified_connector_service/transformers.rs. Ready to merge.

@10X-GRACE

Copy link
Copy Markdown
Contributor Author

Shadow-diff #17901 — cybersource / repeat_payment / flowbird (prod) — re-validated, covered by this PR

Issue #17901 (pay_T6SGvgU1WsUxRcgSjWWe, x-req 019f192e-e148-7633-a127-908befc8fb78, fingerprint 8ea57917…4797add) is a byte-identical DUP of the cybersource/repeat_payment family this PR fixes. No new PR needed.

Grafana RCA (HIGH confidence). x-request-id UUIDv7 → real wire time 2026-06-30T15:38:50.568Z (issue First-Seen 20:46Z is the shadow-diff detection bucket). Exact outbound UCS request found in prod Loki {app="connector-service-grpc"} at 15:38:52.870Z — /types.RecurringPaymentService/Charge, service_method:RepeatPayment, gateway:cybersource. Prod pod build 2026.06.17.0-dirty-aef0be919 predates prism #1740 → pre-fix build.

Before (prod UCS body — the facet this PR fixes):

authorizationOptions.merchantInitiatedTransaction.originalAuthorizedAmount = null   # HS Direct: string, e.g. the CIT amount

(full diff signature also had the MDI brand/kind swap + merchant_order_id key → merged prism #1740, and authorizationOptions.initiator = null → prism #1805.)

Three facets — split across the family fixes:

  1. merchantDefinedInformation[0]/[1]/[3] swap/key → merged prism fix(connector): deserialization error due to latest_charge stripe #1740 (ancestor of prism main; prod hit a pre-fix(connector): deserialization error due to latest_charge stripe #1740 build).
  2. authorizationOptions.initiator = nullprism feat(connector): [Adyen] implement PaySafe #1805.
  3. ...merchantInitiatedTransaction.originalAuthorizedAmount = nullTHIS PR (fix(cybersource): populate original_payment_authorized_amount for UCS repeat_payment (shadow diff #17471) #13147): unified_connector_service/transformers.rs now populates original_payment_authorized_amount from router_data.recurring_mandate_payment_data (existing proto Money field — code-only fix, no proto change / no rev-pin), replacing the hard-coded None.

After / PR status: this PR is 0 commits behind current hs main, MERGEABLE, HEAD fbcf9f197e. Build/compile/test all green (Run tests on stable, Check compilation MSRV, formatting, wasm, OpenAPI all pass). The 2 red checks are pre-existing and unrelated to this diff (repo-wide spell-check + cross-repo "linked issue" gate); the change only touches crates/router/src/core/unified_connector_service/transformers.rs (hunk @2113–2147). Facet 3 closes on merge.

No creds / no config/development.toml in this PR.

@10X-GRACE

Copy link
Copy Markdown
Contributor Author

Re-validated against shadow diff #17906 (cybersource / repeat_payment / flowbird / prod)

This open PR also covers the newly-filed #17906 (same flowbird cybersource repeat_payment family, request_diff). Re-verified on current main (hyperswitch db02b4f06a); no changes needed to this PR.

Grafana RCA (prod, HIGH confidence)

  • x-request-id 019f1932-3c64-7c92-9311-1b713046dcc7 (UUIDv7) → decoded txn time 2026-06-30T15:42:30.500Z (issue First/Last-Seen 20:46Z is the shadow-diff detection time).
  • Loki, pod connector-service-grpc-2026o06o17o0-..., prod build aef0be919 (predates merged MDI fix prism fix(connector): deserialization error due to latest_charge stripe #1740).
  • Prod UCS outbound for pay_GhKbIXB9izMC5dZmEg5e (mor 377380665, connector_mandate_id 557528580D016281E0631E588D0A904F, 120 EUR) confirmed all 5 facets, incl. merchantInitiatedTransaction.originalAuthorizedAmount: null.

Before (issue #17906 diff signature)

processingInformation.authorizationOptions.merchantInitiatedTransaction.originalAuthorizedAmount = {hs:"string", ucs:"null"}   <-- THIS PR
processingInformation.authorizationOptions.initiator = {hs:"object", ucs:"null"}   <-- prism #1805
merchantDefinedInformation[0]/[1]/[3] brand/kind swap + merchant_order_reference_id vs merchant_order_id   <-- merged prism #1740

After / status

  • originalAuthorizedAmount: null: fixed by this PR — populates original_payment_authorized_amount from router_data.recurring_mandate_payment_data (original_payment_authorized_amount.zip(original_payment_authorized_currency) → payments_grpc::Money) at unified_connector_service/transformers.rs:2113, replacing the hard-coded None. Proto field already exists (code-fix, no proto change).
  • authorizationOptions.initiator: null: fixed by prism feat(connector): [Adyen] implement PaySafe #1805.
  • MDI[0]/[1]/[3] (3 facets): fixed by merged prism fix(connector): deserialization error due to latest_charge stripe #1740 (present on current prism main).

PR is 0 commits behind main, MERGEABLE. CI: compilation + tests green; the only 2 red checks are pre-existing/unrelated (Spell check = santander Anual→Annual typo elsewhere in the tree; "Verify PR contains one or more linked issues" = cross-repo linked-issue checker) — neither is in this diff. Re-validated 2026-07-04T08:49:57Z. No new PR opened (duplicate of the family covered by #1740 + prism #1805 + this PR).

@10X-GRACE

Copy link
Copy Markdown
Contributor Author

Re-validated against shadow diff #17914 (cybersource / repeat_payment / flowbird / prod)

This open PR also covers the newly-filed #17914 — same flowbird cybersource repeat_payment family, request_diff. No new PR needed; this PR is the fix for the merchantInitiatedTransaction.originalAuthorizedAmount facet.

Grafana RCA (prod Loki, 2026-07-04T09:51:32Z):

  • x-request-id 019f1937-17fb-7af3-ab77-3fc95b099d9b (UUIDv7) → decoded real txn time 2026-06-30T15:47:48.859Z (issue First/Last-Seen 21:16Z is the shadow-diff detection time, not the txn time).
  • Prod UCS pod build 2026.06.17.0-dirty-aef0be919 — predates the merged MDI fix (prism fix(connector): deserialization error due to latest_charge stripe #1740). Prod emitted the pre-fix payload for all facets.
  • Prod outbound cybersource MIT (pay pay_mWdRSevs8G0ABcqLqzci, mor=377382219, order_id=318187252, connector_mandate_id 5577A590…35FF, 140 EUR): merchantInitiatedTransaction.originalAuthorizedAmount: null.

Before (issue diff signature):

body.typeDiff.processingInformation.authorizationOptions.merchantInitiatedTransaction.originalAuthorizedAmount = {"hyperswitch":"string","ucs":"null"}

Fix (this PR, router/src/core/unified_connector_service/transformers.rs line ~2113/2129, verified against current main db02b4f06a):
populates original_payment_authorized_amount from router_data.recurring_mandate_payment_data (was hard-coded None), mirroring the Direct gateway; proto field already exists so this is a client-side code fix (no proto change).

After: with this PR applied UCS emits the same originalAuthorizedAmount string as Direct → the facet clears.

Status: PR is 0 commits behind main, MERGEABLE, compile + tests green. The 2 red checks are the known-benign "Verify PR contains one or more linked issues" (linked issue is cross-repo in hyperswitch-cloud) and "Spell check" (unrelated santander AnualAnnual). The sibling MDI facets are already fixed on main by merged prism #1740; the initiator facet is covered by prism#1805. No new PR opened (DUP of this family).

@10X-GRACE

Copy link
Copy Markdown
Contributor Author

Re-validated against current main — additional shadow-diff sibling #17942

This PR (originalAuthorizedAmount facet) also resolves shadow-validation issue #17942 ([prod] flowbird / cybersource / repeat_payment), a duplicate of the same 3-facet family this branch targets.

RCA (Grafana / prod Loki, payment pay_BJRHabqY8RQOsMr5MmqK, x-request-id 019f194c-92d7-7d51-80ee-d746eaee2ce2):

  • Decoded UUIDv7 real txn time = 2026-06-30T16:11:16Z (the issue's 21:16Z First-Seen is the shadow-diff detection time, not the txn time).
  • Prod build = aef0be919 (2026.06.17.0-...aef0be919), predating the merge of prism fix(connector): deserialization error due to latest_charge stripe #1740 — so all facets appear in that prod build.
  • Prod UCS RepeatPayment request confirmed merchantInitiatedTransaction.originalAuthorizedAmount = null and initiator = null; merchant_order_id=377388822, order_id=318175310.

Before (issue #17942 diff signature):

processingInformation.authorizationOptions.merchantInitiatedTransaction.originalAuthorizedAmount  hyperswitch=string  ucs=null   ← THIS PR
processingInformation.authorizationOptions.initiator  hyperswitch=object  ucs=null   ← prism#1805
merchantDefinedInformation[0]/[1]/[3] brand/kind swap + key                                                              ← merged prism#1740

Facet ownership / after:

PR status: branch is 1 commit behind origin/main, but the only new main commit (#13140 surcharge routing) touches disjoint files — the single file here (crates/router/src/core/unified_connector_service/transformers.rs) has no conflict (git merge-tree clean). Code confirmed correct against current main. No new PR opened — this issue is a DUP of the family already covered here. (config/development.toml / creds excluded.)

@10X-GRACE

Copy link
Copy Markdown
Contributor Author

Re-validated against shadow diff #17954 (cybersource / repeat_payment / flowbird, prod)

This PR also resolves shadow diff #17954 — a duplicate of the same cybersource repeat_payment family this branch targets (originally #17471).

Grafana RCA (prod): sample pay_AOt87NQ2Q0FMwCzkYwqb, x-request-id 019f1955-42a1-7f13-a50f-fe6566c2b1ae → decoded real txn 2026-06-30T16:20:45.857Z. Prod build 2026.06.17.0-dirty-aef0be919 (pre-#1740). Prod UCS outbound (mor=377391113) emitted merchantInitiatedTransaction.originalAuthorizedAmount: null.

Before (issue #17954 diff signature, relevant facet):

processingInformation.authorizationOptions.merchantInitiatedTransaction.originalAuthorizedAmount
   hyperswitch: string   ucs: null

After (this PR): unified_connector_service/transformers.rs:2129 on current hs main is still the hard original_payment_authorized_amount: None,; this PR populates it from router_data.recurring_mandate_payment_data (original_payment_authorized_amount zipped with original_payment_authorized_currency), mirroring the Direct gateway — so UCS emits the same originalAuthorizedAmount string as HS Direct. The proto Money field already exists, so this is a pure client-mapping code fix (no proto change).

Sibling facets in this diff are owned elsewhere: merchantDefinedInformation[0]/[1]/[3] by MERGED prism #1740 (byte-identical on clean main), and authorizationOptions.initiator: null by open prism #1805.

PR state: MERGEABLE with green CI (compilation on MSRV + stable tests pass); the changed file is disjoint from newer main commits so there's no conflict. Code re-verified against current hs main — no new PR needed for #17954.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants