From 21b1c0510f6019ea1464bc4fa70c2511a9cfad61 Mon Sep 17 00:00:00 2001 From: MarekWo Date: Mon, 16 Mar 2026 21:54:50 +0100 Subject: [PATCH] fix(dm): emit original expected_ack on retry ACK for frontend matching MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a DM is retried, the retry send generates a NEW ack code. The backend correctly maps retry ack → dm_id via _pending_acks, but the WebSocket emit was sending the retry ack code. The frontend DOM still has data-ack="" from the first send, so it could never match retry ACKs → delivery checkmark never appeared. Now both _on_ack() and _confirm_delivery() look up the original expected_ack from the database before emitting to the frontend. Co-Authored-By: Claude Opus 4.6 --- app/device_manager.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/app/device_manager.py b/app/device_manager.py index f2710a3..da035df 100644 --- a/app/device_manager.py +++ b/app/device_manager.py @@ -539,8 +539,16 @@ class DeviceManager: (f" (dm_id={dm_id})" if dm_id else "")) if self.socketio: + # Emit the ORIGINAL expected_ack (from DB) so frontend can match + # the DOM element. Retry sends generate new ack codes, but the + # DOM still has the original expected_ack from the first send. + original_ack = ack_code + if dm_id: + dm = self.db.get_dm_by_id(dm_id) + if dm and dm.get('expected_ack'): + original_ack = dm['expected_ack'] self.socketio.emit('ack', { - 'expected_ack': ack_code, + 'expected_ack': original_ack, 'dm_id': dm_id, 'snr': data.get('snr'), 'rssi': data.get('rssi'), @@ -1119,8 +1127,13 @@ class DeviceManager: logger.info(f"DM delivery confirmed: dm_id={dm_id}, ack={ack_code}") if self.socketio: + # Emit original expected_ack so frontend can match the DOM element + original_ack = ack_code + dm = self.db.get_dm_by_id(dm_id) + if dm and dm.get('expected_ack'): + original_ack = dm['expected_ack'] self.socketio.emit('ack', { - 'expected_ack': ack_code, + 'expected_ack': original_ack, 'dm_id': dm_id, 'snr': data.get('snr'), }, namespace='/chat')