diff --git a/app/packet_processor.py b/app/packet_processor.py index 094a0580..afeb41b4 100644 --- a/app/packet_processor.py +++ b/app/packet_processor.py @@ -477,8 +477,9 @@ async def _process_advertisement( path_len, ) - # Use device_role from advertisement for contact type (1=Chat, 2=Repeater, 3=Room, 4=Sensor) - # Use advert.timestamp for last_advert (sender's timestamp), receive timestamp for last_seen + # Use device_role from advertisement for contact type (1=Chat, 2=Repeater, 3=Room, 4=Sensor). + # Persist advert freshness fields using the server receive wall clock so + # route selection is not affected by sender clock skew. contact_type = ( advert.device_role if advert.device_role > 0 else (existing.type if existing else 0) ) @@ -498,7 +499,7 @@ async def _process_advertisement( type=contact_type, lat=advert.lat, lon=advert.lon, - last_advert=advert.timestamp if advert.timestamp > 0 else timestamp, + last_advert=timestamp, last_seen=timestamp, last_path=path_hex, last_path_len=path_len, diff --git a/frontend/prebuilt/assets/BotCodeEditor-DR_BaXar.js b/frontend/prebuilt/assets/BotCodeEditor-BD2FOJ4s.js similarity index 99% rename from frontend/prebuilt/assets/BotCodeEditor-DR_BaXar.js rename to frontend/prebuilt/assets/BotCodeEditor-BD2FOJ4s.js index 7fa4366d..be010762 100644 Binary files a/frontend/prebuilt/assets/BotCodeEditor-DR_BaXar.js and b/frontend/prebuilt/assets/BotCodeEditor-BD2FOJ4s.js differ diff --git a/frontend/prebuilt/assets/BotCodeEditor-DR_BaXar.js.map b/frontend/prebuilt/assets/BotCodeEditor-BD2FOJ4s.js.map similarity index 99% rename from frontend/prebuilt/assets/BotCodeEditor-DR_BaXar.js.map rename to frontend/prebuilt/assets/BotCodeEditor-BD2FOJ4s.js.map index 349a6ba1..74f86138 100644 Binary files a/frontend/prebuilt/assets/BotCodeEditor-DR_BaXar.js.map and b/frontend/prebuilt/assets/BotCodeEditor-BD2FOJ4s.js.map differ diff --git a/frontend/prebuilt/assets/CrackerPanel-BP-Q9HDo.js b/frontend/prebuilt/assets/CrackerPanel-DSLlik3_.js similarity index 99% rename from frontend/prebuilt/assets/CrackerPanel-BP-Q9HDo.js rename to frontend/prebuilt/assets/CrackerPanel-DSLlik3_.js index 20b8403c..cc959c59 100644 Binary files a/frontend/prebuilt/assets/CrackerPanel-BP-Q9HDo.js and b/frontend/prebuilt/assets/CrackerPanel-DSLlik3_.js differ diff --git a/frontend/prebuilt/assets/CrackerPanel-BP-Q9HDo.js.map b/frontend/prebuilt/assets/CrackerPanel-DSLlik3_.js.map similarity index 99% rename from frontend/prebuilt/assets/CrackerPanel-BP-Q9HDo.js.map rename to frontend/prebuilt/assets/CrackerPanel-DSLlik3_.js.map index 426aeba1..3a2863cb 100644 Binary files a/frontend/prebuilt/assets/CrackerPanel-BP-Q9HDo.js.map and b/frontend/prebuilt/assets/CrackerPanel-DSLlik3_.js.map differ diff --git a/frontend/prebuilt/assets/MapView-DytU-fVV.js b/frontend/prebuilt/assets/MapView-7UG06zXw.js similarity index 92% rename from frontend/prebuilt/assets/MapView-DytU-fVV.js rename to frontend/prebuilt/assets/MapView-7UG06zXw.js index 62aaeab6..ff0d3986 100644 Binary files a/frontend/prebuilt/assets/MapView-DytU-fVV.js and b/frontend/prebuilt/assets/MapView-7UG06zXw.js differ diff --git a/frontend/prebuilt/assets/MapView-DytU-fVV.js.map b/frontend/prebuilt/assets/MapView-7UG06zXw.js.map similarity index 99% rename from frontend/prebuilt/assets/MapView-DytU-fVV.js.map rename to frontend/prebuilt/assets/MapView-7UG06zXw.js.map index 206051a3..f729e3de 100644 Binary files a/frontend/prebuilt/assets/MapView-DytU-fVV.js.map and b/frontend/prebuilt/assets/MapView-7UG06zXw.js.map differ diff --git a/frontend/prebuilt/assets/NeighborsMiniMap-Dju8bMYb.js b/frontend/prebuilt/assets/NeighborsMiniMap-C3Ju-R0X.js similarity index 85% rename from frontend/prebuilt/assets/NeighborsMiniMap-Dju8bMYb.js rename to frontend/prebuilt/assets/NeighborsMiniMap-C3Ju-R0X.js index b4fb52fa..f26f3325 100644 Binary files a/frontend/prebuilt/assets/NeighborsMiniMap-Dju8bMYb.js and b/frontend/prebuilt/assets/NeighborsMiniMap-C3Ju-R0X.js differ diff --git a/frontend/prebuilt/assets/NeighborsMiniMap-Dju8bMYb.js.map b/frontend/prebuilt/assets/NeighborsMiniMap-C3Ju-R0X.js.map similarity index 97% rename from frontend/prebuilt/assets/NeighborsMiniMap-Dju8bMYb.js.map rename to frontend/prebuilt/assets/NeighborsMiniMap-C3Ju-R0X.js.map index 4b2c093e..8dbf1329 100644 Binary files a/frontend/prebuilt/assets/NeighborsMiniMap-Dju8bMYb.js.map and b/frontend/prebuilt/assets/NeighborsMiniMap-C3Ju-R0X.js.map differ diff --git a/frontend/prebuilt/assets/PathRouteMap-D3poE0C9.js b/frontend/prebuilt/assets/PathRouteMap-DdylhAp-.js similarity index 95% rename from frontend/prebuilt/assets/PathRouteMap-D3poE0C9.js rename to frontend/prebuilt/assets/PathRouteMap-DdylhAp-.js index 23eb6692..c57417ad 100644 Binary files a/frontend/prebuilt/assets/PathRouteMap-D3poE0C9.js and b/frontend/prebuilt/assets/PathRouteMap-DdylhAp-.js differ diff --git a/frontend/prebuilt/assets/PathRouteMap-D3poE0C9.js.map b/frontend/prebuilt/assets/PathRouteMap-DdylhAp-.js.map similarity index 99% rename from frontend/prebuilt/assets/PathRouteMap-D3poE0C9.js.map rename to frontend/prebuilt/assets/PathRouteMap-DdylhAp-.js.map index cc476cbe..bb5e2d94 100644 Binary files a/frontend/prebuilt/assets/PathRouteMap-D3poE0C9.js.map and b/frontend/prebuilt/assets/PathRouteMap-DdylhAp-.js.map differ diff --git a/frontend/prebuilt/assets/Popup-kARDuK6y.js b/frontend/prebuilt/assets/Popup-CqM5D37r.js similarity index 81% rename from frontend/prebuilt/assets/Popup-kARDuK6y.js rename to frontend/prebuilt/assets/Popup-CqM5D37r.js index 49af407b..977a2429 100644 Binary files a/frontend/prebuilt/assets/Popup-kARDuK6y.js and b/frontend/prebuilt/assets/Popup-CqM5D37r.js differ diff --git a/frontend/prebuilt/assets/Popup-kARDuK6y.js.map b/frontend/prebuilt/assets/Popup-CqM5D37r.js.map similarity index 97% rename from frontend/prebuilt/assets/Popup-kARDuK6y.js.map rename to frontend/prebuilt/assets/Popup-CqM5D37r.js.map index e7f1367a..bd61344c 100644 Binary files a/frontend/prebuilt/assets/Popup-kARDuK6y.js.map and b/frontend/prebuilt/assets/Popup-CqM5D37r.js.map differ diff --git a/frontend/prebuilt/assets/RepeaterDashboard-BDRVFKsI.js b/frontend/prebuilt/assets/RepeaterDashboard-DrFtUyWd.js similarity index 98% rename from frontend/prebuilt/assets/RepeaterDashboard-BDRVFKsI.js rename to frontend/prebuilt/assets/RepeaterDashboard-DrFtUyWd.js index 4e55ebdc..7d57d958 100644 Binary files a/frontend/prebuilt/assets/RepeaterDashboard-BDRVFKsI.js and b/frontend/prebuilt/assets/RepeaterDashboard-DrFtUyWd.js differ diff --git a/frontend/prebuilt/assets/RepeaterDashboard-BDRVFKsI.js.map b/frontend/prebuilt/assets/RepeaterDashboard-DrFtUyWd.js.map similarity index 99% rename from frontend/prebuilt/assets/RepeaterDashboard-BDRVFKsI.js.map rename to frontend/prebuilt/assets/RepeaterDashboard-DrFtUyWd.js.map index f5ed3715..c974c9a2 100644 Binary files a/frontend/prebuilt/assets/RepeaterDashboard-BDRVFKsI.js.map and b/frontend/prebuilt/assets/RepeaterDashboard-DrFtUyWd.js.map differ diff --git a/frontend/prebuilt/assets/SearchView-tXHXH02i.js b/frontend/prebuilt/assets/SearchView-CqEz3JCz.js similarity index 97% rename from frontend/prebuilt/assets/SearchView-tXHXH02i.js rename to frontend/prebuilt/assets/SearchView-CqEz3JCz.js index ebcc06e9..6b559262 100644 Binary files a/frontend/prebuilt/assets/SearchView-tXHXH02i.js and b/frontend/prebuilt/assets/SearchView-CqEz3JCz.js differ diff --git a/frontend/prebuilt/assets/SearchView-tXHXH02i.js.map b/frontend/prebuilt/assets/SearchView-CqEz3JCz.js.map similarity index 99% rename from frontend/prebuilt/assets/SearchView-tXHXH02i.js.map rename to frontend/prebuilt/assets/SearchView-CqEz3JCz.js.map index f8f2eb56..9dcbef74 100644 Binary files a/frontend/prebuilt/assets/SearchView-tXHXH02i.js.map and b/frontend/prebuilt/assets/SearchView-CqEz3JCz.js.map differ diff --git a/frontend/prebuilt/assets/SettingsModal-Dtfx_pBE.js b/frontend/prebuilt/assets/SettingsModal-GFXFFaeS.js similarity index 99% rename from frontend/prebuilt/assets/SettingsModal-Dtfx_pBE.js rename to frontend/prebuilt/assets/SettingsModal-GFXFFaeS.js index 5ecd2a94..23cbe618 100644 Binary files a/frontend/prebuilt/assets/SettingsModal-Dtfx_pBE.js and b/frontend/prebuilt/assets/SettingsModal-GFXFFaeS.js differ diff --git a/frontend/prebuilt/assets/SettingsModal-Dtfx_pBE.js.map b/frontend/prebuilt/assets/SettingsModal-GFXFFaeS.js.map similarity index 99% rename from frontend/prebuilt/assets/SettingsModal-Dtfx_pBE.js.map rename to frontend/prebuilt/assets/SettingsModal-GFXFFaeS.js.map index 78eb646a..3edb2b98 100644 Binary files a/frontend/prebuilt/assets/SettingsModal-Dtfx_pBE.js.map and b/frontend/prebuilt/assets/SettingsModal-GFXFFaeS.js.map differ diff --git a/frontend/prebuilt/assets/VisualizerView-BgaEF0Sw.js b/frontend/prebuilt/assets/VisualizerView-BswMOFbt.js similarity index 99% rename from frontend/prebuilt/assets/VisualizerView-BgaEF0Sw.js rename to frontend/prebuilt/assets/VisualizerView-BswMOFbt.js index fabbfffb..59d04215 100644 Binary files a/frontend/prebuilt/assets/VisualizerView-BgaEF0Sw.js and b/frontend/prebuilt/assets/VisualizerView-BswMOFbt.js differ diff --git a/frontend/prebuilt/assets/VisualizerView-BgaEF0Sw.js.map b/frontend/prebuilt/assets/VisualizerView-BswMOFbt.js.map similarity index 99% rename from frontend/prebuilt/assets/VisualizerView-BgaEF0Sw.js.map rename to frontend/prebuilt/assets/VisualizerView-BswMOFbt.js.map index 1ee270a6..98d4b193 100644 Binary files a/frontend/prebuilt/assets/VisualizerView-BgaEF0Sw.js.map and b/frontend/prebuilt/assets/VisualizerView-BswMOFbt.js.map differ diff --git a/frontend/prebuilt/assets/hooks-Bk-tBmjl.js b/frontend/prebuilt/assets/hooks-Bk-tBmjl.js new file mode 100644 index 00000000..f74ff367 Binary files /dev/null and b/frontend/prebuilt/assets/hooks-Bk-tBmjl.js differ diff --git a/frontend/prebuilt/assets/hooks-DmAVOeP2.js.map b/frontend/prebuilt/assets/hooks-Bk-tBmjl.js.map similarity index 90% rename from frontend/prebuilt/assets/hooks-DmAVOeP2.js.map rename to frontend/prebuilt/assets/hooks-Bk-tBmjl.js.map index b7815b56..d73cfcef 100644 Binary files a/frontend/prebuilt/assets/hooks-DmAVOeP2.js.map and b/frontend/prebuilt/assets/hooks-Bk-tBmjl.js.map differ diff --git a/frontend/prebuilt/assets/hooks-DmAVOeP2.js b/frontend/prebuilt/assets/hooks-DmAVOeP2.js deleted file mode 100644 index 97cc1145..00000000 Binary files a/frontend/prebuilt/assets/hooks-DmAVOeP2.js and /dev/null differ diff --git a/frontend/prebuilt/assets/index-fakNQBhQ.js b/frontend/prebuilt/assets/index-DSM_ctlA.js similarity index 99% rename from frontend/prebuilt/assets/index-fakNQBhQ.js rename to frontend/prebuilt/assets/index-DSM_ctlA.js index 16d807d3..a924b4c6 100644 Binary files a/frontend/prebuilt/assets/index-fakNQBhQ.js and b/frontend/prebuilt/assets/index-DSM_ctlA.js differ diff --git a/frontend/prebuilt/assets/index-fakNQBhQ.js.map b/frontend/prebuilt/assets/index-DSM_ctlA.js.map similarity index 99% rename from frontend/prebuilt/assets/index-fakNQBhQ.js.map rename to frontend/prebuilt/assets/index-DSM_ctlA.js.map index fce2bae8..0ef131e9 100644 Binary files a/frontend/prebuilt/assets/index-fakNQBhQ.js.map and b/frontend/prebuilt/assets/index-DSM_ctlA.js.map differ diff --git a/frontend/prebuilt/assets/leaflet-CiRM2en4.js b/frontend/prebuilt/assets/leaflet-Bn7rjtY9.js similarity index 99% rename from frontend/prebuilt/assets/leaflet-CiRM2en4.js rename to frontend/prebuilt/assets/leaflet-Bn7rjtY9.js index 46791366..f429b49e 100644 Binary files a/frontend/prebuilt/assets/leaflet-CiRM2en4.js and b/frontend/prebuilt/assets/leaflet-Bn7rjtY9.js differ diff --git a/frontend/prebuilt/assets/leaflet-CiRM2en4.js.map b/frontend/prebuilt/assets/leaflet-Bn7rjtY9.js.map similarity index 99% rename from frontend/prebuilt/assets/leaflet-CiRM2en4.js.map rename to frontend/prebuilt/assets/leaflet-Bn7rjtY9.js.map index 7c1d2a0d..8305ed17 100644 Binary files a/frontend/prebuilt/assets/leaflet-CiRM2en4.js.map and b/frontend/prebuilt/assets/leaflet-Bn7rjtY9.js.map differ diff --git a/frontend/prebuilt/assets/separator-Dddr-OIj.js b/frontend/prebuilt/assets/separator-B1Gufat6.js similarity index 89% rename from frontend/prebuilt/assets/separator-Dddr-OIj.js rename to frontend/prebuilt/assets/separator-B1Gufat6.js index 86a21098..97eb89e0 100644 Binary files a/frontend/prebuilt/assets/separator-Dddr-OIj.js and b/frontend/prebuilt/assets/separator-B1Gufat6.js differ diff --git a/frontend/prebuilt/assets/separator-Dddr-OIj.js.map b/frontend/prebuilt/assets/separator-B1Gufat6.js.map similarity index 98% rename from frontend/prebuilt/assets/separator-Dddr-OIj.js.map rename to frontend/prebuilt/assets/separator-B1Gufat6.js.map index 4ece9eab..98672d69 100644 Binary files a/frontend/prebuilt/assets/separator-Dddr-OIj.js.map and b/frontend/prebuilt/assets/separator-B1Gufat6.js.map differ diff --git a/frontend/prebuilt/index.html b/frontend/prebuilt/index.html index ff7d72d4..090e9270 100644 Binary files a/frontend/prebuilt/index.html and b/frontend/prebuilt/index.html differ diff --git a/tests/test_packet_pipeline.py b/tests/test_packet_pipeline.py index 0e2c067c..24c56169 100644 --- a/tests/test_packet_pipeline.py +++ b/tests/test_packet_pipeline.py @@ -355,10 +355,10 @@ class TestAdvertisementPipeline: assert contact.last_path_len == 1 # Still the shorter path @pytest.mark.asyncio - async def test_advertisement_path_freshness_uses_last_advert_not_last_seen( + async def test_advertisement_path_freshness_uses_receive_time_not_sender_clock( self, test_db, captured_broadcasts ): - """Non-advert contact activity should not keep an old advert path artificially fresh.""" + """Sender clock skew should not keep an old advert path artificially fresh.""" from unittest.mock import MagicMock from app.decoder import ParsedAdvertisement @@ -385,22 +385,43 @@ class TestAdvertisementPipeline: longer_packet_info.path_hash_size = 1 longer_packet_info.payload = b"" + skewed_shorter_packet_info = MagicMock() + skewed_shorter_packet_info.path_length = 1 + skewed_shorter_packet_info.path = bytes.fromhex("aa") + skewed_shorter_packet_info.path_hash_size = 1 + skewed_shorter_packet_info.payload = b"" + with patch("app.packet_processor.broadcast_event", mock_broadcast): with patch("app.packet_processor.parse_advertisement") as mock_parse: mock_parse.return_value = ParsedAdvertisement( public_key=test_pubkey, name="TestNode", - timestamp=1070, + timestamp=5000, lat=None, lon=None, device_role=1, ) - await _process_advertisement(b"", timestamp=1070, packet_info=longer_packet_info) + await _process_advertisement( + b"", timestamp=1070, packet_info=skewed_shorter_packet_info + ) + + with patch("app.packet_processor.broadcast_event", mock_broadcast): + with patch("app.packet_processor.parse_advertisement") as mock_parse: + mock_parse.return_value = ParsedAdvertisement( + public_key=test_pubkey, + name="TestNode", + timestamp=5005, + lat=None, + lon=None, + device_role=1, + ) + await _process_advertisement(b"", timestamp=1200, packet_info=longer_packet_info) contact = await ContactRepository.get_by_key(test_pubkey) assert contact is not None assert contact.last_path_len == 3 assert contact.last_path == "aabbcc" + assert contact.last_advert == 1200 @pytest.mark.asyncio async def test_advertisement_default_path_len_treated_as_infinity(