From 49940935a9c76971c7f06d7178f9c8f60b759b38 Mon Sep 17 00:00:00 2001 From: pharmacomaniac Date: Thu, 10 Sep 2026 16:30:43 -0500 Subject: [PATCH] Manager: cover forced road-state transitions Co-authored-by: pharmacomaniac --- .../tests/test_navigation_params.py | 16 +++++++++ system/manager/manager.py | 22 ++++++------ system/manager/test/test_manager.py | 36 +++++++++++++++++++ 3 files changed, 63 insertions(+), 11 deletions(-) mode change 100644 => 100755 system/manager/manager.py diff --git a/starpilot/system/the_galaxy/tests/test_navigation_params.py b/starpilot/system/the_galaxy/tests/test_navigation_params.py index b941c0228e..d6af895f65 100644 --- a/starpilot/system/the_galaxy/tests/test_navigation_params.py +++ b/starpilot/system/the_galaxy/tests/test_navigation_params.py @@ -753,6 +753,22 @@ def test_force_offroad_toggle_rejects_when_not_parked(monkeypatch): assert fake_params.writes == [] +def test_force_offroad_can_be_disabled_without_live_park(monkeypatch): + client, fake_params = _params_client(monkeypatch, { + "ForceOffroad": True, + "ForceOnroad": False, + "IsOnroad": False, + }, "tici") + monkeypatch.setattr(the_galaxy, "_get_vehicle_parked", lambda: False) + + response = client.put("/api/params", json={"key": "ForceOffroad", "value": False}) + + assert response.status_code == 200 + assert response.get_json()["updated"] == {"ForceOffroad": False, "ForceOnroad": False} + assert fake_params.values["ForceOffroad"] is False + assert fake_params.values["ForceOnroad"] is False + + def test_curve_speed_controller_reset_clears_learned_data_offroad(monkeypatch): client, fake_params = _params_client(monkeypatch, { "IsOnroad": False, diff --git a/system/manager/manager.py b/system/manager/manager.py old mode 100644 new mode 100755 index 5b6e6ca690..92b3c6bc88 --- a/system/manager/manager.py +++ b/system/manager/manager.py @@ -1115,6 +1115,16 @@ def manager_cleanup() -> None: cloudlog.info("everything is dead") +def reset_onroad_transition_params(params, params_memory, force_onroad: bool) -> None: + """Clear stale card-readiness state before a forced onroad restart.""" + if force_onroad: + params.remove("ControlsReady") + params.remove("FirmwareQueryDone") + else: + params.clear_all(ParamKeyFlag.CLEAR_ON_ONROAD_TRANSITION) + params_memory.clear_all(ParamKeyFlag.CLEAR_ON_ONROAD_TRANSITION) + + def manager_thread() -> None: manager_thread_start = time.monotonic() last_timing = _log_boot_timing("manager_thread", "start", manager_thread_start, manager_thread_start) @@ -1164,17 +1174,7 @@ def manager_thread() -> None: started = sm['deviceState'].started if started and not started_prev: - # ForceOnroad skips the normal onroad parameter reset. - if starpilot_toggles.force_onroad: - # These flags stay set after card exits. - # Clear them so pandad doesn't think card finished init on restart. - params.remove("ControlsReady") - params.remove("FirmwareQueryDone") - else: - params.clear_all(ParamKeyFlag.CLEAR_ON_ONROAD_TRANSITION) - - # StarPilot variables - params_memory.clear_all(ParamKeyFlag.CLEAR_ON_ONROAD_TRANSITION) + reset_onroad_transition_params(params, params_memory, starpilot_toggles.force_onroad) elif not started and started_prev: params.clear_all(ParamKeyFlag.CLEAR_ON_OFFROAD_TRANSITION) diff --git a/system/manager/test/test_manager.py b/system/manager/test/test_manager.py index 6ed0300a99..1e91f53e52 100644 --- a/system/manager/test/test_manager.py +++ b/system/manager/test/test_manager.py @@ -74,6 +74,42 @@ class FileBackedFakeParams: Path(self.get_param_path(key)).unlink(missing_ok=True) +class TransitionParams: + def __init__(self): + self.removals = [] + self.clears = [] + + def remove(self, key): + self.removals.append(key) + + def clear_all(self, flags): + self.clears.append(flags) + + +def test_force_onroad_resets_card_readiness_flags(): + params = TransitionParams() + params_memory = TransitionParams() + + manager.reset_onroad_transition_params(params, params_memory, force_onroad=True) + + assert params.removals == ["ControlsReady", "FirmwareQueryDone"] + assert params.clears == [] + assert params_memory.removals == [] + assert params_memory.clears == [] + + +def test_normal_onroad_transition_clears_transition_flags(): + params = TransitionParams() + params_memory = TransitionParams() + + manager.reset_onroad_transition_params(params, params_memory, force_onroad=False) + + assert params.removals == [] + assert params.clears == [manager.ParamKeyFlag.CLEAR_ON_ONROAD_TRANSITION] + assert params_memory.removals == [] + assert params_memory.clears == [manager.ParamKeyFlag.CLEAR_ON_ONROAD_TRANSITION] + + def test_navigation_selected_while_already_offroad_is_not_tracked_for_cleanup(tmp_path): params = FileBackedFakeParams(tmp_path / "params", { "ClearNavOnOffroad": True,