Summary
The debug-only Mesh Lab receive hooks dm_recv and msg_recv accepted only messages whose timestamp (the sender's clock) was >= the receiver's clock when the command started. If the receiver's clock runs ahead of the sender's, a message that really arrived gets skipped and the command times out.
This showed up on two physical phones whose clocks were about 140 s apart: dm, session_recovery and identity_reset failed on both a feature branch and its base commit, even though the sender got delivery ACKs.
Change
- New debug-only
ArrivedMessageMatcher: when a receive command starts, it records the IDs of messages already in the store and then matches only IDs it hasn't seen. Sender timestamps are never compared with the local clock. Thepeer/contains/channelfilters still apply. dm_recvandmsg_recvuse it in bothTestHookDriver(phone) andWearTestHookDriver(watch, which mirrors the debug helper the same wayPttTestAudioAnalyzeris mirrored).file_recvalready uses local file modification times, so it is unchanged.ptt_recvhas no timestamp filter, so it is also unchanged (see below).- Everything stays in
app/src/debug/andwear/src/debug/. No release sources ormesh_lab.pychanges.
Risk
Low. Only debug test hooks change, and nothing in the release APK is affected. The one change in behavior: an existing message that gets updated in place (same ID) no longer counts as a new arrival, which is what the hooks are meant to do.
Tests
./gradlew testDebugUnitTest lintDebug :app:assembleDebug :wear:assembleDebugpasses.- New
ArrivedMessageMatcherTest: a message stamped 140 s behind the receiver's clock still matches, a message already present at start is ignored even if its timestamp is ahead, and the filters still apply. - Mesh Lab
scenario allon two physical phones with one clock about 140 s ahead: 11/12 pass, includingdm,session_recoveryandidentity_reset, which failed before this change. Raw evidence and logs are kept local.
Known remaining failure: ptt_broadcast (separate cause, not a hook bug)
ptt_broadcast still fails when clocks are skewed. The receiver never sees the burst because MessageHandler.handlePublicVoiceFrame drops public voice frames whose packet timestamp is more than ±30 s from the local clock, and it does so without logging. DM PTT goes through Noise without that window, which is why ptt_dm passes. That freshness window is product/protocol behavior, so this PR leaves it alone. Whether to widen it, align it with iOS, or log the drops should be decided separately. With synced clocks, ptt_broadcast is not affected.
Codex Review Summary
This comment shows the latest Codex review activity on this pull request.
0c0b16cℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.