diff --git a/selfdrive/ui/layouts/settings/developer.py b/selfdrive/ui/layouts/settings/developer.py index b632e4e0d..964d28bf9 100644 --- a/selfdrive/ui/layouts/settings/developer.py +++ b/selfdrive/ui/layouts/settings/developer.py @@ -36,7 +36,7 @@ class DeveloperLayout(Widget): def __init__(self): super().__init__() self._params = Params() - self._is_release = self._params.get_bool("IsReleaseBranch") + self._is_release = False # self._params.get_bool("IsReleaseBranch") # Build items and keep references for callbacks/state updates self._adb_toggle = toggle_item( diff --git a/selfdrive/ui/layouts/settings/toggles.py b/selfdrive/ui/layouts/settings/toggles.py index 9923f3a35..dfd0c73f6 100644 --- a/selfdrive/ui/layouts/settings/toggles.py +++ b/selfdrive/ui/layouts/settings/toggles.py @@ -42,7 +42,7 @@ class TogglesLayout(Widget): def __init__(self): super().__init__() self._params = Params() - self._is_release = self._params.get_bool("IsReleaseBranch") + self._is_release = False # self._params.get_bool("IsReleaseBranch") # param, title, desc, icon, needs_restart self._toggle_defs = { diff --git a/selfdrive/ui/sunnypilot/ui_state.py b/selfdrive/ui/sunnypilot/ui_state.py index c80281987..2cfd5bd4f 100644 --- a/selfdrive/ui/sunnypilot/ui_state.py +++ b/selfdrive/ui/sunnypilot/ui_state.py @@ -159,7 +159,6 @@ class UIStateSP: def _enforce_constraints(self) -> None: has_long = self.has_longitudinal_control - has_icbm = self.has_icbm CP = self.CP if CP is not None: @@ -168,8 +167,8 @@ class UIStateSP: self.params.remove("EnforceTorqueControl") self.params.remove("NeuralNetworkLateralControl") - # Alpha longitudinal: clear if not available or on release branch - if not CP.alphaLongitudinalAvailable or self.params.get_bool("IsReleaseBranch"): + # Alpha longitudinal: clear if not available + if not CP.alphaLongitudinalAvailable: self.params.remove("AlphaLongitudinalEnabled") # BSM not available: clear BSM-dependent settings @@ -181,21 +180,23 @@ class UIStateSP: self.params.remove("NeuralNetworkLateralControl") self.params.remove("AlphaLongitudinalEnabled") - # No longitudinal control: no experimental mode + # No longitudinal control: no experimental mode or DEC if not has_long: self.params.remove("ExperimentalMode") + self.params.remove("DynamicExperimentalControl") # ICBM: clear if not available or if full longitudinal control is active if self.CP_SP is not None: if not self.CP_SP.intelligentCruiseButtonManagementAvailable or has_long: self.params.remove("IntelligentCruiseButtonManagement") + self.has_icbm = False else: self.params.remove("IntelligentCruiseButtonManagement") + self.has_icbm = False # Cruise features requiring longitudinal or ICBM - if not (has_long or has_icbm): + if not (has_long or self.has_icbm): self.params.remove("CustomAccIncrementsEnabled") - self.params.remove("DynamicExperimentalControl") self.params.remove("SmartCruiseControlVision") self.params.remove("SmartCruiseControlMap") diff --git a/selfdrive/ui/ui_state.py b/selfdrive/ui/ui_state.py index f7a5d44d9..64c0b88d1 100644 --- a/selfdrive/ui/ui_state.py +++ b/selfdrive/ui/ui_state.py @@ -74,7 +74,7 @@ class UIState(UIStateSP): # Core state variables self.is_metric: bool = self.params.get_bool("IsMetric") - self.is_release = self.params.get_bool("IsReleaseBranch") + self.is_release = False # self.params.get_bool("IsReleaseBranch") self.always_on_dm: bool = self.params.get_bool("AlwaysOnDM") self.started: bool = False self.ignition: bool = False diff --git a/sunnypilot/sunnylink/capabilities.py b/sunnypilot/sunnylink/capabilities.py index 9f22c47ad..933368713 100644 --- a/sunnypilot/sunnylink/capabilities.py +++ b/sunnypilot/sunnylink/capabilities.py @@ -94,7 +94,7 @@ def generate_capabilities(params: Params | None = None) -> dict: # Hardware + boolean params (no CarParams dependency) caps["device_type"] = HARDWARE.get_device_type() - caps["is_release"] = params.get_bool("IsReleaseBranch") + caps["is_release"] = False # params.get_bool("IsReleaseBranch") caps["is_sp_release"] = params.get_bool("IsReleaseSpBranch") caps["is_development"] = params.get_bool("IsDevelopmentBranch") caps["stock_longitudinal"] = params.get_bool("ToyotaEnforceStockLongitudinal") diff --git a/sunnypilot/sunnylink/settings_ui.json b/sunnypilot/sunnylink/settings_ui.json index bfb206238..b762ccb6a 100644 --- a/sunnypilot/sunnylink/settings_ui.json +++ b/sunnypilot/sunnylink/settings_ui.json @@ -574,19 +574,9 @@ "description": "Let the model decide when to use sunnypilot ACC or sunnypilot End to End Longitudinal.", "visibility": [ { - "type": "any", - "conditions": [ - { - "type": "capability", - "field": "has_longitudinal_control", - "equals": true - }, - { - "type": "capability", - "field": "has_icbm", - "equals": true - } - ] + "type": "capability", + "field": "has_longitudinal_control", + "equals": true } ], "enablement": [ @@ -1731,26 +1721,6 @@ "key": "JoystickDebugMode", "widget": "toggle", "title": "Joystick Debug Mode", - "visibility": [ - { - "type": "not", - "condition": { - "type": "any", - "conditions": [ - { - "type": "capability", - "field": "is_release", - "equals": true - }, - { - "type": "capability", - "field": "is_sp_release", - "equals": true - } - ] - } - } - ], "enablement": [ { "type": "offroad_only" @@ -1775,19 +1745,9 @@ { "type": "not", "condition": { - "type": "any", - "conditions": [ - { - "type": "capability", - "field": "is_release", - "equals": true - }, - { - "type": "capability", - "field": "is_sp_release", - "equals": true - } - ] + "type": "capability", + "field": "has_icbm", + "equals": true } } ] @@ -1900,19 +1860,9 @@ { "type": "not", "condition": { - "type": "any", - "conditions": [ - { - "type": "capability", - "field": "is_release", - "equals": true - }, - { - "type": "capability", - "field": "is_sp_release", - "equals": true - } - ] + "type": "capability", + "field": "is_sp_release", + "equals": true } } ], @@ -1947,11 +1897,6 @@ "condition": { "type": "any", "conditions": [ - { - "type": "capability", - "field": "is_release", - "equals": true - }, { "type": "capability", "field": "is_sp_release", diff --git a/sunnypilot/sunnylink/settings_ui_src/_macros.yaml b/sunnypilot/sunnylink/settings_ui_src/_macros.yaml index 3b755db92..a77172083 100644 --- a/sunnypilot/sunnylink/settings_ui_src/_macros.yaml +++ b/sunnypilot/sunnylink/settings_ui_src/_macros.yaml @@ -59,12 +59,7 @@ macros: - type: not condition: {type: capability, field: tesla_has_vehicle_bus, equals: true} - # Hide everything but a clearly-marked release branch (matches Raylib - # _is_release_branch = is_release OR is_sp_release). + # Hide on sunnypilot release branches (is_release is hardcoded False everywhere; is_sp_release is the active gate). release_branches_hide: - type: not - condition: - type: any - conditions: - - {type: capability, field: is_release, equals: true} - - {type: capability, field: is_sp_release, equals: true} + condition: {type: capability, field: is_sp_release, equals: true} diff --git a/sunnypilot/sunnylink/settings_ui_src/pages/cruise.yaml b/sunnypilot/sunnylink/settings_ui_src/pages/cruise.yaml index 795b5a017..3ef73e0fb 100644 --- a/sunnypilot/sunnylink/settings_ui_src/pages/cruise.yaml +++ b/sunnypilot/sunnylink/settings_ui_src/pages/cruise.yaml @@ -21,14 +21,7 @@ sections: title: Dynamic Experimental Control description: Let the model decide when to use sunnypilot ACC or sunnypilot End to End Longitudinal. visibility: - - type: any - conditions: - - type: capability - field: has_longitudinal_control - equals: true - - type: capability - field: has_icbm - equals: true + - $ref: '#/macros/longitudinal' enablement: - $ref: '#/macros/longitudinal' - key: DisengageOnAccelerator diff --git a/sunnypilot/sunnylink/settings_ui_src/pages/developer.yaml b/sunnypilot/sunnylink/settings_ui_src/pages/developer.yaml index 87d9d558b..b42720b43 100644 --- a/sunnypilot/sunnylink/settings_ui_src/pages/developer.yaml +++ b/sunnypilot/sunnylink/settings_ui_src/pages/developer.yaml @@ -26,8 +26,6 @@ sections: - key: JoystickDebugMode widget: toggle title: Joystick Debug Mode - visibility: - - $ref: '#/macros/release_branches_hide' enablement: - $ref: '#/macros/offroad' - key: AlphaLongitudinalEnabled @@ -46,14 +44,9 @@ sections: equals: true - type: not condition: - type: any - conditions: - - type: capability - field: is_release - equals: true - - type: capability - field: is_sp_release - equals: true + type: capability + field: has_icbm + equals: true enablement: - $ref: '#/macros/not_engaged' - key: ShowDebugInfo @@ -131,9 +124,6 @@ sections: condition: type: any conditions: - - type: capability - field: is_release - equals: true - type: capability field: is_sp_release equals: true diff --git a/sunnypilot/sunnylink/tests/test_compile_settings_ui.py b/sunnypilot/sunnylink/tests/test_compile_settings_ui.py index 6f30ef583..2fcd889ec 100644 --- a/sunnypilot/sunnylink/tests/test_compile_settings_ui.py +++ b/sunnypilot/sunnylink/tests/test_compile_settings_ui.py @@ -15,6 +15,7 @@ compiled output once the compiler has produced it. """ from __future__ import annotations +import difflib import json import os @@ -44,7 +45,16 @@ def committed() -> dict: class TestRoundtrip: def test_compiled_matches_committed(self, compiled, committed): """Compiled output must match the checked-in JSON.""" - assert compiled == committed + if compiled == committed: + return + diff = "\n".join(difflib.unified_diff( + json.dumps(committed, indent=2).splitlines(), + json.dumps(compiled, indent=2).splitlines(), + fromfile="settings_ui.json (committed)", + tofile="settings_ui.json (freshly compiled)", + lineterm="", + )) + pytest.fail(f"settings_ui.json schema mismatch — run compile_settings_ui.py\n\n{diff}") def test_committed_file_is_canonical(self): """Compiled output must byte-match the checked-in file (including trailing newline). @@ -53,7 +63,16 @@ class TestRoundtrip: rendered = json.dumps(schema, indent=2) + "\n" with open(DEFAULT_OUT) as f: current = f.read() - assert current == rendered, "settings_ui.json out of sync — run compile_settings_ui.py" + if current == rendered: + return + diff = "\n".join(difflib.unified_diff( + current.splitlines(), + rendered.splitlines(), + fromfile="settings_ui.json (on disk)", + tofile="settings_ui.json (freshly compiled)", + lineterm="", + )) + pytest.fail(f"settings_ui.json out of sync — run compile_settings_ui.py\n\n{diff}") class TestRefResolution: diff --git a/sunnypilot/sunnylink/tests/test_settings_changes.py b/sunnypilot/sunnylink/tests/test_settings_changes.py index 3d53ee1e7..07b05d4ac 100644 --- a/sunnypilot/sunnylink/tests/test_settings_changes.py +++ b/sunnypilot/sunnylink/tests/test_settings_changes.py @@ -181,17 +181,14 @@ class TestTorqueOptionGeneration: class TestReleaseBranchGates: @pytest.mark.parametrize("key", [ - "JoystickDebugMode", - "AlphaLongitudinalEnabled", "EnableGithubRunner", "QuickBootToggle", ]) def test_sp_dev_items_gate_on_is_sp_release(self, schema, key): - """SP dev items must hide on either release branch (is_release OR is_sp_release).""" + """sunnypilot dev items must hide on sunnypilot release branches (is_sp_release gate).""" item = _find_item(schema, key) assert item is not None, f"{key} not found in schema" rules = (item.get("visibility") or []) + (item.get("enablement") or []) - assert _references_capability_field(rules, "is_release"), f"{key} missing is_release gate" assert _references_capability_field(rules, "is_sp_release"), f"{key} missing is_sp_release gate"