Skip to content

fix(wallet): drop a dead socket instead of asking it to close, and make the hand-off measurable - #38

Merged
ehsan6sha merged 1 commit into
mainfrom
wallet/diagnostics-and-fast-reconnect
Sep 4, 2026
Merged

fix(wallet): drop a dead socket instead of asking it to close, and make the hand-off measurable#38
ehsan6sha merged 1 commit into
mainfrom
wallet/diagnostics-and-fast-reconnect

Conversation

@ehsan6sha

Copy link
Copy Markdown
Member

The reporter still sees about five seconds of Connecting Wallet… after approving in MetaMask, with #36 deployed. Two things in response.

1. The reconnect no longer waits for a dead socket to say goodbye

#36 replaced a socket that only claimed to be OPEN by calling restartTransport(). Read further, that is the polite path: resetTransporttransportDisconnectprovider.disconnect() under a 2 s timeout — two seconds spent waiting for a close handshake that a TCP connection Android suspended will never complete, before a single byte of the reconnect is sent.

The relayer has a faster path, and it is the one it takes when a socket's close event fires on its own: onProviderDisconnect() — stop the subscriber and dial a fresh socket 100 ms later. The dead socket is abandoned rather than closed; createProvider() detaches its listeners first, so its eventual close reaches nobody. That is the truthful treatment of a socket that is, in fact, gone. The polite restart stays as the fallback if the fresh socket is not up within WAKE_TIMEOUT_MS, and the log says which path ran.

Checked while here: batchFetchMessages, with its 1 s sleep, has no call site in the shipped core. The relay pushes queued messages on irn_batchSubscribe, so nothing else on the path waits on purpose.

2. The hand-off is now measurable from the phone

Every theory about the delay and the splash-screen hang so far has been argued from code reading, because the only evidence was console.log on a phone nobody had a debugger attached to. wallet/diag.ts routes the same lines into the clientLogger ring buffer, timestamped "+N ms since return" — the moment every one of those seconds is counted from — and the debug-mode banner now shares that buffer (plus the build sha) with one tap.

Logged: tab hidden/visible with the hidden duration and whether a relay provider was even present; which reconnect path ran and how long it took; every AppKit connected/connecting/account/provider flip; on the sign tap, the relay state, the stored deep-link choice and Chrome's user-activation flag; when the request reached the relay; the exact URL of each hop and the activation flag at that moment; when the signature arrived. Always on — the ring is 500 lines in memory — so the one report that matters is not taken with it off.

How to capture a report

  1. Enable debug mode (Settings → Mode → Debug, or press and hold the Welcome picture for 3 s). A yellow banner appears at the top.
  2. Reproduce: connect, come back, tap Sign with Wallet, come back.
  3. Tap the banner → share/copy → paste.

Testing

  • npm test --workspaces — 951 passing, no unhandled errors. New: fast path preferred when onProviderDisconnect exists and the fresh socket comes up; polite restart as fallback when it does not; polite restart when the fast path is absent.
  • npm run typecheck --workspaces, npm run lint clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_013BpqXrkEPA9odTyRdK5Mnx

…ke the hand-off measurable

The reporter still sees about five seconds of "Connecting Wallet..." after
approving in MetaMask, with #36 deployed. Two things in response.

1. The reconnect no longer waits for a dead socket to say goodbye.

   #36 replaced a socket that only claimed to be OPEN by calling
   `restartTransport()`. Read further, that is the polite path: `resetTransport`
   -> `transportDisconnect` -> `provider.disconnect()` under a 2 s timeout --
   two seconds spent waiting for a close handshake that a TCP connection Android
   suspended will never complete, before a single byte of the reconnect is sent.

   The relayer has a faster path, and it is the one IT takes when a socket's
   `close` event fires on its own: `onProviderDisconnect()` -- stop the
   subscriber and dial a FRESH socket 100 ms later. The dead socket is abandoned
   rather than closed; `createProvider()` detaches its listeners first, so its
   eventual close reaches nobody. That is the truthful treatment of a socket
   that is, in fact, gone. The polite restart stays as the fallback if the fresh
   socket is not up within WAKE_TIMEOUT_MS, and the log says which path ran.

   (Checked while here: `batchFetchMessages`, with its 1 s sleep, has no call
   site in the shipped core. The relay pushes queued messages on
   `irn_batchSubscribe`, so nothing else on the path waits on purpose.)

2. The hand-off is now measurable from the phone.

   Every theory about the delay and the splash-screen hang has been argued from
   code reading, because the only evidence was console.log on a phone nobody had
   a debugger on. `wallet/diag.ts` routes the same lines into the clientLogger
   ring buffer, timestamped "+Nms since return" -- the moment every one of those
   seconds is counted from -- and the debug-mode banner now shares the buffer
   (plus the build sha) with one tap. Logged: tab hidden/visible with the hidden
   duration and whether a relay provider was even present; which reconnect path
   ran and how long it took; every AppKit connected/connecting/account/provider
   flip; on the sign tap, the relay state, the stored deep-link choice and
   Chrome's user-activation flag; when the request reached the relay; the exact
   URL of each hop and the activation flag at that moment; when the signature
   arrived. Always on -- the ring is 500 lines in memory -- so the one report
   that matters is not taken with it off.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013BpqXrkEPA9odTyRdK5Mnx
@ehsan6sha
ehsan6sha merged commit 7187fba into main Sep 4, 2026
2 checks passed
@ehsan6sha
ehsan6sha deleted the wallet/diagnostics-and-fast-reconnect branch September 4, 2026 23:08
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