From b9a64c6560282649cc3d313520898fc031a28cad Mon Sep 17 00:00:00 2001 From: c4ch3c4d3 Date: Sat, 22 Aug 2026 18:31:06 -0600 Subject: [PATCH] fix(reliability): supervisor re-parks stock-resurrected dummy STA on interval --- .../user/remote_access/pager-webui/server.py | 16 +++++++++++++++ tests/test_health.py | 20 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/payload/user/remote_access/pager-webui/server.py b/payload/user/remote_access/pager-webui/server.py index 90ac91c..bc3c5cd 100644 --- a/payload/user/remote_access/pager-webui/server.py +++ b/payload/user/remote_access/pager-webui/server.py @@ -4719,6 +4719,7 @@ def _mem_percent(path='/proc/meminfo'): MEM_WARN_PERCENT = 85 MEM_WARN_STREAK = 5 +HEALTH_STA_PARK_INTERVAL = 4 # every Nth health tick (~1/min at 15s poll) def health_check(): @@ -4755,6 +4756,21 @@ def health_check(): # does not bring secondary monitors back). Repair them without cooldown. if _monitor_down('wlan1mon') or _monitor_down('wlan0mon'): _bring_monitors_up(h) + # The stock daemon re-enables its dummy STA during its own config + # reconvergence (e.g. after wifi reloads), silently pinning phy0 again. + # Re-park periodically — parking never runs wifi reload, so it is safe + # to repeat. + h['ticks'] = h.get('ticks', 0) + 1 + if h['ticks'] % HEALTH_STA_PARK_INTERVAL == 0 and _sta_uplink_enabled(): + try: + _park_dummy_sta() + h['last_action'] = 'dummy STA re-parked' + import mk8_events + mk8_events.log_event('guard_fix', + msg='re-parked dummy_radio0 STA ' + '(stock reconvergence)') + except Exception: + pass h['mem_percent'] = _mem_percent() if h['mem_percent'] >= MEM_WARN_PERCENT: h['mem_streak'] = h.get('mem_streak', 0) + 1 diff --git a/tests/test_health.py b/tests/test_health.py index 181721d..a75f389 100644 --- a/tests/test_health.py +++ b/tests/test_health.py @@ -1,6 +1,7 @@ import os import sys import unittest +from unittest import mock sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'payload', 'user', 'remote_access', 'pager-webui')) import server @@ -150,6 +151,25 @@ class SupervisorExtrasTest(unittest.TestCase): open(path, 'w').write(content) self.assertEqual(server._mem_percent(path), 60) + def test_health_reparks_resurrected_dummy_sta(self): + server._health['ticks'] = server.HEALTH_STA_PARK_INTERVAL - 1 + with mock.patch.object( + server, '_sta_uplink_enabled', return_value=True), \ + __import__('unittest').mock.patch.object( + server, '_park_dummy_sta') as park: + h = server.health_check() + park.assert_called_once() + self.assertEqual(server._health['ticks'], + server.HEALTH_STA_PARK_INTERVAL) + # not on interval ticks: no re-park + server._health['ticks'] = 1 + with mock.patch.object( + server, '_sta_uplink_enabled', return_value=True), \ + __import__('unittest').mock.patch.object( + server, '_park_dummy_sta') as park: + server.health_check() + park.assert_not_called() + def test_health_reports_events_and_counters(self): import mk8_events mk8_events.log_event('restart', msg='x')