Skip to content

Fix room message timestamps - #3127

Open
mikecarper wants to merge 1 commit into
meshcore-dev:devfrom
mikecarper:agent/fix-legacy-room-message-acks
Open

Fix room message timestamps#3127
mikecarper wants to merge 1 commit into
meshcore-dev:devfrom
mikecarper:agent/fix-legacy-room-message-acks

Conversation

@mikecarper

@mikecarper mikecarper commented Aug 7, 2026

Copy link
Copy Markdown

Summary

  • translate direct room-message timestamps onto the companion's monotonic RTC clock
  • preserve that translated timestamp across application retries
  • add a bounded timestamp-mapping cache with native regression tests

The current implementation uses one per-client last_timestamp replay watermark for login requests, keep-alives, CLI traffic, and room posts. Current upstream dev still uses this shared watermark, as do deployed room servers built from earlier versions of the same implementation.

This PR changes only companion firmware so those deployed room servers do not need to be updated.

Root cause

The companion already generates login and keep-alive timestamps from its own RTC. For ordinary text messages, however, it forwards the timestamp supplied by the phone app. Those timestamps can come from different clock states even though the packets are sent by the same companion.

With a shared room-server replay watermark, this can produce the following sequence:

  1. The companion logs in using a timestamp from its RTC, advancing client->last_timestamp on the room server.
  2. The app submits a room message carrying an older phone-supplied timestamp.
  3. The room server compares that timestamp with the login timestamp and rejects the message as stale.
  4. No ACK is sent, so the app remains at Sending (attempt 2/3) and subsequent attempts fail the same comparison.

The fix gives a new room message a timestamp from the companion's monotonic RTC, matching the clock source already used for login and keep-alive traffic.

Why retries keep the same timestamp

The logical message timestamp and the MeshCore packet hash serve different purposes:

  • The room server uses the timestamp to decide whether a post is new or a retry. It must remain stable across attempts.
  • Mesh duplicate detection hashes the encrypted payload. Each app retry changes the attempt byte inside that payload, so attempts 1, 2, and 3 have different packet hashes even when their logical timestamp is unchanged.

This gives the intended behavior:

  • If the original message is lost, the retry is newer than the room's watermark, so the room stores it and ACKs it.
  • If the room received the original but its ACK was lost, the equal timestamp identifies the retry; the room sends another ACK without storing a duplicate post.
  • Assigning a fresh timestamp to every retry would instead make the room store the same text more than once.

Lower-level retransmission of the exact same encrypted packet is separate from the app-level attempt mechanism addressed here.

Impact and scope

Companions can send messages to room servers using the shared replay watermark without requiring a room-server firmware update. Peer messages, channel messages, and room-server firmware are unchanged.

Validation

  • pio test -e native — 30 tests passed
  • pio run -e Heltec_v3_companion_radio_ble — passed
  • pio run -e RAK_WisMesh_Tag_companion_radio_ble — passed

@mikecarper mikecarper changed the title Fix room message timestamps for legacy servers Fix room message timestamps Aug 7, 2026
@mikecarper
mikecarper marked this pull request as ready for review August 7, 2026 21:03
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