Skip to content

fix: [SDK-5606] send full email and SMS fields on composite login - #2815

Open
abdulraqeeb33 wants to merge 2 commits into
mainfrom
ar/sdk-5606
Open

abdulraqeeb33 wants to merge 2 commits into
mainfrom
ar/sdk-5606

Conversation

@abdulraqeeb33

@abdulraqeeb33 abdulraqeeb33 commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Description

One Line Summary

Composite login email and SMS subscriptions now include the same device fields as addEmail and addSms, without a subscription status, and the identity-verification warning is gone.

Details

Motivation

Fixes SDK-5606. Found in the 5.11.0 bug bash. Profile subscriptions were sent as type and token only, so the backend stored empty device fields. A successful composite login also logged a warning about identity verification that addEmail never logs.

enabled and notification_types are deliberately not sent. Create User applies them to an email or SMS that already exists (on this user or moved from another), so sending "subscribed" would re-subscribe someone who unsubscribed, on every composite login. Add Subscription, which addEmail uses, ignores status for an existing address, so it never does this.

The cost: a new address created through composite login is still stored as notification_types: -99 until the backend changes Create User to default a new email or SMS with no status to subscribed, and to apply status only on create. No SDK release is needed once that ships.

Scope

Create User payloads for an email or SMS that comes from the login profile. A grouped subscription operation that already has that token is unchanged. Identity-only login(externalId) is unchanged. Composite login still does not identify the anonymous user.

Testing

Unit testing

LoginUserOperationExecutorTests email-only and SMS-only cases assert that enabled and notification_types are absent and that the SDK version and device fields are present and non-null (except carrier, which is null under Robolectric). Putting the status back makes both tests fail. Assertions run after coVerify so they don't call a mocked AndroidUtils during verification.

Manual testing

Replayed the Create User and Add Subscription requests against the demo app for email and SMS. On an emulator, the previous commit's request matched the "status sent" replay; this PR's payload is the same minus the two status fields.

Case addEmail / addSms Composite, status sent Composite, this PR
New address 1 1 -99 (needs backend change)
Existing address, unsubscribed (-2) stays -2 re-subscribed to 1 stays -2
Address moved from another user, -2 stays -2 re-subscribed to 1 stays -2

Affected code checklist

  • Notifications
    • Display
    • Open
    • Push Processing
    • Confirm Deliveries
  • Outcomes
  • Sessions
  • In-App Messaging
  • REST API requests
  • Public API changes

Checklist

Overview

  • I have filled out all REQUIRED sections above
  • PR does one thing
  • Any Public API changes are explained in the PR details and conform to existing APIs

Testing

  • I have included test coverage for these changes, or explained why they are not needed
  • All automated tests pass, or I explained why that is not possible
  • I have personally tested this on my device, or explained why that is not possible

Final pass

  • Code is as readable as possible.
  • I have reviewed this PR myself, ensuring it meets each checklist item

Made with Cursor

Profile subscriptions were only type and token, so the backend stored notification_types -99. Match CreateSubscriptionOperation and drop the identity-verification warning.

Co-authored-by: Cursor <cursoragent@cursor.com>
@abdulraqeeb33
abdulraqeeb33 requested a review from a team October 26, 2026 19:19
@fadi-george

Copy link
Copy Markdown
Contributor

Fix CI.

subscriptions = LoginProfileApplier.addSubscriptions(createUserOperation, subscriptions)
subscriptions =
LoginProfileApplier.addSubscriptions(createUserOperation, subscriptions) { type, token ->
subscriptionWithDevice(type, token, enabled = true, notificationTypes = SubscriptionStatus.SUBSCRIBED.value)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking: for an email/SMS that already exists, Create User applies these fields as updates (turbine users/create/create.go calls UpdateAsync, and event_capnp.go sets notification_types whenever it's present). So someone who unsubscribed via the email link (-2) gets flipped back to 1 on the next composite login, and again on every login after.

addEmail doesn't hit this because create-subscription returns 200/202 for an existing sub without updating it.

Could we leave enabled/notification_types unset here and only send the device fields? New addresses would still land at -99 though, so fully fixing that probably needs Create User to only apply status on create.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both fixed in e5ba296.

  1. Dropped enabled/notification_types for profile email/SMS. Device fields still sent. Backend ticket for status-on-create-only is next.
  2. Added non-null checks (except carrier, which is null under Robolectric) and moved assertions out of withArg.

Comment on lines +1097 to +1099
sub.netType shouldBe DeviceUtils.getNetType(context)
sub.carrier shouldBe DeviceUtils.getCarrierName(context)
sub.appVersion shouldBe AndroidUtils.getAppVersion(context)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: these compare against the same helpers the code calls, so if they return null under Robolectric, a field that's never set still passes. Maybe add a non-null check where there's a real value.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in e5ba296.

@fadi-george fadi-george left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes for the resubscribe issue on LoginUserOperationExecutor.kt:214 (see inline comment).

… SMS

Create User applies enabled/notification_types to an existing address,
which would re-subscribe a user who unsubscribed. Device fields are still sent.

Also moves the test assertions out of withArg so they don't call a mocked
AndroidUtils during verification, and suppresses TooManyFunctions.

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions

Copy link
Copy Markdown
Contributor

📊 Diff Coverage Report

Diff Coverage Report (Changed Lines Only)

Gate: aggregate coverage on changed executable lines must be ≥ 80% (JaCoCo line data for lines touched in the diff).

Changed Files Coverage

  • LoginProfileApplier.kt: 2/2 touched executable lines (100.0%) (3 touched lines in diff)
  • LoginUserOperationExecutor.kt: 24/24 touched executable lines (100.0%) (30 touched lines in diff)

Overall (aggregate gate)

26/26 touched executable lines covered (100.0% — requires ≥ 80%)

📥 View workflow run

@abdulraqeeb33
abdulraqeeb33 requested review from a team, fadi-george and nan-li October 26, 2026 21:52
@abdulraqeeb33

Copy link
Copy Markdown
Contributor Author

@fadi-george addressed in e5ba296, CI is green. Could you take another look?

  1. Composite login no longer sends enabled/notification_types for profile email/SMS, so no resubscribe. New addresses stay at -99 until Create User applies status only on create.
  2. Same resubscribe already happens when addEmail is queued with login (grouped into Create User). Reproduced offline on an emulator. The backend fix covers both.

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.

2 participants