Skip to content

Turn the Pro badge on when an account gets its first ever proof - #787

Open
mpretty-cyro wants to merge 1 commit into
session-foundation:devfrom
mpretty-cyro:fix/pro-badge-on-first-proof
Open

mpretty-cyro wants to merge 1 commit into
session-foundation:devfrom
mpretty-cyro:fix/pro-badge-on-first-proof

Conversation

@mpretty-cyro

Copy link
Copy Markdown
Collaborator

The Pro badge is off by default, so a new subscriber had to find the toggle in Pro settings before anyone could tell they had subscribed. Desktop has done this since 266ac2c9e ("setProBadge on when recovering pro without swarm config"); this is the same behaviour on iOS, client-side only.

The guard is "has this account ever held Pro", not "does it hold Pro now"

The obvious reading — enable the badge whenever Pro becomes active — is wrong in a way that is easy to ship and annoying to diagnose: a subscriber who deliberately turns the badge off has it turned back on at every proof renewal, with no way to make the choice stick. Being visible as a subscriber is the user's call, which is why the badge is off by default in the first place.

So the condition is all three of proConfig, proAccessExpiry and the profile-feature bitset being absent, matching Desktop. proAccessExpiry is the value doing the real work: a lapsed plan has its proof cleared but keeps its expiry, so that expiry is what separates a returning subscriber from a first-time one.

hasNeverHeldPro is read inside the same mutate(cache:) that writes the proof and the expiry, and before either of them — two of the three values it asks about are things that write is about to change.

The badge write

applyProofSuccess already ended with Profile.updateLocal(proFeatures:); it now passes .inserting(.proBadge) on a first-ever proof. That is the same route the Pro settings toggle uses (Profile.updateLocalProfile.updateIfNeededcache.updateProfileuser_profile_set_pro_badge), so there is no second writer for the badge and no new cache API.

A linked device is unaffected — it takes the badge from the user-profile config it merges, and that config's proof or expiry fails the guard in any case. A device that syncs a config with the badge off keeps it off.

Testing

ProBadgeFirstProofSpec — 4 tests, all passing, and proven to fail: forcing hasNeverHeldPro to true fails 3 of the 4 (a stored proof, a surviving access expiry, an existing profile feature). Those three are the regression.

SessionMessagingKitTests: 597 passed, 0 failed, 0 restarts — the 593 baseline plus these 4. Run through the Session scheme with -parallel-testing-enabled NO, since the SessionMessagingKit scheme can't resolve its WebRTC dependency.

One gap, stated rather than papered over: the spec covers the decision, not the call-site wiring. Network.SessionPro.GenerateProProofResponse has only init(parsing: Data) over raw backend bytes and there is no MockSessionProManager, so exercising applyProofSuccess end-to-end would mean crafting a signed backend response. The Android companion does cover placement, because there the badge write sits inside the tested seam.

Companion Android change: session-foundation/session-android#2214.

The badge is off by default, so a new subscriber had to find the toggle in Pro
settings before anyone could tell they had subscribed. Desktop has done this
since session-desktop 266ac2c9e; this is the same behaviour.

The condition is that config carries no proof, no access expiry and no profile
features - that this account has never held Pro - rather than that Pro is active
now. Enabling on "active" would turn the badge back on at every renewal for a
subscriber who had deliberately turned it off, and since a lapsed plan keeps its
access expiry after the proof is cleared, that expiry is what tells a returning
subscriber from a first-time one. It is read inside the same `mutate(cache:)`
that writes the proof and the expiry, and before either of them.

The badge itself goes through `Profile.updateLocal(proFeatures:)`, which the Pro
settings toggle already uses, so there is no second writer for it.

A linked device is unaffected: it takes the badge from the user profile config it
merges, and that config's proof or expiry fails the check in any case.

`ProBadgeFirstProofSpec` covers the check. It does not cover the call site:
`GenerateProProofResponse` can only be built by parsing raw backend bytes, and
there is still no `MockSessionProManager`.
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