From 86526335956a01f7dec4d8d69fa8f42d724691bf Mon Sep 17 00:00:00 2001 From: mikecarper Date: Mon, 21 Sep 2026 16:29:49 -0700 Subject: [PATCH] fix(ci): keep KISS artifacts outside OTA gate --- build.sh | 21 ++++++++++++++++----- test/test_message_navigation.py | 6 ++++++ test/test_release_ota_policy.sh | 11 +++++++++++ 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/build.sh b/build.sh index 2a335037e..262c7eeb4 100755 --- a/build.sh +++ b/build.sh @@ -2035,6 +2035,16 @@ is_kiss_modem_target() { esac } +requires_wireless_self_update() { + # KISS firmware is a host-controlled radio modem, not a standalone node. + # It deliberately has no application updater: the connected host performs + # any firmware maintenance over its wired programming interface. Building + # it with --include-kiss must not misrepresent that as an OTA regression. + [ "${REQUIRE_OTA_UPDATES:-0}" = "1" ] \ + && ! is_companion_build "$1" \ + && ! is_kiss_modem_target "$1" +} + is_bluetooth_target() { case "$(get_variant_name_for_env "$1")" in companion_radio_ble|*_companion_radio_ble) @@ -4067,7 +4077,7 @@ write_build_capability_manifest() { ) local item - if [ "${REQUIRE_OTA_UPDATES:-0}" = "1" ] && ! is_companion_build "$env_name"; then + if requires_wireless_self_update "$env_name"; then checker_args+=(--require-ota) fi if [ "$env_platform" = "ESP32_PLATFORM" ]; then @@ -4170,8 +4180,9 @@ output_artifact_exists() { } build_artifacts_exist() { - local env_platform=$1 - local firmware_filename=$2 + local env_name=$1 + local env_platform=$2 + local firmware_filename=$3 output_artifact_exists "${firmware_filename}.capabilities.json" || return 1 python3 scripts/firmware_memory_manifest.py validate-package \ @@ -4190,7 +4201,7 @@ proven = {(item.get("capability"), item.get("evidence")) required = {tuple(value.split("=", 1)) for value in sys.argv[2:]} sys.exit(0 if required <= proven else 1) PY - if [ "${REQUIRE_OTA_UPDATES:-0}" = "1" ]; then + if requires_wireless_self_update "$env_name"; then python3 - "${OUTPUT_DIR}/${firmware_filename}.capabilities.json" <<'PY' || return 1 import json, sys manifest = json.load(open(sys.argv[1])) @@ -4496,7 +4507,7 @@ build_firmware() { local embedded_version_string="${firmware_version}${embedded_build_suffix}${embedded_variant_tag}-${commit_hash}" declare_full_logging_application_contract "$env_name" - if [ "$RESUME_BUILD_OUTPUT" == "1" ] && build_artifacts_exist "$env_platform" "$firmware_filename"; then + if [ "$RESUME_BUILD_OUTPUT" == "1" ] && build_artifacts_exist "$env_name" "$env_platform" "$firmware_filename"; then echo "Skipping ${env_name}; existing artifacts found for ${firmware_filename}." return 0 fi diff --git a/test/test_message_navigation.py b/test/test_message_navigation.py index 884db6989..2f5068c27 100644 --- a/test/test_message_navigation.py +++ b/test/test_message_navigation.py @@ -366,6 +366,12 @@ class MessageNavigationTest(unittest.TestCase): home = source[source.index("class HomeScreen :"):] home_navigation = home[home.index(" bool handleInput(char c) override {"):] home_navigation = home_navigation.split("#ifdef COMPANION_EXCLUSIVE_WIFI_BLE", 1)[0] + # This focused navigation harness intentionally omits HomeScreen's + # radio-page timing state. Entering the radio page resets that state + # in production, but it is unrelated to the button routing exercised + # below, so remove only that call from the extracted fragment. + home_navigation = home_navigation.replace( + "if (_page == HomePage::RADIO) resetRadioProfileDisplayPage();\n", "") home_navigation = home_navigation.replace("{\n", "{\n Screen::handleInput(c);\n", 1) implementation += ("class HomeScreen : public Screen { public: UITask* _task; " "enum HomePage {FIRST,MESSAGES,RECENT,RADIO,DISCOVERY,Count}; int _page=0; " diff --git a/test/test_release_ota_policy.sh b/test/test_release_ota_policy.sh index e91bff1d1..c6561685b 100644 --- a/test/test_release_ota_policy.sh +++ b/test/test_release_ota_policy.sh @@ -27,6 +27,17 @@ resolve_command_targets build-firmwares-logging-matrix >/dev/null || fail "USB-updated Companion was excluded" [ "${#OTA_EXCLUDED_TARGETS[@]}" = 2 ] || fail "missing exclusion report" +# KISS is a host-controlled modem, so including it in a logging build does +# not turn it into a self-updating infrastructure node. Its cable-only +# maintenance path must not reject an otherwise valid KISS artifact. +REQUIRE_OTA_UPDATES=1 +requires_wireless_self_update Heltec_t096_kiss_modem \ + && fail "KISS modem incorrectly requires wireless self-update" +requires_wireless_self_update nrf_repeater \ + || fail "standalone nRF repeater lost wireless self-update requirement" +requires_wireless_self_update esp_companion_radio_full \ + && fail "Companion incorrectly requires wireless self-update" + parse_cli_options build-firmwares-logging-matrix --allow-no-ota resolve_command_targets "${PARSED_COMMAND_ARGS[@]}" >/dev/null [ "${#RESOLVED_BUILD_TARGETS[@]}" = 5 ] || fail "development override lost targets"