Skip to content

fix(vitals): fall back to the body component list for telemetry state - #14

Merged
enkerewpo merged 3 commits into
syswonder:mainfrom
lwxcd:fix/local-deployment
Oct 22, 2026
Merged

enkerewpo merged 3 commits into
syswonder:mainfrom
lwxcd:fix/local-deployment

Conversation

@lwxcd

@lwxcd lwxcd commented Oct 16, 2026

Copy link
Copy Markdown
Contributor

Problem

Components without scalar telemetry (lidar, IMU, camera, audio) read "unknown" forever in the client: they emit no Vitals signals, and the robot health source does not populate a per-component health field either.

Changes

  • Collects enabled from the Soma body component list (body.components[].enabled).
  • When there is no direct health and no telemetry, maps enabled → ok/error; detail: "component reported offline by the robot health source" when absent.
  • In this path sourceComponentId points at the component; all other paths unchanged.

Validation

  • .venv/bin/python -m unittest tests.test_vitals_transport -v — 16 passed.
  • Live stack: 5 formerly-unknown components all show explicit ok (probe + dashboard WebSocket); 8/8 definite after the companion robot_audio liveness change.
  • python3 scripts/check_commit_authorship.py --base origin/main --head HEAD — passed.

Compatibility

Additive; wire schema and frontend bundle unchanged; no config/migration.

Components without scalar telemetry (lidar, IMU, camera, audio) stayed
"unknown" forever in the dashboard. Read the enabled flag of the body
component entries instead and map it to ok/error, with an explicit
detail when the robot reports a component offline.

Assisted-by: Claude-Code:deepseek-flash
Signed-off-by: lwxcd <l1393452711@gmail.com>

@enkerewpo enkerewpo left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested end to end: real Vitals conversion (snapshot_to_vitals in robonix system/vitals) → vitals_snapshot_to_dict on main (d368173) vs this branch (e1e3d92).

Soma reports main this PR
sensor OK, online unknown ok
sensor ERROR, online, no fault entry unknown ok
sensor offline unknown error
joint torque off warn warn

Existing 16 tests pass; none covers the new path.

Fix:

  1. Address the inline comments and add tests for the fallback.
  2. Follow-up in robonix: Vitals should forward ComponentStatus.health as a signal. The faulted-but-online case is then covered.
Logs

Vitals output:

PROBE_SIGNAL body/arm/joint_2/torque_enabled health=1 detail="body/arm/joint_2 torque is disabled"
PROBE_BODYCOMP body=computer_jetson id=body/computer_jetson/lidar_ok kind=sensor enabled=true error_code=0
PROBE_BODYCOMP body=computer_jetson id=body/computer_jetson/lidar_err kind=sensor enabled=true error_code=0
PROBE_BODYCOMP body=computer_jetson id=body/computer_jetson/lidar_off kind=sensor enabled=false error_code=0
PROBE_BODYCOMP body=computer_jetson id=body/computer_jetson/lidar_nohealth kind=sensor enabled=true error_code=0
PROBE_BODYCOMP body=arm id=body/arm/joint_2 kind=joint enabled=false error_code=0

Client output:

== main d368173
body/computer_jetson/cpu                 health=ok       detail=''
body/computer_jetson/lidar_ok            health=unknown  detail=''
body/computer_jetson/lidar_err           health=unknown  detail=''
body/computer_jetson/lidar_off           health=unknown  detail=''
body/computer_jetson/lidar_nohealth      health=unknown  detail=''
body/arm/joint_2                         health=warn     detail='body/arm/joint_2 torque is disabled'
== pr e1e3d92
body/computer_jetson/cpu                 health=ok       detail=''
body/computer_jetson/lidar_ok            health=ok       detail=''
body/computer_jetson/lidar_err           health=ok       detail=''
body/computer_jetson/lidar_off           health=error    detail='component reported offline by the robot health source'
body/computer_jetson/lidar_nohealth      health=ok       detail=''
body/arm/joint_2                         health=warn     detail='body/arm/joint_2 torque is disabled'

