Reduce Android realtime heartbeat noise

This commit is contained in:
kris
2026-04-10 13:25:05 +08:00
parent 0cba837ed3
commit c4dbfc7398
6 changed files with 308 additions and 2 deletions

View File

@@ -0,0 +1,23 @@
# Android Realtime Noise Reduction Design
## Goal
Reduce Android message receive stutter and reconnect-visible reloads by preventing heartbeat-only SSE traffic from triggering full conversation list refreshes.
## Evidence
The production `boss-web` service was active and had no recent service errors. A direct authenticated SSE probe showed the stream stays open with keepalive comments, but every local-agent heartbeat emitted `devices.updated` followed by `conversation.updated` with only `deviceId`. Android `MainActivity` treated that device-only `conversation.updated` as a full conversations tab reload. The stream also sends an initial `conversation.context_indicator.updated` snapshot on connection; Android was not consuming its payload directly and instead used it as another full reload trigger.
## Design
Keep `devices.updated` for every heartbeat so device status remains fresh. Stop publishing `conversation.updated` for unchanged device heartbeats. Publish a single `conversation.updated` with `note: "device_import.updated"` only when heartbeat candidate/import state actually changes the conversation drawer structure.
On Android, do not use the initial `conversation.context_indicator.updated` snapshot as a full list reload trigger. Actual conversation and project message events still refresh the relevant views, while the existing root-page auto-refresh remains the low-frequency fallback for aggregate context status.
## Testing
Add event-contract tests proving unchanged heartbeats only emit `devices.updated`, while changed import candidates emit one `conversation.updated` marked as `device_import.updated`. Add an Android static test proving `MainActivity` no longer returns `true` for the initial context snapshot refresh path.
## Out Of Scope
This change does not replace SSE with a different transport, does not remove project-scoped message events, and does not implement payload-level in-place updates for Android conversation rows.