Skip to content

feat(checkout): Migrate CBA MPGS to Resolver Configuration#3075

Open
henrikh-kovalenko wants to merge 2 commits into
masterfrom
PI-4748
Open

feat(checkout): Migrate CBA MPGS to Resolver Configuration#3075
henrikh-kovalenko wants to merge 2 commits into
masterfrom
PI-4748

Conversation

@henrikh-kovalenko

@henrikh-kovalenko henrikh-kovalenko commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

What/Why?

Migrate CBA MPGS payment method to the new resolver-based architecture by registering it in the HostedCreditCardPaymentMethod component resolver (packages/hosted-credit-card-integration).

The migration is gated behind the PI-4748.cba_resolver_configuration experiment:

Experiment ON — CBA MPGS routes through the new resolver flow (HostedCreditCardComponent), where createCBAMPGSPaymentStrategy is included conditionally.
Experiment OFF — CBA MPGS falls back to the legacy V1 flow (HostedCreditCardPaymentMethod in core), where createCBAMPGSPaymentStrategy is added to the integration list conditionally.
The experiment flag is checked via isExperimentEnabled in core and directly via checkoutSettings.features in the hosted-credit-card-integration package (where the utility is not available). Both conditional blocks are intentionally duplicated to make cleanup straightforward once the experiment is fully rolled out.

Added global functional for experiment

Rollout/Rollback

roll back this commit

Testing

without 3ds isHostedFormEnabled false

without.3ds.isHostedFormEnabled.false.mov

with 3ds isHostedFormEnabled false

with.3ds.isHostedFormEnabled.false.mov

without 3ds isHostedFormEnabled true

without.3ds.isHostedFormEnabled.true.mov

with 3ds isHostedFormEnabled true

with.3ds.isHostedFormEnabled.true.mov

Note

Medium Risk
Changes which checkout UI and payment initialization path CBA MPGS uses, gated by a feature flag; incorrect flag handling could break MPGS checkout for some stores.

Overview
CBA MPGS can route through the hosted-credit-card resolver when PI-4748.cba_resolver_configuration is on, instead of always using the legacy core hosted card path.

Resolver entries can now declare an optional experiment on PaymentMethodResolveId. resolvePaymentMethod filters the generated registry so experiment-gated mappings (e.g. cba_mpgs) only apply when the flag is enabled; PaymentMethodV2 passes checkoutSettings into that resolver.

createCBAMPGSPaymentStrategy is wired on exactly one path: included in the new HostedCreditCardComponent integrations when the experiment is on, and kept in core HostedCreditCardPaymentMethod when it is off, so rollout can flip without double-registering the strategy.

Reviewed by Cursor Bugbot for commit 396016e. Bugbot is set up for automated code reviews on this repo. Configure here.

@henrikh-kovalenko henrikh-kovalenko requested a review from a team as a code owner June 10, 2026 13:35
animesh1987
animesh1987 previously approved these changes Jun 11, 2026
bc-ania
bc-ania previously approved these changes Jun 11, 2026

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 4550f1f. Configure here.