Comment thread src/robonix_client/vitals_transport.py Outdated
Comment on lines +376 to +379
# Components with no scalar telemetry (this deployment's lidar, imu,
# camera and audio) would otherwise read "unknown" forever; fall back
# to the online/present flag the robot's health source reports for
# them in the body component list.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment describes one specific robot. Please describe the rule instead, e.g. "Components without telemetry fall back to their online flag; ok only means the component is online."

Comment thread src/robonix_client/vitals_transport.py Outdated
Comment on lines +381 to +383
if body_enabled[component_id]:
direct_health = "ok"
direct_visual_state = "ok"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Being online does not mean healthy. If Soma reports a sensor as ERROR while it is still online, this shows it as ok. Please add a detail so users can tell the difference:

detail = "online, no health data"

@enkerewpo

Copy link
Copy Markdown
Member

Upstream follow-up for the faulted-but-online case: syswonder/robonix#278

The body-component-list fallback maps an online component to "ok", but
online does not mean healthy: a sensor that Soma reports as ERROR while
still online is indistinguishable from a healthy one. Set an explicit
"online, no health data" detail in this path so the two cases can be
told apart, and describe the fallback rule in the comment rather than
one deployment's component list. Add tests covering the online, offline
and direct-telemetry-precedence cases.

Assisted-by: Claude-Code:deepseek-flash
Signed-off-by: lwxcd <l1393452711@gmail.com>
@enkerewpo

Copy link
Copy Markdown
Member

Thanks for the update; the inline points are addressed. One rule is still off: the fallback treats enabled: false as offline and enabled: true as online for every component, but the flag does not mean that.

  • For an actuator (arm, leg, joint, wheel, gripper, end_effector) Vitals' enabled is torque, not presence. A joint with torque on is shown ok, one with torque off error; neither says anything about health.
  • Soma reports a component that nothing has observed yet as offline. So enabled: false cannot tell "offline" from "never seen", and right after boot every unobserved sensor turns red.

Change: only a non-actuator that is explicitly enabled: true counts as online (ok, detail online, no health data); everything else stays unknown. Tests: an unobserved component stays unknown, and an actuator's torque flag is ignored.

The patch below applies on d251786 (git apply); the 20 tests in tests/test_vitals_transport.py pass with it.

Patch
diff --git a/src/robonix_client/vitals_transport.py b/src/robonix_client/vitals_transport.py
index f13c835..197c4c3 100644
--- a/src/robonix_client/vitals_transport.py
+++ b/src/robonix_client/vitals_transport.py
@@ -29,6 +29,9 @@ VITALS_MODULES_GET_PATH = (
     "/robonix.contracts.RobonixSystemVitalsModulesGet/GetModuleHealthSnapshot"
 )
 
