Pro: turn the badge on when an account gets its first ever proof - #2214
Open
mpretty-cyro wants to merge 1 commit into
Open
mpretty-cyro wants to merge 1 commit into
mpretty-cyro wants to merge 1 commit into
Conversation
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. 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. The proof write moves to ProProofGenerationWorker.storeProof so a test can drive it - doWork() is unreachable from a JVM unit test because ED25519 loads the native library.
Bilb
approved these changes
Sep 15, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 Android, 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,proAccessExpiryand the profile-feature bitset being absent, matching Desktop.proAccessExpiryis 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.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.
Why the proof write moved
storeProofis extracted so a test can drive it.doWork()itself is unreachable from a JVM unit test: it callsED25519, anexternalobject whose class initialiser loads libsession's native library. The ordering constraint is now stated at both ends — the guard reads the access expiry, so it has to run before the response's expiry is written.Testing
ProBadgeFirstProofTest— 5 tests, all passing, and proven to fail: replacing the guard with an unconditionalsetProBadge(true)fails 3 of the 5 (the renewing subscriber, the lapsed subscriber, and the account whose config already carries a profile feature). Those three are the regression.Full unit suite: 303 tests, 0 failures (
:app:testPlayDebugUnitTest) — the 298 baseline plus these 5.Companion iOS change: session-foundation/session-ios
fix/pro-badge-on-first-proof.