From 43e44b9bc25b95918d803702ecf5ac3fb366c4dc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marco=20Ch=C3=A1vez?= <marco@expensify.com>
Date: Fri, 13 Mar 2026 15:12:36 -0600
Subject: [PATCH 1/4] Add rhpHomePage variant (D) to onboarding A/B/C/D test

Add frontend handling for the new rhpHomePage variant that navigates
users to the Home page after onboarding, without opening the side
panel or test drive modal. Concierge Anywhere remains accessible
in the #admins room naturally.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---
 src/CONST/index.ts                               | 1 +
 src/components/SidePanel/RHPVariantTest/index.ts | 9 ++++++++-
 src/types/onyx/OnboardingRHPVariant.ts           | 5 +++--
 3 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/src/CONST/index.ts b/src/CONST/index.ts
index f2d66c6656c6..ab9a72ed9772 100644
--- a/src/CONST/index.ts
+++ b/src/CONST/index.ts
@@ -6373,6 +6373,7 @@ const CONST = {
     ONBOARDING_RHP_VARIANT: {
         RHP_CONCIERGE_DM: 'rhpConciergeDm',
         RHP_ADMINS_ROOM: 'rhpAdminsRoom',
+        RHP_HOME_PAGE: 'rhpHomePage',
         CONTROL: 'control',
     },
     ACTIONABLE_TRACK_EXPENSE_WHISPER_MESSAGE: 'What would you like to do with this expense?',
diff --git a/src/components/SidePanel/RHPVariantTest/index.ts b/src/components/SidePanel/RHPVariantTest/index.ts
index 43cfe8e7d11d..3871a124b49c 100644
--- a/src/components/SidePanel/RHPVariantTest/index.ts
+++ b/src/components/SidePanel/RHPVariantTest/index.ts
@@ -34,8 +34,9 @@ const shouldOpenRHPVariant: ShouldOpenRHPVariant = () => {
     const isMicroCompany = onboardingCompanySize === CONST.ONBOARDING_COMPANY_SIZE.MICRO;
     const isRHPConciergeDM = onboardingRHPVariant === CONST.ONBOARDING_RHP_VARIANT.RHP_CONCIERGE_DM;
     const isRHPAdminsRoom = onboardingRHPVariant === CONST.ONBOARDING_RHP_VARIANT.RHP_ADMINS_ROOM;
+    const isRHPHomePage = onboardingRHPVariant === CONST.ONBOARDING_RHP_VARIANT.RHP_HOME_PAGE;
 
-    return isMicroCompany && (isRHPConciergeDM || isRHPAdminsRoom);
+    return isMicroCompany && (isRHPConciergeDM || isRHPAdminsRoom || isRHPHomePage);
 };
 
 /**
@@ -43,8 +44,14 @@ const shouldOpenRHPVariant: ShouldOpenRHPVariant = () => {
  * - Control: navigate to the last accessed report on small screens, do not open side panel
  * - RHP Concierge DM: navigate to the workspace overview and open the side panel with the Concierge DM
  * - RHP Admins Room: navigate to the workspace overview and open the side panel with the Admins Room
+ * - RHP Home Page: navigate to the Home page without opening the side panel or test drive modal
  */
 const handleRHPVariantNavigation: HandleRHPVariantNavigation = (onboardingPolicyID) => {
+    if (onboardingRHPVariant === CONST.ONBOARDING_RHP_VARIANT.RHP_HOME_PAGE) {
+        Navigation.navigate(ROUTES.HOME);
+        return;
+    }
+
     Navigation.navigate(ROUTES.WORKSPACE_OVERVIEW.getRoute(onboardingPolicyID));
     SidePanelActions.openSidePanel(true);
 };
diff --git a/src/types/onyx/OnboardingRHPVariant.ts b/src/types/onyx/OnboardingRHPVariant.ts
index 271e1977e737..9ac25b94c31c 100644
--- a/src/types/onyx/OnboardingRHPVariant.ts
+++ b/src/types/onyx/OnboardingRHPVariant.ts
@@ -1,9 +1,10 @@
 /**
- * The variant of the onboarding RHP for A/B/C testing
+ * The variant of the onboarding RHP for A/B/C/D testing
  * @description 'control' - The variant with the Concierge DM
  * @description 'rhpConciergeDm' - Admin of workspace with Concierge DM
  * @description 'rhpAdminsRoom' - Admin of workspace with the admins room
+ * @description 'rhpHomePage' - Navigate to Home page with Concierge Anywhere accessible in #admins room
  */
-type OnboardingRHPVariant = 'rhpConciergeDm' | 'rhpAdminsRoom' | 'control';
+type OnboardingRHPVariant = 'rhpConciergeDm' | 'rhpAdminsRoom' | 'rhpHomePage' | 'control';
 
 export default OnboardingRHPVariant;

From 1e7a8503ed47dca112e801fb4e13f0c2e13a38c5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marco=20Ch=C3=A1vez?= <marco@expensify.com>
Date: Fri, 13 Mar 2026 15:25:47 -0600
Subject: [PATCH 2/4] Fix race condition: pass RHP variant from API response to
 navigation

The module-level onboardingRHPVariant variable in RHPVariantTest/index.ts
is populated by an Onyx.connectWithoutView callback that may not have
fired by the time navigateAfterOnboarding calls shouldOpenRHPVariant.
This causes intermittent failures where users assigned to rhpConciergeDm
or rhpAdminsRoom fall through to default navigation instead of the
workspace editor.

Fix: accept an optional variantOverride parameter in shouldOpenRHPVariant
and handleRHPVariantNavigation. The caller in BaseOnboardingInterestedFeatures
extracts the variant directly from the CompleteGuidedSetup API response
onyxData and passes it through, bypassing the async Onyx callback entirely.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---
 .../SidePanel/RHPVariantTest/index.native.ts  |  6 ++++--
 .../SidePanel/RHPVariantTest/index.ts         | 20 +++++++++++++------
 .../SidePanel/RHPVariantTest/types.ts         |  6 ++++--
 src/libs/navigateAfterOnboarding.ts           |  8 ++++++--
 .../BaseOnboardingInterestedFeatures.tsx      |  9 ++++++++-
 5 files changed, 36 insertions(+), 13 deletions(-)

diff --git a/src/components/SidePanel/RHPVariantTest/index.native.ts b/src/components/SidePanel/RHPVariantTest/index.native.ts
index 466080a1b07d..53127b64b42c 100644
--- a/src/components/SidePanel/RHPVariantTest/index.native.ts
+++ b/src/components/SidePanel/RHPVariantTest/index.native.ts
@@ -3,11 +3,13 @@ import type {HandleRHPVariantNavigation, ShouldOpenRHPVariant} from './types';
 /**
  * Side Panel is not supported on native platforms, so we always return false.
  */
-const shouldOpenRHPVariant: ShouldOpenRHPVariant = () => false;
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+const shouldOpenRHPVariant: ShouldOpenRHPVariant = (_variantOverride) => false;
 
 /**
  * No-op on native platforms since Side Panel is not supported.
  */
-const handleRHPVariantNavigation: HandleRHPVariantNavigation = () => {};
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+const handleRHPVariantNavigation: HandleRHPVariantNavigation = (_onboardingPolicyID, _variantOverride) => {};
 
 export {shouldOpenRHPVariant, handleRHPVariantNavigation};
diff --git a/src/components/SidePanel/RHPVariantTest/index.ts b/src/components/SidePanel/RHPVariantTest/index.ts
index 3871a124b49c..6cd1ab028ec0 100644
--- a/src/components/SidePanel/RHPVariantTest/index.ts
+++ b/src/components/SidePanel/RHPVariantTest/index.ts
@@ -29,12 +29,17 @@ Onyx.connectWithoutView({
 /**
  * Determines if the user should be navigated to the RHP variant side panel after onboarding.
  * The RHP variant is only shown to micro companies that are part of the RHP experiment.
+ *
+ * Accepts an optional variantOverride to bypass the module-level Onyx variable, avoiding a race
+ * condition where the Onyx callback hasn't fired yet when this is called immediately after the
+ * CompleteGuidedSetup API response.
  */
-const shouldOpenRHPVariant: ShouldOpenRHPVariant = () => {
+const shouldOpenRHPVariant: ShouldOpenRHPVariant = (variantOverride) => {
+    const variant = variantOverride ?? onboardingRHPVariant;
     const isMicroCompany = onboardingCompanySize === CONST.ONBOARDING_COMPANY_SIZE.MICRO;
-    const isRHPConciergeDM = onboardingRHPVariant === CONST.ONBOARDING_RHP_VARIANT.RHP_CONCIERGE_DM;
-    const isRHPAdminsRoom = onboardingRHPVariant === CONST.ONBOARDING_RHP_VARIANT.RHP_ADMINS_ROOM;
-    const isRHPHomePage = onboardingRHPVariant === CONST.ONBOARDING_RHP_VARIANT.RHP_HOME_PAGE;
+    const isRHPConciergeDM = variant === CONST.ONBOARDING_RHP_VARIANT.RHP_CONCIERGE_DM;
+    const isRHPAdminsRoom = variant === CONST.ONBOARDING_RHP_VARIANT.RHP_ADMINS_ROOM;
+    const isRHPHomePage = variant === CONST.ONBOARDING_RHP_VARIANT.RHP_HOME_PAGE;
 
     return isMicroCompany && (isRHPConciergeDM || isRHPAdminsRoom || isRHPHomePage);
 };
@@ -45,9 +50,12 @@ const shouldOpenRHPVariant: ShouldOpenRHPVariant = () => {
  * - RHP Concierge DM: navigate to the workspace overview and open the side panel with the Concierge DM
  * - RHP Admins Room: navigate to the workspace overview and open the side panel with the Admins Room
  * - RHP Home Page: navigate to the Home page without opening the side panel or test drive modal
+ *
+ * Accepts an optional variantOverride for the same race-condition reason as shouldOpenRHPVariant.
  */
-const handleRHPVariantNavigation: HandleRHPVariantNavigation = (onboardingPolicyID) => {
-    if (onboardingRHPVariant === CONST.ONBOARDING_RHP_VARIANT.RHP_HOME_PAGE) {
+const handleRHPVariantNavigation: HandleRHPVariantNavigation = (onboardingPolicyID, variantOverride) => {
+    const variant = variantOverride ?? onboardingRHPVariant;
+    if (variant === CONST.ONBOARDING_RHP_VARIANT.RHP_HOME_PAGE) {
         Navigation.navigate(ROUTES.HOME);
         return;
     }
diff --git a/src/components/SidePanel/RHPVariantTest/types.ts b/src/components/SidePanel/RHPVariantTest/types.ts
index 7efd441c0526..15dff41a1af6 100644
--- a/src/components/SidePanel/RHPVariantTest/types.ts
+++ b/src/components/SidePanel/RHPVariantTest/types.ts
@@ -1,4 +1,6 @@
-type ShouldOpenRHPVariant = () => boolean;
-type HandleRHPVariantNavigation = (onboardingPolicyID?: string) => void;
+import type {OnboardingRHPVariant} from '@src/types/onyx';
+
+type ShouldOpenRHPVariant = (variantOverride?: OnboardingRHPVariant | null) => boolean;
+type HandleRHPVariantNavigation = (onboardingPolicyID?: string, variantOverride?: OnboardingRHPVariant | null) => void;
 
 export type {ShouldOpenRHPVariant, HandleRHPVariantNavigation};
diff --git a/src/libs/navigateAfterOnboarding.ts b/src/libs/navigateAfterOnboarding.ts
index cfb8de469374..8c7b4b8e0bac 100644
--- a/src/libs/navigateAfterOnboarding.ts
+++ b/src/libs/navigateAfterOnboarding.ts
@@ -1,5 +1,6 @@
 import {handleRHPVariantNavigation, shouldOpenRHPVariant} from '@components/SidePanel/RHPVariantTest';
 import ROUTES from '@src/ROUTES';
+import type {OnboardingRHPVariant} from '@src/types/onyx';
 import {setDisableDismissOnEscape} from './actions/Modal';
 import shouldOpenOnAdminRoom from './Navigation/helpers/shouldOpenOnAdminRoom';
 import Navigation from './Navigation/Navigation';
@@ -50,11 +51,12 @@ function navigateAfterOnboarding(
     onboardingPolicyID?: string,
     onboardingAdminsChatReportID?: string,
     shouldPreventOpenAdminRoom = false,
+    onboardingRHPVariant?: OnboardingRHPVariant | null,
 ) {
     setDisableDismissOnEscape(false);
 
-    if (shouldOpenRHPVariant()) {
-        handleRHPVariantNavigation(onboardingPolicyID);
+    if (shouldOpenRHPVariant(onboardingRHPVariant)) {
+        handleRHPVariantNavigation(onboardingPolicyID, onboardingRHPVariant);
         return;
     }
 
@@ -83,6 +85,7 @@ function navigateAfterOnboardingWithMicrotaskQueue(
     onboardingPolicyID?: string,
     onboardingAdminsChatReportID?: string,
     shouldPreventOpenAdminRoom = false,
+    onboardingRHPVariant?: OnboardingRHPVariant | null,
 ) {
     Navigation.dismissModal();
     Navigation.setNavigationActionToMicrotaskQueue(() => {
@@ -94,6 +97,7 @@ function navigateAfterOnboardingWithMicrotaskQueue(
             onboardingPolicyID,
             onboardingAdminsChatReportID,
             shouldPreventOpenAdminRoom,
+            onboardingRHPVariant,
         );
     });
 }
diff --git a/src/pages/OnboardingInterestedFeatures/BaseOnboardingInterestedFeatures.tsx b/src/pages/OnboardingInterestedFeatures/BaseOnboardingInterestedFeatures.tsx
index 9429cd1531cc..4cd9edfc256e 100644
--- a/src/pages/OnboardingInterestedFeatures/BaseOnboardingInterestedFeatures.tsx
+++ b/src/pages/OnboardingInterestedFeatures/BaseOnboardingInterestedFeatures.tsx
@@ -33,6 +33,7 @@ import CONST from '@src/CONST';
 import type {TranslationPaths} from '@src/languages/types';
 import ONYXKEYS from '@src/ONYXKEYS';
 import ROUTES from '@src/ROUTES';
+import type {OnboardingRHPVariant} from '@src/types/onyx';
 import type {BaseOnboardingInterestedFeaturesProps, Feature, SectionObject} from './types';
 
 function BaseOnboardingInterestedFeatures({shouldUseNativeStyles}: BaseOnboardingInterestedFeaturesProps) {
@@ -212,7 +213,7 @@ function BaseOnboardingInterestedFeatures({shouldUseNativeStyles}: BaseOnboardin
                 setOnboardingPolicyID(policyID);
             }
 
-            await completeOnboarding({
+            const response = await completeOnboarding({
                 engagementChoice: onboardingPurposeSelected,
                 onboardingMessage: onboardingMessages[onboardingPurposeSelected],
                 adminsChatReportID,
@@ -228,6 +229,11 @@ function BaseOnboardingInterestedFeatures({shouldUseNativeStyles}: BaseOnboardin
                 betas,
             });
 
+            // Extract the RHP variant directly from the API response to avoid a race condition
+            // where the Onyx callback hasn't fired yet when navigateAfterOnboarding is called.
+            const rhpVariantUpdate = response?.onyxData?.find((update) => update.key === ONYXKEYS.NVP_ONBOARDING_RHP_VARIANT);
+            const rhpVariant = rhpVariantUpdate?.value as OnboardingRHPVariant | undefined;
+
             // Avoid creating new WS because onboardingPolicyID is cleared before unmounting
             // eslint-disable-next-line @typescript-eslint/no-deprecated
             InteractionManager.runAfterInteractions(() => {
@@ -246,6 +252,7 @@ function BaseOnboardingInterestedFeatures({shouldUseNativeStyles}: BaseOnboardin
                 // Onboarding tasks would show in Concierge instead of admins room for testing accounts, we should open where onboarding tasks are located
                 // See https://github.com/Expensify/App/issues/57167 for more details
                 (session?.email ?? '').includes('+'),
+                rhpVariant,
             );
         } catch (error) {
             Log.warn('[BaseOnboardingInterestedFeatures] Error completing onboarding', {error});

From 092a5880a0e3e0d39f81f096f6099584242414bf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marco=20Ch=C3=A1vez?= <marco@expensify.com>
Date: Fri, 13 Mar 2026 16:05:13 -0600
Subject: [PATCH 3/4] Fix typecheck: cast onyxData to broader type for variant
 extraction

The response onyxData is typed with a narrow key union that does not
include nvp_onboardingRHPVariant. Cast to Array<{key: string; value: unknown}>
to allow searching for the variant key.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---
 .../BaseOnboardingInterestedFeatures.tsx                        | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/pages/OnboardingInterestedFeatures/BaseOnboardingInterestedFeatures.tsx b/src/pages/OnboardingInterestedFeatures/BaseOnboardingInterestedFeatures.tsx
index 4cd9edfc256e..2351f302218e 100644
--- a/src/pages/OnboardingInterestedFeatures/BaseOnboardingInterestedFeatures.tsx
+++ b/src/pages/OnboardingInterestedFeatures/BaseOnboardingInterestedFeatures.tsx
@@ -231,7 +231,7 @@ function BaseOnboardingInterestedFeatures({shouldUseNativeStyles}: BaseOnboardin
 
             // Extract the RHP variant directly from the API response to avoid a race condition
             // where the Onyx callback hasn't fired yet when navigateAfterOnboarding is called.
-            const rhpVariantUpdate = response?.onyxData?.find((update) => update.key === ONYXKEYS.NVP_ONBOARDING_RHP_VARIANT);
+            const rhpVariantUpdate = (response?.onyxData as Array<{key: string; value: unknown}> | undefined)?.find((update) => update.key === ONYXKEYS.NVP_ONBOARDING_RHP_VARIANT);
             const rhpVariant = rhpVariantUpdate?.value as OnboardingRHPVariant | undefined;
 
             // Avoid creating new WS because onboardingPolicyID is cleared before unmounting

From 6830fb4b3cf8d07381e81adec81910d91dc4ba4b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marco=20Ch=C3=A1vez?= <marco@expensify.com>
Date: Fri, 13 Mar 2026 17:17:23 -0600
Subject: [PATCH 4/4] Open side panel for rhpHomePage variant after navigating
 to Home

The rhpHomePage variant should open the RHP with Concierge DM on the
Home page, not just navigate to Home silently. This matches the
experiment intent: test whether landing on Home + RHP Concierge
performs differently from workspace overview + RHP Concierge.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---
 src/components/SidePanel/RHPVariantTest/index.ts | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/components/SidePanel/RHPVariantTest/index.ts b/src/components/SidePanel/RHPVariantTest/index.ts
index 6cd1ab028ec0..1f6ba8f3393e 100644
--- a/src/components/SidePanel/RHPVariantTest/index.ts
+++ b/src/components/SidePanel/RHPVariantTest/index.ts
@@ -49,7 +49,7 @@ const shouldOpenRHPVariant: ShouldOpenRHPVariant = (variantOverride) => {
  * - Control: navigate to the last accessed report on small screens, do not open side panel
  * - RHP Concierge DM: navigate to the workspace overview and open the side panel with the Concierge DM
  * - RHP Admins Room: navigate to the workspace overview and open the side panel with the Admins Room
- * - RHP Home Page: navigate to the Home page without opening the side panel or test drive modal
+ * - RHP Home Page: navigate to the Home page and open the side panel with the Concierge DM
  *
  * Accepts an optional variantOverride for the same race-condition reason as shouldOpenRHPVariant.
  */
@@ -57,6 +57,7 @@ const handleRHPVariantNavigation: HandleRHPVariantNavigation = (onboardingPolicy
     const variant = variantOverride ?? onboardingRHPVariant;
     if (variant === CONST.ONBOARDING_RHP_VARIANT.RHP_HOME_PAGE) {
         Navigation.navigate(ROUTES.HOME);
+        SidePanelActions.openSidePanel(true);
         return;
     }
 
