Skip to content

Analytics: Snapshot the site into a value type at the tracking boundary - #25883

Open
jkmassel wants to merge 1 commit into
cmm-2213-my-site-dashboard-card-impressions-on-android-carry-nofrom
jkmassel/analytics-module-split
Open

Analytics: Snapshot the site into a value type at the tracking boundary#25883
jkmassel wants to merge 1 commit into
cmm-2213-my-site-dashboard-card-impressions-on-android-carry-nofrom
jkmassel/analytics-module-split

Conversation

@jkmassel

@jkmassel jkmassel commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Building on #25882, this replaces the raw Core Data Blog at the analytics boundary with a Sendable value-type snapshot, so tracking never reads a managed object off its context's queue. It's the load-bearing first step toward extracting analytics into a module that takes no Core Data types.

Summary

  • New BlogAnalyticsProperties value type + BlogAnalyticsRepresentable protocol in WordPressShared.
  • Blog conforms in WordPressData, snapshotting on its context queue.
  • The two site-attaching track boundaries read from the snapshot, not the live Blog.
  • No call-site changes — Blog conforms, so existing track(…, blog:) calls compile unchanged.

Root cause

WPAnalytics.track(_:properties:blog:) read blog.dotComID and blog.isWPForTeams synchronously, on whatever thread the caller was on. Both are Core Data accesses:

  • Blog.dotComID's getter can write back to the object — it back-fills blogID from jetpack.siteID.
  • isWPForTeams faults the options relationship.

Reading either off the object's context queue is a threading violation. AnalyticsTrackerAutomatticTracks.getSessionInfo already wraps its Blog reads in context.performAndWait — the per-event path was the one place that didn't.

Changes

1. BlogAnalyticsProperties + BlogAnalyticsRepresentable (WordPressShared)

A Sendable struct carrying the two facts analytics needs — dotComID and isWPForTeams — and a protocol that vends it. Only this value crosses the model boundary.

2. Blog: BlogAnalyticsRepresentable (WordPressData)

analyticsProperties reads the two fields inside managedObjectContext.performAndWait, so the snapshot is safe to hand to analytics from any thread. Conformance lives with the model — not retroactive.

3. Boundary functions read the snapshot (app target)

  • WPAnalyticsEvent.swift: split into a value-type core track(_:properties:blogProperties:) and a track(_:properties:blog: some BlogAnalyticsRepresentable) convenience that snapshots. The @objc trackEvent(…blog: Blog) and trackBlockEditorEvent forward through it, unchanged.
  • WPAppAnalytics+Extensions.swift: track(_:properties:blog:) reads blog.analyticsProperties instead of touching dotComID / siteType(for:) directly.

Not in this PR

  • The module. This is the boundary type. Moving WPAnalyticsEvent, BlogDashboardAnalytics, and the trackers into a standalone WordPressAnalytics package (depends on WordPressShared, not WordPressData) is the follow-up — now unblocked, because the per-event Core Data dependency is severed. AnalyticsTrackerAutomatticTracks stays app-side (it's injected via registerTracker), so the module won't need Blog.count(in:) / hasAnyJetpackBlogs.
  • The domains and post paths. WPAnalytics.domainsProperties(for: blog) (reads canRegisterDomainWithPaidPlan) and WPAppAnalytics.track(_:properties:post:) still take Core Data types. Same treatment, separate PRs.

Test plan

Related

@jkmassel jkmassel self-assigned this Aug 8, 2026
@jkmassel jkmassel added this to the 27.2 milestone Aug 8, 2026
@wpmobilebot

wpmobilebot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor
App Icon📲 You can test the changes from this Pull Request in WordPress by scanning the QR code below to install the corresponding build.
App NameWordPress
ConfigurationRelease-Alpha
Build Number33662
VersionPR #25883
Bundle IDorg.wordpress.alpha
Commitee53c23
Installation URL39if862uaihlo
Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.

@wpmobilebot

wpmobilebot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor
App Icon📲 You can test the changes from this Pull Request in Jetpack by scanning the QR code below to install the corresponding build.
App NameJetpack
ConfigurationRelease-Alpha
Build Number33662
VersionPR #25883
Bundle IDcom.jetpack.alpha
Commitee53c23
Installation URL6pl3gu62dvc28
Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.

@jkmassel
jkmassel force-pushed the jkmassel/analytics-module-split branch from 09e4a74 to 90e0d43 Compare August 8, 2026 01:08
Introduce BlogAnalyticsProperties (Sendable) and BlogAnalyticsRepresentable in
WordPressShared, conform Blog in WordPressData, and read the snapshot in the two
site-attaching track() paths instead of the live managed object.

Reading blog.dotComID / blog.isWPForTeams off the object's context queue is a
Core Data threading violation: dotComID's getter can write back to the object,
and isWPForTeams faults the options relationship. Blog.analyticsProperties takes
the snapshot on the object's context queue, so only a Sendable value crosses into
analytics. Existing track(..., blog:) call sites compile unchanged because Blog
conforms to the protocol.

This is the boundary type that unblocks moving analytics into a module that takes
no Core Data types.
@jkmassel
jkmassel force-pushed the jkmassel/analytics-module-split branch from 90e0d43 to ee53c23 Compare August 8, 2026 01:31
@wpmobilebot

Copy link
Copy Markdown
Contributor

🤖 Build Failure Analysis

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

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.

2 participants