Push notification dedupe: one message = one notification — an offline message was notified twice (FCM push, then again when the app synced the outbox and mirrored the replayed frames). Fix: the gateway records the highest outbox cursor delivered per device via push (devices.last_pushed_cursor, advanced only on successful send) and returns it in hello.ack; sync-replayed frames carry their outbox cursor in the envelope; the app skips system notifications for replayed frames at/below the watermark (live frames never suppressed — that is the case where no push fired). Also: 5s per-chat push coalescing so a cron delivery (notification frame + message frame) pushes once, and the FCM handler no longer posts a redundant notification (skips when WS is connected or FCM already displayed the notification payload; data-only messages are the exception). Docs: frames.schema.json, 04-wire-protocol.md, 08-push.md §8.8
This commit is contained in:
1 parent
acd5fb4ad0
commit
9f3f9842c8
11 files changed
+301
-98
No files matched your search
@@ -21,6 +21,10 @@ Every frame:
|
||||
- `v` — protocol version (currently `1`). Server rejects unknown major versions.
|
||||
- `id` — request id (client-chosen). Responses/acks echo it. Events have no `id`.
|
||||
- `chat_id` / `thread_id` — top-level for convenience; may also be in `payload`.
|
||||
- `cursor` — outbox cursor the frame was parked under. Present **only** on
|
||||
frames replayed by `sync` (live frames carry none). The app compares it
|
||||
against `last_pushed_cursor` from `hello.ack` to skip re-notifying frames
|
||||
that already woke the device via push (`08-push.md` §8.7).
|
||||
- Unknown `type`s are ignored (forward-compat); unknown `payload` fields ignored.
|
||||
|
||||
**Binary media frames** are not JSON. A media transfer is: one JSON header frame
|
||||
@@ -36,9 +40,14 @@ Pairing succeeded.
|
||||
"server_caps":{"streaming":true,"reasoning":true,"tools":true,"media":true,
|
||||
"search":true,"push":"fcm","pickers":true},
|
||||
"sync_cursor":1042,
|
||||
"last_pushed_cursor":1040,
|
||||
"channels":[{"chat_id":"android:default","name":"Default","kind":"default","is_default":true}]
|
||||
}}
|
||||
```
|
||||
`last_pushed_cursor` is the highest outbox cursor already delivered to THIS
|
||||
device via the push backend (0 = never). The app skips system notifications
|
||||
for sync-replayed frames with `cursor <= last_pushed_cursor` — they already
|
||||
woke the device via push (dedupe, `08-push.md` §8.7).
|
||||
|
||||
### `message`
|
||||
A final / standalone message.
|
||||
|
||||
Reference in new issue
Block a user