Bug Fix
PDO placeholder-resend: at-most-once per message (#841) A peer device with cloned Signal state could redeliver the same undecryptable message every ~11 seconds. Each copy triggered a PDO placeholder-resend request to our own phone — thepdo_pending_requests dedup only covered in-flight requests, so it emptied the moment the phone answered (~800 ms), and the next copy immediately opened a new one. In a three-hour storm this produced ~700 redundant requests with no benefit: the phone had already answered without content, so re-asking could not produce anything new.
One request per message. A new pdo_requested memo cache (24h TTL, 512 entries) gates send_pdo_placeholder_resend_request — mirroring WAWebNonMessageDataRequestPlaceholderMessageResendUtils, which uses a session-lifetime set for the same purpose. The memo slot is released if the send itself fails, so a transient error does not permanently block recovery. A content-less phone response leaves the memo in place (the phone has nothing to share for this message; re-asking on the next redelivery cannot help).
Skip migration retry decrypt when nothing moved. migrate_signal_sessions_on_lid_discovery now returns bool indicating whether any sessions moved into a LID slot. When it returns false, the subsequent retry decrypt in try_pn_to_lid_migration_decrypt is skipped: the Signal state is unchanged, so the retry would fail identically and only add a second decrypt error to the log for every redelivered copy.
Log-level adjustments. Three lines that fired once per redelivered copy are brought in line with WA Web’s telemetry handling:
- “Skipping skmsg decryption” →
debug(WA Web’scanDecryptNextskips silently after a retryable pkmsg failure) - “missing message content” on a PDO response →
info(WA Web counts this outcome in telemetry only, no warning) - “Max retries reached” at the PDO fallback →
debug(the high-retrywarn!already fired on the way to the cap)
Breaking changes
CacheConfig gains a new field (whatsapp-rust)
CacheConfig now has a pdo_requested field (default: 24h TTL, 512 entries). Struct literals that spell out every field rather than using ..Default::default() will fail to compile.
MemoryDiagnostics gains a new field (whatsapp-rust)
MemoryDiagnostics now has a pdo_requested: u64 field. Code that exhaustively pattern-matches or constructs MemoryDiagnostics directly will need updating.