From cd928caf948b342b9fd57c606cc8f93060b2e630 Mon Sep 17 00:00:00 2001 From: Sylvester Kaczmarek <16242628+sylvesterkaczmarek@users.noreply.github.com> Date: Mon, 31 Aug 2026 16:04:50 +0100 Subject: [PATCH 1/2] Handle v2-only registration fields in v1 downgrade --- .../translator/proto_to_proto_translator.py | 17 ++++++ tests/test_proto_to_proto_translator.py | 57 +++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 tests/test_proto_to_proto_translator.py diff --git a/sapient_apex_server/translator/proto_to_proto_translator.py b/sapient_apex_server/translator/proto_to_proto_translator.py index 609d2a1..6f209c0 100644 --- a/sapient_apex_server/translator/proto_to_proto_translator.py +++ b/sapient_apex_server/translator/proto_to_proto_translator.py @@ -166,13 +166,30 @@ def _registration_translate_v2_to_v1(message_dict: dict) -> bool: # value back from CommandType enum instead mode_definitions = registration_dict.get("mode_definition", []) + v2_only_command_types = { + "COMMAND_TYPE_MOVE_TO", + "COMMAND_TYPE_PATROL", + "COMMAND_TYPE_FOLLOW", + } + for mode_definition in mode_definitions: _convert_repeated_to_single(mode_definition, "detection_definition") _convert_single_to_repeated(mode_definition, "task") + # Extensible taxonomy docking was introduced in V2 and has no V1 representation. + detection_definition = mode_definition.get("detection_definition", {}) + detection_classes = detection_definition.get("detection_class_definition", []) + for detection_class in detection_classes: + _remove_fields(detection_class, ["taxonomy_dock_definition"]) + tasks = mode_definition.get("task", []) for task in tasks: commands = task.get("command", []) + # Mobile-node commands were introduced in V2. Drop these capability declarations + # when downgrading because the V1 command enum cannot represent them. + commands[:] = [ + command for command in commands if command.get("type") not in v2_only_command_types + ] for command in commands: if "type" in command: # Get the string representation of the type enum diff --git a/tests/test_proto_to_proto_translator.py b/tests/test_proto_to_proto_translator.py new file mode 100644 index 0000000..a2e067e --- /dev/null +++ b/tests/test_proto_to_proto_translator.py @@ -0,0 +1,57 @@ +# +# Copyright (c) 2019-2024 Roke Manor Research Ltd +# + +from google.protobuf.json_format import MessageToDict, ParseDict + +from sapient_apex_server.translator.proto_to_proto_translator import translate_v2_to_v1 +from sapient_msg.bsi_flex_335_v2_0.sapient_message_pb2 import SapientMessage + + +def test_v2_registration_downgrade_omits_v2_only_taxonomy_and_commands(): + message = ParseDict( + { + "registration": { + "icd_version": "BSI Flex 335 v2.0", + "mode_definition": [ + { + "detection_definition": [ + { + "detection_class_definition": [ + { + "taxonomy_dock_definition": [ + { + "Dock_class_namespace": "sapient_core", + "Dock_class": "Land Vehicle.2 Wheels.Other", + } + ] + } + ] + } + ], + "task": { + "command": [ + {"type": "COMMAND_TYPE_MOVE_TO"}, + {"type": "COMMAND_TYPE_PATROL"}, + {"type": "COMMAND_TYPE_FOLLOW"}, + {"type": "COMMAND_TYPE_LOOK_AT"}, + ] + }, + } + ], + } + }, + SapientMessage(), + ) + + downgraded = translate_v2_to_v1(message) + registration = MessageToDict(downgraded, preserving_proto_field_name=True)["registration"] + + assert registration["icd_version"] == "BSI Flex 335 v1.0" + detection_definition = registration["mode_definition"][0]["detection_definition"] + detection_class = detection_definition["detection_class_definition"][0] + assert "taxonomy_dock_definition" not in detection_class + + commands = registration["mode_definition"][0]["task"][0]["command"] + assert [command["type"] for command in commands] == ["COMMAND_TYPE_LOOK_AT"] + assert commands[0]["name"] == "LookAt" From 1518d3004aab2293a35a4c7afb8d9a991a998803 Mon Sep 17 00:00:00 2001 From: Sylvester Kaczmarek <16242628+sylvesterkaczmarek@users.noreply.github.com> Date: Sat, 12 Sep 2026 15:08:03 +0100 Subject: [PATCH 2/2] Drop v2-only region types during downgrade --- .../translator/proto_to_proto_translator.py | 12 ++++++++++++ tests/test_proto_to_proto_translator.py | 12 +++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/sapient_apex_server/translator/proto_to_proto_translator.py b/sapient_apex_server/translator/proto_to_proto_translator.py index 6f209c0..f93c5af 100644 --- a/sapient_apex_server/translator/proto_to_proto_translator.py +++ b/sapient_apex_server/translator/proto_to_proto_translator.py @@ -171,6 +171,10 @@ def _registration_translate_v2_to_v1(message_dict: dict) -> bool: "COMMAND_TYPE_PATROL", "COMMAND_TYPE_FOLLOW", } + v2_only_region_types = { + "REGION_TYPE_MOBILE_NODE_NO_GO_AREA", + "REGION_TYPE_MOBILE_NODE_GO_AREA", + } for mode_definition in mode_definitions: _convert_repeated_to_single(mode_definition, "detection_definition") @@ -184,6 +188,14 @@ def _registration_translate_v2_to_v1(message_dict: dict) -> bool: tasks = mode_definition.get("task", []) for task in tasks: + region_definition = task.get("region_definition", {}) + region_types = region_definition.get("region_type", []) + region_types[:] = [ + region_type + for region_type in region_types + if region_type not in v2_only_region_types + ] + commands = task.get("command", []) # Mobile-node commands were introduced in V2. Drop these capability declarations # when downgrading because the V1 command enum cannot represent them. diff --git a/tests/test_proto_to_proto_translator.py b/tests/test_proto_to_proto_translator.py index a2e067e..459499b 100644 --- a/tests/test_proto_to_proto_translator.py +++ b/tests/test_proto_to_proto_translator.py @@ -30,6 +30,13 @@ def test_v2_registration_downgrade_omits_v2_only_taxonomy_and_commands(): } ], "task": { + "region_definition": { + "region_type": [ + "REGION_TYPE_AREA_OF_INTEREST", + "REGION_TYPE_MOBILE_NODE_NO_GO_AREA", + "REGION_TYPE_MOBILE_NODE_GO_AREA", + ] + }, "command": [ {"type": "COMMAND_TYPE_MOVE_TO"}, {"type": "COMMAND_TYPE_PATROL"}, @@ -52,6 +59,9 @@ def test_v2_registration_downgrade_omits_v2_only_taxonomy_and_commands(): detection_class = detection_definition["detection_class_definition"][0] assert "taxonomy_dock_definition" not in detection_class - commands = registration["mode_definition"][0]["task"][0]["command"] + task = registration["mode_definition"][0]["task"][0] + assert task["region_definition"]["region_type"] == ["REGION_TYPE_AREA_OF_INTEREST"] + + commands = task["command"] assert [command["type"] for command in commands] == ["COMMAND_TYPE_LOOK_AT"] assert commands[0]["name"] == "LookAt"