Skip to content

fix(android): wait for gateway connect before node events#79565

Closed
TurboTheTurtle wants to merge 3 commits into
openclaw:mainfrom
TurboTheTurtle:fix/android-node-event-handshake
Closed

fix(android): wait for gateway connect before node events#79565
TurboTheTurtle wants to merge 3 commits into
openclaw:mainfrom
TurboTheTurtle:fix/android-node-event-handshake

Conversation

@TurboTheTurtle

@TurboTheTurtle TurboTheTurtle commented May 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #79552.

Android now publishes GatewaySession.currentConnection only after the gateway connect RPC has completed, so reconnect-window callers cannot send node.event as the first websocket request before the handshake. Notification listener events that arrive while reconnect is still in flight are retained in a bounded queue and flushed once the node session reconnects.

Follow-up after review:

  • Connection.connect() now returns the parsed ready metadata instead of firing onConnected internally.
  • connectOnce() assigns currentConnection = conn before invoking onConnected, so NodeRuntime.flushPendingForwardedNodeEvents() runs only after the ready connection is visible to sendNodeEvent.

Real behavior proof

Behavior or issue addressed: notifications.changed must not be sent as node.event before the node gateway connection finishes the connect RPC, and queued notification events must flush only after the ready connection is visible.

Real environment tested: local OpenClaw checkout at f5fb8104d11a on macOS. Local Android test execution is blocked on this machine because no Java runtime is installed, so the Android unit test is expected to be verified by CI after this push.

Exact steps or command run after this patch: inspected and patched the real Android runtime path so GatewaySession.Connection.connect() completes handshake parsing, GatewaySession.connectOnce() publishes currentConnection, and only then invokes onConnected, which is the callback that starts notification queue flushing in NodeRuntime.

Evidence after fix:

Connection.connect() -> returns GatewayConnectionReadyInfo after connect RPC success
connectOnce() -> currentConnection = conn
connectOnce() -> onConnected(readyInfo.serverName, readyInfo.remoteAddress, readyInfo.mainSessionKey)
NodeRuntime.onConnected -> flushPendingForwardedNodeEvents()

Observed result after fix: the queue flush callback now happens after currentConnection is populated, so a retained notifications.changed event can be sent through the newly ready connection instead of being drained while sendNodeEvent still sees no connection.

What was not tested: I did not run a live Android device or local Robolectric shard on this Mac because Java is unavailable locally. CI should run android-test-play for the pushed head.

Before evidence: the previous PR head failed android-test-play on GatewaySessionInvokeTest > sendNodeEventDetailed_doesNotSendBeforeConnectHandshakeCompletes, matching the review finding that the queue could flush while currentConnection was still null.

Validation

  • git diff --check
  • Attempted ./gradlew :app:testPlayDebugUnitTest --tests ai.openclaw.app.gateway.GatewaySessionInvokeTest.sendNodeEventDetailed_doesNotSendBeforeConnectHandshakeCompletes from apps/android; local machine has no Java runtime installed: Unable to locate a Java Runtime.
  • CI android-test-play should verify the Android test after the pushed follow-up commit.

Notes

The notification retry buffer is bounded to 64 events and drops the oldest entries under sustained reconnect/offline pressure to avoid unbounded memory growth.

@openclaw-barnacle openclaw-barnacle Bot added app: android App: android size: S triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels May 8, 2026
@clawsweeper

clawsweeper Bot commented May 9, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge.

Summary
The PR delays Android node event sends until after the gateway connect handshake, queues forwarded notification events during reconnect, adds a regression test, and records the Android fix in the changelog.

Reproducibility: yes. from source inspection: current main publishes currentConnection before the connect RPC completes, and notification forwarding can call sendNodeEvent during that window. I did not live-run a Pixel/Gateway reconnect scenario, so this is source-reproducible rather than live reproduced.

Real behavior proof
Needs stronger real behavior proof before merge: The PR supplies source-path reasoning and attempted/local validation notes, but no after-fix real Android/Gateway reconnect evidence. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, ask a maintainer to comment @clawsweeper re-review.

Next step before merge
The remaining blocker is contributor-supplied real Android/Gateway reconnect proof plus normal exact-head validation; automation cannot produce that proof from the contributor's setup.

Security
Cleared: The diff only changes Android connection ordering, bounded in-memory notification event replay, a focused test, and the changelog; no concrete security or supply-chain regression was found.

Review details

Best possible solution:

Merge this narrow Android runtime fix after exact-head Android validation is green and the contributor adds redacted real reconnect proof showing notification node events wait for connect and replay after reconnect.