+# Body component kinds whose `enabled` is torque, not presence.
+ACTUATOR_KINDS = frozenset({"arm", "leg", "joint", "wheel", "gripper", "end_effector"})
+
 HEALTH_SEVERITY = {
     "unknown": 0,
     "ok": 1,
@@ -347,11 +350,21 @@ def aggregate_component_health(
         if match:
             body_health[match] = str(body.get("health") or "unknown")
 
-    body_enabled: dict[str, bool] = {}
+    # Vitals' `enabled` is torque for an actuator and present-and-online for
+    # anything else, and Soma reports a component nothing has observed as
+    # offline. So only a non-actuator that is explicitly enabled says
+    # anything: it is online. False means "offline" or "never observed"
+    # alike, and stays unknown.
+    online: set[str] = set()
     for body in bodies:
         for component in body.get("components") or []:
-            if isinstance(component, dict) and component.get("id"):
-                body_enabled[str(component["id"])] = bool(component.get("enabled"))
+            if (
+                isinstance(component, dict)
+                and component.get("id")
+                and component.get("enabled") is True
+                and str(component.get("kind") or "") not in ACTUATOR_KINDS
+            ):
+                online.add(str(component["id"]))
 
     rows: dict[str, dict[str, Any]] = {}
     for component in components:
@@ -373,17 +386,11 @@ def aggregate_component_health(
         )
         detail = str(worst_signal.get("detail") or "")
         source_component_id = component_id if direct_values else ""
-        # Components without telemetry fall back to their online flag;
-        # `ok` only means the component is online.
-        if direct_health == "unknown" and component_id in body_enabled:
-            if body_enabled[component_id]:
-                direct_health = "ok"
-                direct_visual_state = "ok"
-                detail = "online, no health data"
-            else:
-                direct_health = "error"
-                direct_visual_state = "error"
-                detail = "component reported offline by the robot health source"
+        # Without telemetry, `ok` only means the component is online.
+        if direct_health == "unknown" and component_id in online:
+            direct_health = "ok"
+            direct_visual_state = "ok"
+            detail = "online, no health data"
             source_component_id = component_id
         rows[component_id] = {
             "componentId": component_id,
diff --git a/tests/test_vitals_transport.py b/tests/test_vitals_transport.py
index f257bb6..2442785 100644
--- a/tests/test_vitals_transport.py
+++ b/tests/test_vitals_transport.py
@@ -392,7 +392,9 @@ class ComponentHealthTest(unittest.TestCase):
         self.assertEqual(camera["detail"], "online, no health data")
         self.assertEqual(camera["sourceComponentId"], "body/head_camera")
 
-    def test_treats_component_disabled_by_health_source_as_offline(self):
+    def test_keeps_unobserved_component_unknown(self):
+        """Soma reports a component nothing observed as offline, so a false
+        `enabled` cannot tell offline from never seen."""
         rows = aggregate_component_health(
             self.description,
             [],
@@ -405,15 +407,25 @@ class ComponentHealthTest(unittest.TestCase):
             ],
         )
         health = {row["componentId"]: row for row in rows}
+        self.assertEqual(health["body/head_camera"]["health"], "unknown")
 
-        camera = health["body/head_camera"]
-        self.assertEqual(camera["health"], "error")
-        self.assertEqual(camera["directHealth"], "error")
-        self.assertEqual(
-            camera["detail"],
-            "component reported offline by the robot health source",
+    def test_ignores_actuator_torque_flag(self):
+        """An actuator's `enabled` is torque; torque on says nothing about health."""
+        rows = aggregate_component_health(
+            self.description,
+            [],
+            [
+                {
+                    "key": "body",
+                    "health": "ok",
+                    "components": [
+                        {"id": "body/head_camera", "enabled": True, "kind": "gripper"}
+                    ],
+                }
+            ],
         )
-        self.assertEqual(camera["sourceComponentId"], "body/head_camera")
+        health = {row["componentId"]: row for row in rows}
+        self.assertEqual(health["body/head_camera"]["health"], "unknown")
 
     def test_direct_telemetry_takes_precedence_over_online_flag(self):
         signals = [

Soma reports a component that nothing has observed as offline, so a
false `enabled` cannot distinguish offline from never seen, and marking
it as error turns every unobserved sensor red after boot. Treat only an
explicitly enabled non-actuator as online when it has no telemetry;
actuator `enabled` is torque, so ignore it and stay unknown. Update the
tests for the unobserved and actuator-torque cases.

Assisted-by: Claude-Code:deepseek-flash
Signed-off-by: lwxcd <l1393452711@gmail.com>
@lwxcd

lwxcd commented Oct 22, 2026

Copy link
Copy Markdown
Contributor Author

Thanks — applied. Only non-actuators with enabled: true now count as online; unobserved components and actuator torque flags stay unknown. Added the two tests you asked for; the vitals transport tests pass.

@enkerewpo

Copy link
Copy Markdown
Member

Thanks

@enkerewpo
enkerewpo merged commit eb63cf0 into syswonder:main Oct 22, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants