Skip to content

refactor: move endpoint host resolution to Swift - #874

Merged
nickolas-dimitrakas merged 1 commit into
workstation/swift-migrationfrom
refactor/endpoint-host-resolution-to-swift
Sep 1, 2026
Merged

nickolas-dimitrakas merged 1 commit into
workstation/swift-migrationfrom
refactor/endpoint-host-resolution-to-swift

Conversation

@nickolas-dimitrakas

@nickolas-dimitrakas nickolas-dimitrakas commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

The stack

  1. refactor: move request signing to Swift #872 — request signing
  2. refactor: move URL request header assembly to Swift #873 — URL request headers
  3. refactor: move endpoint host resolution to Swift #874 — endpoint host resolution
  4. test: pin the exact endpoint URL strings before converting them #875 — endpoint URL characterization tests
  5. refactor: move endpoint path-style decisions to Swift #876 — endpoint path-style decisions

Review bottom-up; merge top-down. This is #874.


Third of five, stacked on the previous.

What moves

MPEndpointHostResolver owns two things:

  • defaultHost(subdomain:apiKey:) parses the pod prefix out of the API key. A key with
    no hyphen, an empty key and a nil key all route to us1, matching
    componentsSeparatedByString: on nil returning nil and the original count <= 1 test.
  • resolvedHost(...) is the one precedence ladder behind all five endpoint families:
    customBaseURL host, then the tracking host when ATT is authorized, then the configured
    host, then the default. Config and audience pass a nil tracking host, which is what the
    ObjC did by having no tracking branch at all.

The .m keeps every read of MPStateMachine, MPNetworkOptions and MPUploadSettings,
and every MPILogWarning, at the same call sites with the same text. A new private
-attAuthorized collapses the four copies of the ATT comparison; it is not declared in any
header.

Two behaviours worth naming, both preserved

  • An empty-string host overrides the default rather than falling through, because
    ObjC's ?: treats @"" as a live object. Covered by a test so a future Swift rewrite
    cannot quietly "fix" it.
  • The audience endpoint ignores eventsTrackingHost entirely, unlike events — it only
    picks up the tracking subdomain indirectly through defaultEventHost. Reproduced, not
    corrected.

self.defaultEventHost / defaultIdentityHost are now evaluated eagerly as the
defaultHost: argument instead of behind ?:. Both are pure functions of the ATT status
and API key, and both were already called unconditionally on the following line to build
defaultURL, so nothing observable changes.

The alias endpoint's eventsOnly fallback stays a plain ?: — a two-way default with no
tracking or custom host, where the resolver would only add noise.

Gate

Item Result
1. Zero public-ABI diff pass — abi-guard.sh check clean, Include/ diff empty
2. pod lib lint x3 podspecs iOS pass; tvOS not runnable locally
3. Build iOS + tvOS iOS pass, no new warnings; tvOS not runnable locally
4. trunk check pass — no new issues
5. ObjC + Swift suites pass — ObjC 982/982, Swift 405/405 (13 new here)

The first build of this slice left two unused variable 'stateMachine' warnings behind in
identityURL: and modifyURL; both locals are gone and the build is warning-clean.

tvOS and test-flakiness caveats as in the first PR of the stack.

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Aug 27, 2026

Copy link
Copy Markdown

🐦 Swift Migration Progress

Production implementation code at 14996c65bf2f compared with edb9962d4228.

Area Goal Progress Base This PR Swift SLOC Objective-C remaining Change
Core SDK Short term — in scope ████▎░░░░░ 42.85% 42.99% 6,294 8,346 🚀 +0.14 pp
Core SDK Long term — all Objective-C ███▏░░░░░░ 30.60% 30.71% 6,294 14,201 🚀 +0.11 pp
SDK kit infrastructure Short term — in scope ░░░░░░░░░░ 0.00% 0.00% 0 3,340 ➖ 0.00 pp
SDK kit infrastructure Long term — all Objective-C ░░░░░░░░░░ 0.00% 0.00% 0 3,725 ➖ 0.00 pp
Standalone kits Short term — in scope ▏░░░░░░░░░ 1.06% 1.06% 152 14,231 ➖ 0.00 pp
Standalone kits Long term — all Objective-C ▏░░░░░░░░░ 1.06% 1.06% 152 14,231 ➖ 0.00 pp

Objective-C retained by design: Core SDK 5,855 · SDK kit infrastructure 385 · Standalone kits 0.

This PR's code movement

Area Swift lines added Objective-C lines removed
Core SDK 29 60
SDK kit infrastructure 0 0
Standalone kits 0 0
How this is measured
  • Current composition uses production source lines of code (SLOC) from cloc; comments and blank lines are excluded.
  • Short term — in scope excludes the Objective-C the migration will not delete, so 100% is the end of this project: every in-scope implementation gone.
  • Long term — all Objective-C keeps the full denominator. Reaching 100% there means the public API itself becomes Swift, which is a breaking change reserved for a future major release.
  • The gap between the two rows is the retained public/kit contract, runtime-identity, and boundary-glue surface listed in Tools/swift-migration-retained-objc.txt.
  • Retained wrappers keep their Objective-C interface but still shed logic to Swift. That thinning moves the long-term row and the retained figure, not the short-term row.
  • Both revisions are measured with the manifest from the head revision, so a manifest edit does not by itself move the reported change. A retained file this pull request renamed or deleted still counts as retained at the base.
  • Pull request movement uses physical additions/deletions from git diff base...head --numstat; it counts retained files too and is intentionally separate from SLOC totals.
  • Core excludes SDK kit infrastructure and vendored libraries. Standalone kits include only files below Kits/**/Sources.
  • Tests, examples, headers, build outputs, vendored libraries, and the MParticle/Sources Swift overlay are excluded.
  • Objective-C++ (.mm) is included in the Objective-C figures and removed counts.

Generated with cloc 2.10. This report is informational and does not gate migration direction.

@github-actions

github-actions Bot commented Aug 27, 2026

Copy link
Copy Markdown

📦 SDK Size Impact Report

Measures how much the SDK adds to an app's size (with-SDK minus without-SDK).

Metric Target Branch This PR Change
App Bundle Impact 2.18 MB 2.18 MB +N/A
Executable Impact 848 bytes 848 bytes +N/A
XCFramework Size 6.69 MB 6.69 MB +N/A

➡️ SDK size impact change is minimal.

Raw measurements

Target branch (workstation/swift-migration):

{"baseline_app_size_kb":84,"baseline_executable_size_bytes":75464,"with_sdk_app_size_kb":2320,"with_sdk_executable_size_bytes":76312,"sdk_impact_kb":2236,"sdk_executable_impact_bytes":848,"xcframework_size_kb":6852}

This PR:

{"baseline_app_size_kb":84,"baseline_executable_size_bytes":75464,"with_sdk_app_size_kb":2320,"with_sdk_executable_size_bytes":76312,"sdk_impact_kb":2236,"sdk_executable_impact_bytes":848,"xcframework_size_kb":6852}

@nickolas-dimitrakas
nickolas-dimitrakas force-pushed the refactor/endpoint-host-resolution-to-swift branch from ef35d35 to ebca24b Compare August 31, 2026 20:38
@nickolas-dimitrakas
nickolas-dimitrakas force-pushed the refactor/endpoint-host-resolution-to-swift branch from ebca24b to fa85a2f Compare September 1, 2026 15:00
@nickolas-dimitrakas
nickolas-dimitrakas marked this pull request as ready for review September 1, 2026 15:02
@nickolas-dimitrakas
nickolas-dimitrakas requested a review from a team as a code owner September 1, 2026 15:02
@cursor

cursor Bot commented Sep 1, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Changes which backend hostnames the SDK uses for config, events, identity, and related uploads; mistakes would misroute traffic or break ATT-gated tracking endpoints, though the PR is intended as behavior-preserving with broad test coverage.

Overview
Endpoint host selection is centralized in a new Swift MPEndpointHostResolver, and MPNetworkCommunication delegates to it instead of duplicating inline precedence logic.

defaultHost(subdomain:apiKey:) builds pod-based default hostnames from the API key prefix (falling back to us1). resolvedHost(...) applies one shared ladder everywhere it’s wired: custom base URL host, then tracking host when ATT is authorized, then configured host, then default. Config and audience pass a nil tracking host, matching prior ObjC behavior.

ObjC still owns warnings, network options, and upload settings at each call site; a private -attAuthorized replaces repeated ATT checks for default event/identity subdomains and resolver calls. New Swift unit tests lock in pod routing, precedence, and legacy quirks such as empty-string hosts not falling through to the default.

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

@nickolas-dimitrakas
nickolas-dimitrakas force-pushed the refactor/endpoint-host-resolution-to-swift branch from fa85a2f to 3881dd5 Compare September 1, 2026 15:09
Base automatically changed from refactor/url-request-headers-to-swift to workstation/swift-migration September 1, 2026 15:22
Extracts pod routing and the host precedence ladder from
MPNetworkCommunication into a Foundation-only Swift type, per
docs/swift-migration/CONVERSION-RECIPE.md.

MPEndpointHostResolver owns two things:

- defaultHost(subdomain:apiKey:) parses the pod prefix out of the API
  key. A key with no hyphen, an empty key and a nil key all route to
  us1, matching componentsSeparatedByString: on nil returning nil and
  the original `count <= 1` test.
- resolvedHost(...) is the one precedence ladder behind all five
  endpoint families: customBaseURL host, then the tracking host when ATT
  is authorized, then the configured host, then the default. Config and
  audience pass a nil tracking host, which is what the ObjC did by
  having no tracking branch at all.

The .m keeps every read of MPStateMachine, MPNetworkOptions and
MPUploadSettings, and every MPILogWarning, at the same call sites and
with the same text. A new private -attAuthorized collapses the four
copies of the ATT comparison; it is not declared in any header.

Two behaviours worth naming, both preserved:

- An empty-string host overrides the default rather than falling
  through, because ObjC's ?: treats @"" as a live object. Covered by a
  test so a future Swift rewrite cannot quietly "fix" it.
- The audience endpoint ignores eventsTrackingHost entirely, unlike the
  events endpoint. That asymmetry is reproduced, not corrected.

self.defaultEventHost / defaultIdentityHost are now evaluated eagerly as
the defaultHost: argument instead of behind ?:. Both are pure functions
of the ATT status and API key, and both were already called
unconditionally on the following line to build defaultURL, so nothing
observable changes.

The alias endpoint's eventsOnly fallback stays a plain ?: -- it is a
two-way default with no tracking or custom host, and the resolver would
only add noise there.

Include/ has a zero diff and abi-guard.sh check passes; the new resolver
is not an exported declaration.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@nickolas-dimitrakas
nickolas-dimitrakas force-pushed the refactor/endpoint-host-resolution-to-swift branch from 3881dd5 to 14996c6 Compare September 1, 2026 15:22
@nickolas-dimitrakas
nickolas-dimitrakas merged commit fdff960 into workstation/swift-migration Sep 1, 2026
3 checks passed
@nickolas-dimitrakas
nickolas-dimitrakas deleted the refactor/endpoint-host-resolution-to-swift branch September 1, 2026 15:25
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.

3 participants