Skip to content

fix(js): treat session notifications as hints, read the daemon's state - #29675

Merged
chrisnojima merged 5 commits into
nojima/HOTPOT-js-04-httpsrvfrom
nojima/HOTPOT-js-05-session
Sep 23, 2026
Merged

chrisnojima merged 5 commits into
nojima/HOTPOT-js-04-httpsrvfrom
nojima/HOTPOT-js-05-session

Conversation

@chrisnojima

Copy link
Copy Markdown
Contributor

Stack 3/7 on #29650.

Why

  • Session notifications can arrive out of order. The notify router sends each notification on its own goroutine (test(libkb): failing tests for notify router ordering and teardown #29666), so loggedOut and loggedIn from a quick logout and login, or from an account switch, can reach JS reversed. Master's JS set loggedIn straight from them and could end up believing the older one.
  • A cancelled account switch strands the app. userSwitching stays set, so the logged-out status the switch withheld is never applied and the routers stay held.
  • Session re-reads hang off gregor reachability, a service stream JS used only for this.

What this changes

  • stores/daemon.tsx: each bootstrap-status read gets a sequence number, and only the reply to the latest read applies. refreshSessionFromDaemon(reason) starts a read that supersedes any read in flight.
  • Session notifications: NotifySession.loggedIn and loggedOut now only trigger refreshSessionFromDaemon. Nothing sets the session from a notification.
  • login and provisioning re-read the session when the RPC returns instead of calling setLoggedIn(true).
  • onBootstrapStatusChanged: a logged-in reply for a uid other than the one held logs the old account out first, then applies the reply to fresh stores. The userSwitching guard now runs before the identity is written.
  • Network status: going from offline to online triggers a re-read. JS no longer uses reachability, and the channels subscribe with reachability: false. checkReachability stays as nudgeGregor, because the call makes the service re-dial gregor.
  • httpSrv is kept across logout, because it belongs to the process rather than an account.

Judgment calls

  • loggedIn and loggedOut are hints that trigger a daemon re-read. A fresh login shows one getBootstrapStatus round trip later; a failed latest read changes nothing until the next hint, reconnect or online edge.
  • HTTPSrvInfoUpdate applies its address and token at once and does not re-read the session.
  • A cancelled switch clears userSwitching. That covers a cancelled login, including abandoning the new-device-name prompt, and any non-RPC error. When a switch ends, the current status is applied again, so the logged-out status it withheld takes effect.
  • Gregor reachability is no longer a re-read trigger. Re-reads come from the device's offline-to-online edge instead. A gregor drop and re-dial while the device stays online re-reads nothing.

Tests

  • stores/tests/daemon.test.ts: overlapping refreshes drop the older reply in either arrival order, a handshake read superseded by a refresh settles with the newer status, a failed refresh is logged, and handshakeGeneration survives resetState.
  • constants/init/shared.test.ts:
    • reversed hints end on the last reply
    • the cross-user reply logs out first
    • the same user, or no user yet, is not a switch
    • userSwitching gating
    • failed and cancelled switches end logged out
    • the offline-to-online cases
  • stores/tests/config.test.ts: httpSrv survives logout, and neither notifications nor login results set the session.

Each guard was mutation-checked.

…tate

loggedIn, loggedOut and HTTPSrvInfoUpdate are sent from separate goroutines
and can reach the GUI out of order, so none of them sets the session any
more. Each starts a fresh bootstrap-status read, and only the latest read's
reply applies; a superseded read settles with the newer one. The session is
also re-read after login RPCs return and when the network comes back.

A reply for a different user while logged in logs out first, clearing the
old account's stores. A logged-out reply during an account switch is still
ignored, and is applied once the switch ends.

Reachability tracking is dropped: the service is no longer asked to start
it or send its notifications; a network change still nudges gregor through
checkReachability. The http server address survives a logout.
A cancelled login (the PromptNewDeviceName hand-off, or a non-RPC error) left
userSwitching set, which withholds the logged-out session forever. Also drop
the bootstrap re-read on loggedIn: only a bootstrap reply sets it now.
The payload carries the address and token and the config store applies
it; only loggedIn/loggedOut are hints to re-read the daemon.
@chrisnojima
chrisnojima added this pull request to stack #29680 September 23, 2026 19:54
@chrisnojima
chrisnojima removed this pull request from stack #29680 September 23, 2026 19:56
@chrisnojima
chrisnojima added this pull request to stack #29681 September 23, 2026 19:56
@chrisnojima
chrisnojima merged commit 2f54486 into master Sep 23, 2026
1 check passed
@chrisnojima
chrisnojima deleted the nojima/HOTPOT-js-05-session branch September 23, 2026 20:53
chrisnojima added a commit that referenced this pull request Sep 24, 2026
…29683)

* fix(protocol): drop reachabilityChanged from enabled incoming calls

The JS side stopped handling it in #29675, but only the generated
index.tsx was edited, so CI's regen put the union member back.

* docs(claude): skip /code-review for trivial diffs
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.

1 participant