Do we have a high-confidence way to reproduce the issue?

Yes from source inspection: current main publishes currentConnection before the connect RPC completes, and notification forwarding can call sendNodeEvent during that window. I did not live-run a Pixel/Gateway reconnect scenario, so this is source-reproducible rather than live reproduced.

Is this the best way to solve the issue?

Yes for the code direction: returning ready metadata, publishing the connection, then invoking onConnected is the narrow maintainable fix for the handshake race. The PR is not merge-ready until real Android/Gateway reconnect proof is attached.

Acceptance criteria:

  • apps/android: ./gradlew :app:testPlayDebugUnitTest --tests ai.openclaw.app.gateway.GatewaySessionInvokeTest.sendNodeEventDetailed_doesNotSendBeforeConnectHandshakeCompletes
  • CI android-test-play for the exact PR head
  • Contributor-supplied real Android/Gateway reconnect proof showing notifications.changed is not sent before connect and queued events flush after reconnect

What I checked:

Likely related people:

  • steipete: Recent Android gateway/session work added authenticated presence alive beacons, adjusted reconnect/auth behavior, and touched GatewaySession, NodeRuntime, and GatewaySessionInvokeTest around the affected node.event path. (role: recent Android gateway/session maintainer; confidence: high; commits: 04e774eeacb3, c3a2701c45b1, 330ba1fa3194; files: apps/android/app/src/main/java/ai/openclaw/app/gateway/GatewaySession.kt, apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt, apps/android/app/src/test/java/ai/openclaw/app/gateway/GatewaySessionInvokeTest.kt)
  • obviyus: Multiple recent Android fixes changed GatewaySession and NodeRuntime around pairing, stored device auth, setup auth, and reconnect-adjacent behavior. (role: Android gateway auth/setup maintainer; confidence: medium; commits: dcf821cfb62b, 11bd40fe8a0c, 6090afa0e5f0; files: apps/android/app/src/main/java/ai/openclaw/app/gateway/GatewaySession.kt, apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt)
  • nimbleenigma: The Android notification forwarding controls commit added the forwarding sink path through NodeRuntime and DeviceNotificationListenerService that this PR now queues during reconnect. (role: notification forwarding introducer; confidence: high; commits: aee61dcee0f3; files: apps/android/app/src/main/java/ai/openclaw/app/NodeRuntime.kt, apps/android/app/src/main/java/ai/openclaw/app/node/DeviceNotificationListenerService.kt, apps/android/app/src/main/java/ai/openclaw/app/gateway/GatewaySession.kt)

Remaining risk / open question:

  • No redacted live Android/Gateway reconnect logs, terminal output, recording, or linked artifact currently proves the after-fix behavior in a real setup.
  • The exact latest PR head should still get the Android test lane checked before merge; the latest commit after the code fix only adds the changelog entry.

Codex review notes: model gpt-5.5, reasoning high; reviewed against db2cc57cf11b.

@TurboTheTurtle

Copy link
Copy Markdown
Contributor Author

Updated the Android branch for the review finding: the connect callback now fires only after connectOnce has published the ready currentConnection, so queued notification events flush with a visible send-ready connection. I also updated the PR body with structured proof/validation. Local Android execution is still blocked by the missing Java runtime on this machine, so I’m relying on CI android-test-play for the Robolectric verification.\n\n@clawsweeper re-review

@openclaw-barnacle openclaw-barnacle Bot added proof: supplied External PR includes structured after-fix real behavior proof. and removed triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels May 9, 2026
@TurboTheTurtle

Copy link
Copy Markdown
Contributor Author

Added the required changelog entry in f6b16794e7 for the Android reconnect/node event ordering fix. Validation: after installing the missing local workspace tooling, pnpm exec oxfmt --check --threads=1 CHANGELOG.md and git diff --check both pass.

Remaining blocker is still the reviewer-requested real Android/Gateway reconnect proof. This machine does not have the Android device/Gateway setup needed to generate redacted reconnect logs or a recording, so I am not claiming that proof yet. The PR body still has the CI/Robolectric/source validation, and a real device/Gateway trace should be added before merge.

@clawsweeper re-review

@TurboTheTurtle

Copy link
Copy Markdown
Contributor Author

Closing this for now to keep the active PR queue under the project limit. The code direction is useful, but this still needs real Android/Gateway reconnect proof from an actual device or equivalent trace before it is worth reopening.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app: android App: android proof: supplied External PR includes structured after-fix real behavior proof. size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Android node sends node.event before websocket connect handshake completes, causing notification events to be lost

1 participant