Comment thread packages/core/src/app/payment/resolvePaymentMethod.ts
@henrikh-kovalenko henrikh-kovalenko force-pushed the PI-4748 branch 3 times, most recently from 7059546 to 846c74d Compare June 23, 2026 12:38
@@ -35,6 +38,13 @@ const HostedCreditCardPaymentMethod: FunctionComponent<
initializePayment,
...rest
}) => {
const { selectedState: config } = useCheckout(({ data }) => data.getConfig());
const isCBAMPGSResolverEnabled = isExperimentEnabled(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

): ComponentType<PaymentMethodProps> | undefined {
const { ComponentRegistry, ...allExports } = lazyPaymentMethods;
const filteredMethods = Object.fromEntries(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we adding this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @animesh1987 we want to experiments for our PaymentMethods
However we can't somehow change this
image
that's why one place where we can check this experiments in this file, and we filter our payment methods if experiment is false then this method should not be in result arr

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for behavior of this PR we set experiment name in config then in file resolvePaymentMethod we check is this experiment true or false if it is true pr if we don't have experiment then this method will be in result arr if not than we will not have this mthod in arr

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Attaching an experiment name to a payment method config requires some explanations on the purpose of this experiment.

Could we use the experiment to control payment method identifiers instead of making it part of the payment method resolution logic?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This experiment is specifically needed to safely migrate the CBA MPGS and other payment providers that are using hosted fields from the legacy core flow to the new resolver-based package architecture.
Why it needs to be on the resolver level, not on the identifier level:
The resolver is the exact point where the routing decision is made — it determines whether a payment method renders via the new package component or falls back to the legacy V1 core component. Controlling the identifier itself wouldn't give us that routing control, since the same cba_mpgs ID needs to exist in both paths during the transition.
Why we're being cautious:
We previously had an incident with the hosted fields migration process, so we want to roll this out gradually and have a clean rollback path. The experiment flag gives us that safety net.
What happens after the migration is complete:
Once we've validated the rollout, we'll remove both the experiment flag and all the conditional logic around it — it's intentionally duplicated in the code to make that cleanup straightforward (each side clearly shows what gets removed).
Future migrations:
We'll need similar experiments for migrating other payment providers through the same pattern. The experiment field on PaymentMethodResolveId is designed to be generic for exactly that purpose — any future provider migration can use the same mechanism without changes to the resolver infrastructure itself.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My question is narrower: it's about where the gate lives, not whether it exists.

Agreed on the rollout safety, the experiment, gradual rollout, and clean revert path. All make sense given the prior incident, no objection there.

The point that the routing decision must happen at runtime in the resolver is right (the registry is generated at build time). But that doesn't require an experiment to be a field on PaymentMethodResolveId.

If we do want a generic per-package migration-gate mechanism long term, I think that's worth its own small design rather than an experiment field.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

 this is not long term, we need this for migration maybe 3 providers.
 Maybe you have some suggestions how we can resolve it ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the context. That changes the perspective.

this is not long term, we need this for migration maybe 3 providers.

If possible, could you please add this context as comments? My concern is we will soon forget about it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I created task for remove this functional after migration will be completed PI-5464

const isCBAMPGSResolverEnabled = isExperimentEnabled(
config?.checkoutSettings,
'PI-4748.cba_resolver_configuration',
false,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The purpose of this fallback value is for the time when PI-4748.cba_resolver_configuration is undefined in the checkout settings.
If we have surfaced it, we don't need to explicitly set the value here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But we have default value true and we need false
image

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please explain when the experiment will not appear in the features[]?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before the experiment is surfaced/registered in LaunchDarkly (or whatever feature flag service is used), the key won't exist in features[] at all — features['PI-4748.cba_resolver_configuration'] will be undefined.

In that case ?? fallbackValue kicks in. Since the default fallback in isExperimentEnabled is true, without explicitly passing false here, cba_mpgs would resolve through the new flow on day one — before we've intentionally enabled it for anyone. That's exactly what we want to avoid.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, this is intended use case when we introduced this fallback value.

The experiment appears to be added on Jun 23, 2026 at https://app.launchdarkly.com/projects/default/flags/PI-4748.cba_resolver_configuration/targeting?env=production&selected-env=production.

Is anything blocking us from showing it to Checkout FE now?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I turned on this flag if you about that. Or I miss understood

): ComponentType<PaymentMethodProps> | undefined {
const { ComponentRegistry, ...allExports } = lazyPaymentMethods;
const filteredMethods = Object.fromEntries(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Attaching an experiment name to a payment method config requires some explanations on the purpose of this experiment.

Could we use the experiment to control payment method identifiers instead of making it part of the payment method resolution logic?

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.

4 participants