Skip to content

Gate New Stats behind remote feature flag#22996

Open
adalpari wants to merge 9 commits into
trunkfrom
feat/new-stats-remote-flag
Open

Gate New Stats behind remote feature flag#22996
adalpari wants to merge 9 commits into
trunkfrom
feat/new-stats-remote-flag

Conversation

@adalpari

@adalpari adalpari commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Description

The New Stats experience was previously gated by a local experimental
feature flag (ExperimentalFeatures.Feature.NEW_STATS), toggled both from the
experimental-features settings screen and from in-app "Try new stats" /
"Disable new stats" controls.

This PR replaces that local experimental flag with a new remote feature
flag, android_new_stats, so the rollout can be controlled server-side, and
keeps a local opt-in preference so users can move between the classic and new
experiences.

Routing (which Stats screen opens by default) is decided by either signal:
the New Stats screen opens when the remote flag android_new_stats is on
(the rollout default) or the user has opted in locally
(NEW_STATS_USER_OPTED_IN). The remote flag is the rollout default, not the
sole source of truth — a local opt-in is honored even when the remote flag
resolves to false (offline / not yet fetched / not segmented in). The remote
flag defaults to false when its value is unavailable.

The in-app switch controls persist the local opt-in preference:

  • "Try new stats" (from the classic screen) sets
    NEW_STATS_USER_OPTED_IN = true and opens the new experience. The opt-in
    persists across launches, so Stats keeps opening the new screen on
    subsequent launches.
  • "Disable new stats" (from the new screen) clears
    NEW_STATS_USER_OPTED_IN = false and returns to the classic experience.

The "Disable new stats" action is gated on the remote flag: it is shown only
when android_new_stats is off. When the remote flag is on, the new
experience is the rollout default, the action is hidden, and the user cannot
switch back (the local opt-in cannot be cleared from the UI while the rollout
flag is on).

Changes

  • New remote flag: added NewStatsFeatureConfig (@Feature("android_new_stats", false))
    and the NEW_STATS buildConfigField. The @Feature annotation auto-registers
    the default in the KSP-generated RemoteFeatureConfigDefaults.
  • New local opt-in preference: added NEW_STATS_USER_OPTED_IN
    (AppPrefs/AppPrefsWrapper), a persisted boolean that defaults to false.
  • Gating read swapped: ListItemActionHandler now opens New Stats when
    newStatsFeatureConfig.isEnabled() || appPrefsWrapper.getNewStatsUserOptedIn()
    (tests updated/added accordingly).
  • Local experimental flag removed: dropped the NEW_STATS entry from
    ExperimentalFeatures (it disappears from the experimental-features settings
    screen automatically).
  • "Try new stats" kept on the classic screen: the toolbar menu
    (res/menu/stats_toolbar_menu.xml) and the "new Stats experience" suggestion
    dialog in StatsFragment remain. Selecting them sets the opt-in preference to
    true and launches NewStatsActivity.
  • "Disable new stats" kept on the new screen, gated on the remote flag: the
    overflow action in NewStatsActivity is shown only when
    newStatsFeatureConfig.isEnabled() is false. When the remote flag is true
    the action is hidden, so users on the rollout cannot switch back. Selecting it
    clears the opt-in preference (false) and launches the classic StatsActivity.
  • Retained the supporting suggestion prefs (AppPrefs/AppPrefsWrapper), base
    English strings, and the STATS_NEW_STATS_ENABLED/STATS_NEW_STATS_DISABLED
    analytics events used by these controls.

Testing instructions

