Skip to content

Replace the Jetpack features removal remote flags with a fixed rule - #26280

Merged
jkmassel merged 3 commits into
trunkfrom
jkmassel/remove-jetpack-removal-flags
Oct 29, 2026
Merged

jkmassel merged 3 commits into
trunkfrom
jkmassel/remove-jetpack-removal-flags

Conversation

@jkmassel

@jkmassel jkmassel commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Replaces the eight Jetpack features removal remote flags with a fixed rule that gives the result the server already sends. Users see no change, apart from the timing fix described under Behaviour change.

Why

The server sends the same values to every app and version we checked (org.wordpress and com.automattic.jetpack, marketing versions 25.0, 26.5, 27.3 and 27.5, checked 2026-10-28):

Remote key Value
jp_removal_one, jp_removal_two, jp_removal_three, jp_removal_static_posters true
jp_removal_four, jp_removal_new_users false
jp_removal_self_hosted true anonymous, false with a WordPress.com token
prevent_duplicate_notifs_remote_field true

The app only uses jp_removal_self_hosted when there is no WordPress.com account, and without an account it fetches the flags anonymously. So it effectively reads true.

Changes

  • JetpackFeaturesRemovalCoordinator.generalPhase(): WordPress app with a WordPress.com account → .staticScreens; WordPress app without one → .selfHosted; any other app → .normal. Same result as the old flag chain with the values above.
  • siteCreationPhase(): WordPress app → .two if the user has a site, otherwise .normal. Other apps → .normal.
  • JetpackNotificationMigrationService: the duplicate-notifications check is always on. The flag's server value and its app default were already true.
  • RemoteFeatureFlag: the eight cases are gone. The server keys stay, because older app versions still read them.
  • RootViewCoordinator, JetpackBrandingTextProvider and JetpackBrandingMenuCardPresenter no longer take a RemoteFeatureFlagStore. The last two take a phaseProvider closure instead, so their existing per-phase tests still run until Remove the Jetpack features removal phases no one can reach #26281 deletes those phases.
  • JetpackFeaturesRemovalCoordinatorTests is rewritten in Swift Testing. Both phase functions take the account and site checks as @autoclosure defaults, so the suite runs without Core Data or other shared state and is safe to run in parallel.
  • Unit test host: TestingAppDelegate sets currentAppUIType = .normal at launch. On trunk, an unfetched flag meant the normal phase, so tests that check jetpackFeaturesEnabled() saw every feature on. With the fixed rule a test process with no WordPress.com account would be .selfHosted; DomainCreditEligibilityTests failed without this. RootViewCoordinatorTests now restores the value it changes.

The phases no one can reach (.one to .four, .newUsers) are left in place to keep this diff reviewable. #26281 deletes them.

The first commit only runs swift-format on the touched files. Review the second commit for the actual change.

Rebased onto the 27.4 Reader work

The 27.4 merge-back (#26297) added "Reader in WordPress app" (readerInWordPressApp), which builds on the same phase logic. The rebase keeps all of it. The fixed rule simply feeds into it:

  • RootViewCoordinator.appUIType(for:isReaderInWordPressAppEnabled:) maps .staticScreens to .staticScreensWithReader when the flag is on. The account-change observer and reload tracking are unchanged.
  • One trunk test expectation changed: testReloadUIWhenSwitchingFromStaticScreensWithReader signs out with a never-fetched flag store, which trunk resolves to .normal. With the fixed rule it is .simplified. This is case 2 under Behaviour change, which on trunk can now also happen through the account-change observer, not only on relaunch.
  • The other RootViewCoordinatorTests drop their flag-store helpers. The normal-UI tab bar test now uses the Jetpack app, since the WordPress app can't reach the normal UI.
  • Trunk's two staticScreensWithReader state tests are kept, in a small XCTest class next to the Swift Testing suite, because they set a shared static.

Behaviour change

On trunk, the self-hosted phase depends on a cached flag whose app default is false. The UI type is chosen when the app launches, so a user with no WordPress.com account gets the normal UI (Reader, Notifications and Me tabs) until the flag is cached and the app is relaunched:

  1. First launch after signing in to a self-hosted site. Checked on a simulator: trunk showed the normal UI with the flag fetch blocked and also with it allowed. Only the next launch showed the simplified UI.
  2. After signing out of WordPress.com with a self-hosted site left. The cached value came from the signed-in fetch, which returns false, so trunk keeps the normal UI until a later anonymous fetch and relaunch. This one comes from reading the code; it was not reproduced on a simulator.

With the fixed rule these users get the simplified UI immediately.

Trunk, first launch This PR, first launch
Trunk: normal tab bar UI on first launch This PR: simplified site menu on first launch

The trunk screenshot uses the normal UI's tab bar. This PR's screenshot is the simplified site menu, with no tab bar.

Test plan

  • Unit tests: full WordPressUnitTests plan on an iPhone 17 Pro (iOS 27.0) simulator — 4,199 passed, 0 failed, 5 skipped
  • After the rebase onto the 27.4 merge-back: full WordPressUnitTests plan on an iPhone 18 Pro (iOS 27.0) simulator — 4,354 passed, 0 failed, 5 skipped
  • swift-format and SwiftLint clean on every touched file
  • Simulator (iPhone 18 Pro, iOS 27.0), WordPress app, trunk vs this PR: self-hosted sign-in (see above); signing in to WordPress.com from the simplified UI switches to static screens (Reader poster); site creation with an existing site shows the Jetpack overlay
  • Simulator, WordPress app with a WordPress.com account that has no sites: "Create WordPress.com site" opens the site creation wizard, not the Jetpack overlay. Same as trunk.
  • Simulator, Jetpack app: self-hosted sign-in gives the normal UI (no Jetpack card or overlay); after WordPress.com sign-in the Reader is the real Reader, not a poster; site creation with existing sites opens the wizard. Same as trunk.
Trunk vs this PR: no-sites site creation and the Jetpack app (pixel-identical below the status bar)
Trunk #26280
WordPress app, WordPress.com account with no sites Trunk: WordPress app, WordPress.com account with no sites #26280: WordPress app, WordPress.com account with no sites
…then Create WordPress.com site Trunk: …then Create WordPress.com site #26280: …then Create WordPress.com site
Jetpack app, self-hosted sign-in Trunk: Jetpack app, self-hosted sign-in #26280: Jetpack app, self-hosted sign-in
Jetpack app, Reader after WordPress.com sign-in Trunk: Jetpack app, Reader after WordPress.com sign-in #26280: Jetpack app, Reader after WordPress.com sign-in
Jetpack app, site creation with sites Trunk: Jetpack app, site creation with sites #26280: Jetpack app, site creation with sites

The no-sites account is the real test account behind a local proxy that answers me/sites with an empty list. The Reader screenshots are cropped to hide followed P2 names.

@jkmassel jkmassel self-assigned this Oct 29, 2026
@jkmassel jkmassel added this to the 27.5 milestone Oct 29, 2026
@dangermattic

dangermattic commented Oct 29, 2026 •

Copy link
Copy Markdown
Collaborator
1 Warning
⚠️ This PR is larger than 500 lines of changes. Please consider splitting it into smaller PRs for easier and faster reviews.

Generated by 🚫 Danger

@jkmassel
jkmassel marked this pull request as ready for review October 29, 2026 04:26
@jkmassel
jkmassel requested a review from crazytonyli October 29, 2026 04:26
@jkmassel
jkmassel added this pull request to stack #26292 October 29, 2026 04:27
@crazytonyli
crazytonyli self-requested a review October 29, 2026 20:43
@crazytonyli

Copy link
Copy Markdown
Contributor

@jkmassel There are conflicts in this PR.

Formatting only, so the follow-up change has a readable diff.
The server returns the same values for these eight flags to every app
version, so the app now hard-codes the phase they produce:

- WordPress app with a WordPress.com account: static screens
- WordPress app without one: simplified UI
- Any other app: normal

Site creation follows the same pattern, and the duplicate-notifications
check is always on, matching its server value and app default.
The phase no longer falls back to normal when no flag has been
fetched, so tests that never set up the root view would see
whichever phase their account state implies. Pin the test host to
the normal UI type, and restore the value RootViewCoordinatorTests
changes.
@jkmassel
jkmassel force-pushed the jkmassel/remove-jetpack-removal-flags branch from 1bd97ca to 9dd247c Compare October 29, 2026 20:55
@jkmassel
jkmassel enabled stacked auto-merge October 29, 2026 21:27
@jkmassel
jkmassel added this pull request to the merge queue Oct 29, 2026
Merged via the queue into trunk with commit e46888f Oct 29, 2026
22 checks passed
@jkmassel
jkmassel deleted the jkmassel/remove-jetpack-removal-flags branch October 29, 2026 23:07
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.

3 participants