Skip to content

fix(session): keep feature-flag-derived state across logout - #1162

Merged
bmc08gt merged 1 commit into
code/cashfrom
fix/tipping-tab-logout-desync
Jul 27, 2026
Merged

fix(session): keep feature-flag-derived state across logout#1162
bmc08gt merged 1 commit into
code/cashfrom
fix/tipping-tab-logout-desync

Conversation

@bmc08gt

@bmc08gt bmc08gt commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Problem

Log out of an account with the Tipping beta flag on, log into another account, and you end up in a contradictory state: the beta flag is still on, but the scanner Tips tab is gone — and stays gone.

Root cause

SessionState.isTippingEnabled (and vibrateOnScan / showNetworkOffline) are fed only by featureFlagController.observe(flag) — hot StateFlows that dedup and re-emit only on a value change.

On logout (AuthState.LoggedOut in RealSessionController), stateHolder.reset() did a blanket _state.value = SessionState(), forcing isTippingEnabled = false. Because the observer's value was unchanged (the beta-flags store is device-level and shared across accounts, so tipping_enabled stays true), it never re-pushed to repopulate the field. isTippingEnabled was stuck at the reset default, so the scanner hid the Tips tab even though the flag was still enabled — a permanent desync until the flag value actually changed.

Fix

SessionStateHolder.reset() now clears only account-scoped state and preserves the device-scoped, feature-flag-derived fields (isTippingEnabled, vibrateOnScan, showNetworkOffline), letting observe(flag) remain their single source of truth:

  • If the flag genuinely clears, the observer emits false and the field follows.
  • If the flag persists, the field stays consistent with it.

Either way SessionState can no longer desync from the flag. Account/token/settings-derived fields (isPhoneNumberSendEnabled, hasGiveableBalance, autoStartCamera, …) still reset — their sources re-emit on account switch and self-heal.

Tests

SessionStateHolderTest: split the old reset test into reset clears account-scoped state, and added reset preserves device-scoped feature-flag state. All passing.

Note

Distinct root cause from #1157 (that fixes the persisted nav-bar order lacking Tips). This one fixes session state desyncing from the flag on logout. The two together cover both ways the Tips tab could fail to appear.

SessionState.isTippingEnabled (and vibrateOnScan / showNetworkOffline) are
fed only by featureFlagController.observe(flag) — hot StateFlows that dedup
and re-emit only on a value change. On logout, stateHolder.reset() blanket-
reset SessionState() to defaults, forcing these to false. The observer never
re-pushes its unchanged value, so the field stayed stuck at the default even
though the underlying flag was still enabled.

Result: log out with tipping on, log into another account, and the beta flag
is still on but the scanner Tips tab is gone — SessionState desynced from the
flag.

reset() now clears only account-scoped state and preserves the device-scoped,
feature-flag-derived fields, letting observe(flag) remain their single source
of truth. Account/token/settings-derived fields still reset; their sources
re-emit on account switch and self-heal.
@bmc08gt bmc08gt self-assigned this Jul 27, 2026
@bmc08gt
bmc08gt merged commit 0091d63 into code/cash Jul 27, 2026
3 checks passed
@bmc08gt
bmc08gt deleted the fix/tipping-tab-logout-desync branch July 27, 2026 18:28
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.

1 participant