1. The experimental flag is gone

  1. Build & install the Jetpack debug app.
  2. Open Me → App Settings → Experimental Features.
  • Verify "New Stats" is no longer listed (it's now a remote flag, not a local experimental toggle).

2. a8c user → New Stats is presented and locked in

  1. Log in with an a8c (Automattic) account, which is segmented into the rollout (android_new_stats resolves to on).
  2. Open My Site → Stats.
  • Verify the new Stats screen opens directly.
  • Verify the overflow "Disable new stats" action is NOT shown — the user is locked into New Stats while the flag is on (the local opt-in cannot be cleared from the UI).

3. Random (non-a8c) user → ~90% see classic Stats, can opt in, and the opt-in persists

  1. Log in with a regular WordPress.com / Jetpack-connected account. With the rollout at 10%, there's a ~90% chance the flag resolves to off.
  2. Open My Site → Stats.
  • Verify the classic Stats screen opens (expected for the ~90% with the flag off).
  • Verify the "Try new stats" toolbar menu item is present, and the "A new Stats experience" suggestion dialog appears on first eligible launch.
  • Tap "Try new stats" (or "Try it out") → verify the new Stats screen opens. This persists the local opt-in (NEW_STATS_USER_OPTED_IN = true).
  • Relaunch the app (or return to My Site → Stats) → verify Stats now opens the new screen directly, because the local opt-in persists across launches even though the remote flag is off.
  • In the new Stats screen, verify the overflow "Disable new stats" action is present (remote flag is off) and tapping it returns you to the classic Stats screen. This clears the local opt-in (NEW_STATS_USER_OPTED_IN = false).
  • After disabling, relaunch / reopen Stats → verify it opens the classic screen again (opt-in was cleared).
  • (If you happen to land in the ~10% with the flag on, you'll see the new screen with no "Disable" action — same as scenario 2.)

Tip: to force a specific path locally regardless of segmentation, set NEW_STATS to "true"/"false" in WordPress/build.gradle (the build flag overrides the remote value) and rebuild. Note this only overrides the remote signal — a persisted local opt-in still routes to New Stats independently. To reset the local opt-in, use "Disable new stats" (when the remote flag is off) or clear app storage.

Replace the local NEW_STATS experimental flag with a server-controlled
remote feature flag so the New Stats rollout can be managed remotely.
Because the remote flag is read-only, the manual opt-in/opt-out toggles
are removed and the flag is now the single source of truth.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dangermattic

dangermattic commented Jun 17, 2026

Copy link
Copy Markdown
Collaborator
1 Warning
⚠️ PR is not assigned to a milestone.

Generated by 🚫 Danger

@wpmobilebot

wpmobilebot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

App Icon📲 You can test the changes from this Pull Request in Jetpack Android by scanning the QR code below to install the corresponding build.

App NameJetpack Android
Build TypeDebug
Versionpr22996-c979996
Build Number1497
Application IDcom.jetpack.android.prealpha
Commitc979996
Installation URL51nh6ptu257f8
Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.

@wpmobilebot

wpmobilebot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

App Icon📲 You can test the changes from this Pull Request in WordPress Android by scanning the QR code below to install the corresponding build.

App NameWordPress Android
Build TypeDebug
Versionpr22996-c979996
Build Number1497
Application IDorg.wordpress.android.prealpha
Commitc979996
Installation URL3gbasvh2tqhfg
Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.

@wpmobilebot

Copy link
Copy Markdown
Contributor

🤖 Build Failure Analysis

This build has failures. Claude has analyzed them - check the build annotations for details.

adalpari and others added 2 commits June 17, 2026 12:44
…rrors

The previous commit removed the New Stats opt-in/opt-out strings from the
default locale but left them in the translation files, causing 204
ExtraTranslation lint errors. Remove the orphaned translations.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Jun 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 41.17647% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 37.44%. Comparing base (c51dd34) to head (c979996).

Files with missing lines Patch % Lines
.../wordpress/android/ui/newstats/NewStatsActivity.kt 0.00% 5 Missing ⚠️
.../java/org/wordpress/android/ui/prefs/AppPrefs.java 0.00% 3 Missing ⚠️
.../org/wordpress/android/ui/prefs/AppPrefsWrapper.kt 0.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##            trunk   #22996      +/-   ##
==========================================
- Coverage   37.44%   37.44%   -0.01%     
==========================================
  Files        2325     2326       +1     
  Lines      125520   125529       +9     
  Branches    17227    17229       +2     
==========================================
+ Hits        47007    47008       +1     
- Misses      74693    74701       +8     
  Partials     3820     3820              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

adalpari and others added 3 commits June 17, 2026 17:53
Re-add the "Try new stats" toolbar menu and suggestion dialog on the
classic Stats screen, and the "Disable new stats" overflow on the new
Stats screen. The latter is shown only when the android_new_stats remote
flag is off, so users on the rollout cannot switch back. Controls are
plain navigation now; the remote flag remains the routing source of truth
(no local ExperimentalFeatures flag is reintroduced).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…o companion

The previous cleanup removed translations for eight New Stats string keys, but
only two (experimental_new_stats, experimental_new_stats_description) are
actually orphaned. The other six are still rendered by the kept controls
(stats_try_new_stats, stats_switch_to_old_stats, and the four
stats_new_stats_suggestion_* strings), so deleting their translations made
non-English users see English text. Restore those six across all locales while
keeping the two genuinely-orphaned experimental keys removed.

Also move NEW_STATS_REMOTE_FIELD into a companion object const referenced from
@feature, matching the convention used by the other FeatureConfig classes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@adalpari adalpari requested a review from nbradbury June 18, 2026 12:59
adalpari and others added 2 commits June 19, 2026 10:36
Show New Stats when the remote feature flag is on or the user has opted
in locally. Opting in via the old Stats screen sets the preference, and
switching back to old Stats clears it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@adalpari adalpari marked this pull request as ready for review June 19, 2026 09:09
@adalpari adalpari requested a review from a team as a code owner June 19, 2026 09:09
@nbradbury

Copy link
Copy Markdown
Contributor

From Claude:

The description states the in-app controls “no longer persist any local flag, so the remote flag remains the routing source of truth” and “plain navigation.” The actual implementation (and the latest commit, “Add local opt-in preference for New Stats”) does the opposite — it persists NEW_STATS_USER_OPTED_IN and that pref participates in routing. The remote flag is the rollout default, not the sole source of truth. Please update the Description and the Testing section (scenario 3 now implies the opt-in persists across launches) so reviewers/QA test the right behavior.

@adalpari

Copy link
Copy Markdown
Contributor Author

From Claude:

The description states the in-app controls “no longer persist any local flag, so the remote flag remains the routing source of truth” and “plain navigation.” The actual implementation (and the latest commit, “Add local opt-in preference for New Stats”) does the opposite — it persists NEW_STATS_USER_OPTED_IN and that pref participates in routing. The remote flag is the rollout default, not the sole source of truth. Please update the Description and the Testing section (scenario 3 now implies the opt-in persists across launches) so reviewers/QA test the right behavior.

Good catch! It seems like the PR description was outdated. I've updated it now.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants