feat: synchronize CH1 vehicle control and feedback
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import copy
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
@@ -140,6 +141,62 @@ class NativeCanIntegrationTests(unittest.TestCase):
|
||||
).execute(self.runtime, plan, config)
|
||||
self.assertEqual(report["spec"]["status"], "failed")
|
||||
|
||||
def test_executor_ignores_stale_wrong_value_until_target_feedback_arrives(self) -> None:
|
||||
config, plan = self._compile(
|
||||
"climate",
|
||||
[
|
||||
{
|
||||
"domain": "climate",
|
||||
"capability": "climate.set_power",
|
||||
"target": "vehicle",
|
||||
"operation": "set",
|
||||
"parameters": {"state": "on"},
|
||||
}
|
||||
],
|
||||
)
|
||||
off = CanFrame(0x404, bytes((0, 2, 0, 0, 0, 0, 0, 0)), channel=1)
|
||||
on = CanFrame(0x404, bytes((0, 1, 0, 0, 0, 0, 0, 0)), channel=1)
|
||||
bus = _FakeBus([off, on])
|
||||
|
||||
with patch("cognitive_agent.application.native_can_runtime.time.sleep"):
|
||||
report = NativeCanExecutor(lambda: bus, feedback_timeout_ms=10).execute(
|
||||
self.runtime, plan, config
|
||||
)
|
||||
|
||||
telemetry = report["spec"]["results"][0]["telemetry"]
|
||||
self.assertEqual(report["spec"]["status"], "succeeded")
|
||||
self.assertTrue(telemetry["feedback_match"])
|
||||
self.assertEqual(telemetry["feedback_frame"]["data_hex"], "00 01 00 00 00 00 00 00")
|
||||
self.assertEqual(telemetry["channel"], 1)
|
||||
|
||||
def test_executor_refuses_to_send_without_value_match_contract(self) -> None:
|
||||
config, plan = self._compile(
|
||||
"climate",
|
||||
[
|
||||
{
|
||||
"domain": "climate",
|
||||
"capability": "climate.set_power",
|
||||
"target": "vehicle",
|
||||
"operation": "set",
|
||||
"parameters": {"state": "on"},
|
||||
}
|
||||
],
|
||||
)
|
||||
unsafe_plan = copy.deepcopy(plan)
|
||||
unsafe_plan["spec"]["commands"][0]["signals"]["expected_feedback"] = ""
|
||||
bus = _FakeBus()
|
||||
|
||||
report = NativeCanExecutor(lambda: bus, feedback_timeout_ms=1).execute(
|
||||
self.runtime, unsafe_plan, config
|
||||
)
|
||||
|
||||
self.assertEqual(report["spec"]["status"], "failed")
|
||||
self.assertFalse(bus.sent)
|
||||
self.assertIn(
|
||||
"target-value match contract",
|
||||
report["spec"]["results"][0]["message"],
|
||||
)
|
||||
|
||||
def test_one_sentence_builds_seat_and_vehicle_channel_plans(self) -> None:
|
||||
service = SeatDemoService(REPOSITORY_ROOT)
|
||||
result = service.process(
|
||||
@@ -154,6 +211,28 @@ class NativeCanIntegrationTests(unittest.TestCase):
|
||||
self.assertTrue(all(item["bus"] == "body_can" for item in body_commands))
|
||||
self.assertFalse(result["deferred_requests"])
|
||||
|
||||
def test_retired_vehicle_lock_intent_returns_explicit_unavailable_result(self) -> None:
|
||||
service = SeatDemoService(REPOSITORY_ROOT)
|
||||
for index, command in enumerate(("door vehicle lock", "door vehicle unlock")):
|
||||
with self.subTest(command=command):
|
||||
result = service.process(
|
||||
command,
|
||||
provider="local",
|
||||
conversation_id=f"conv-retired-door-lock-{index}",
|
||||
execution_mode="dry_run",
|
||||
)
|
||||
self.assertEqual(result["status"], "capability_unavailable")
|
||||
self.assertEqual(result["function_configs"], {})
|
||||
self.assertEqual(result["command_plans"], {})
|
||||
self.assertEqual(
|
||||
result["deferred_requests"][0]["rejection_code"],
|
||||
"CH1_DOOR_LOCK_CONTROL_UNSUPPORTED",
|
||||
)
|
||||
self.assertEqual(
|
||||
result["deferred_requests"][0]["execution_backend"],
|
||||
"unsupported",
|
||||
)
|
||||
|
||||
def test_vehicle_timing_contract_matches_requested_60mhz_values(self) -> None:
|
||||
settings = VehicleCanSettings.from_env(Path(REPOSITORY_ROOT))
|
||||
self.assertTrue(settings.timing_is_verified)
|
||||
|
||||
Reference in New Issue
Block a user