Fixes
Empty device record now falls through to network instead of blocking sends (#799) The problem.get_user_devices only goes to the network when a user is completely absent from the device registry. A record that exists but contains no devices was returned as-is — Some([]) — and because any present record was treated as authoritative, the usync re-fetch never fired again.
An empty device list is never valid: WA Web always keeps the primary (device 0) in a user’s device list, so an empty record can only be local corruption. The practical effect was that the affected user became permanently unreachable: every send silently returned an empty recipient list with no network call and no error.
The fix. Both cache layers (L1 in-memory and L2 database) now treat an empty result the same as a missing record — get_devices_from_registry returns None instead of Some([]) when the resolved device list is empty. get_user_devices then falls through to the usync fetch as it would for a brand-new contact, and the corrupted record is overwritten with the valid server-side list on the next send.
Additionally, process_device_list_response now skips persisting any empty device list that usync itself returns (transient or corrupt server response), so a good cached record is never clobbered with an empty one that would then trigger a re-fetch on every subsequent send.
The hot path is unchanged: a record with real devices (including the common single-device [0] case) is still served from the registry with no network round-trip.
Impact. If a contact had an empty device record in your local store (for example, as a result of a corrupted usync response), messages you sent to them after that point would silently produce no encrypted recipients and never be delivered. The state now self-heals on the next send. No API changes. No breaking changes.