Files
Cognitive_Agent/tests/unit/test_frontend_vehicle_state_sync_contract.py
T

292 lines
11 KiB
Python

from __future__ import annotations
import json
from pathlib import Path
import shutil
import subprocess
import unittest
from cognitive_agent.application.conversation_state import ConversationStateStore
REPOSITORY_ROOT = Path(__file__).resolve().parents[2]
APP_SOURCE_PATH = REPOSITORY_ROOT / "apps" / "web-console" / "app.js"
EXTENSION_SOURCE_PATH = (
REPOSITORY_ROOT / "apps" / "web-console" / "self-extension.js"
)
def function_source(source: str, signature: str, next_signature: str) -> str:
start = source.index(signature)
end = source.index(next_signature, start)
return source[start:end]
class FrontendVehicleStateSyncContractTests(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
cls.app_source = APP_SOURCE_PATH.read_text(encoding="utf-8")
cls.extension_source = EXTENSION_SOURCE_PATH.read_text(encoding="utf-8")
def test_both_modules_use_the_same_browser_conversation(self) -> None:
key = "cognitive-agent.conversation-id"
self.assertIn(
f'sessionStorage.getItem("{key}")',
self.app_source,
)
self.assertIn(
f'sessionStorage.setItem("{key}", conversationId)',
self.app_source,
)
self.assertIn(
f'const CONVERSATION_KEY = "{key}"',
self.extension_source,
)
self.assertIn(
"body: JSON.stringify({ command, conversation_id: sharedConversationId() })",
self.extension_source,
)
def test_lan_http_origin_does_not_require_crypto_random_uuid(self) -> None:
id_source = function_source(
self.app_source,
"function createOpaqueId(prefix) {",
"\nfunction createConversationId",
)
self.assertIn("globalThis.crypto?.randomUUID", id_source)
self.assertIn("globalThis.crypto?.getRandomValues", id_source)
self.assertIn("Math.random()", id_source)
self.assertIn('return createOpaqueId("conv")', self.app_source)
self.assertIn('createOpaqueId("hwc")', self.app_source)
def test_extension_accepts_only_explicit_physical_ch1_state(self) -> None:
authority_source = function_source(
self.extension_source,
" function isAuthoritativeVehicleStatePayload(payload) {",
"\n function renderAuthoritativeVehicleState",
)
self.assertIn(
'payload.conversation_id !== sharedConversationId()', authority_source
)
self.assertIn(
"containsAuthoritativePhysicalCh1State(payload.actuator_state)",
authority_source,
)
self.assertIn(
"containsAuthoritativePhysicalCh1State(payload.domain_state)",
authority_source,
)
self.assertNotIn("physical_feedback_confirmed", authority_source)
summary_source = function_source(
self.extension_source,
" function renderAuthoritativeVehicleState(payload) {",
"\n function setMode",
)
self.assertNotIn(
"items.length === 1 && payload.physical_feedback_confirmed",
summary_source,
)
for state_path in (
"ventilation?.feedback_source",
"heating?.feedback_source",
"climate?.feedback_source",
"roof?.feedback_source",
"frontLeftWindow?.feedback_source",
):
self.assertIn(f'{state_path} === "physical_can_ch1"', summary_source)
def test_orchestration_renders_only_the_physical_ch1_patch(self) -> None:
apply_source = function_source(
self.app_source,
"function applyAuthoritativeVehicleState(payload) {",
'\nwindow.addEventListener("cognitive-agent:extension-vehicle-result"',
)
self.assertIn(
"const actuatorPatch = physicalCh1StatePatch(payload.actuator_state)",
apply_source,
)
self.assertIn(
"const domainPatch = physicalCh1StatePatch(payload.domain_state)",
apply_source,
)
self.assertIn("renderSeatState(actuatorPatch)", apply_source)
self.assertIn("renderDomainState(domainPatch)", apply_source)
self.assertIn("if (actuatorPatch?.driver)", apply_source)
self.assertNotIn("renderSeatState(payload.actuator_state)", apply_source)
self.assertNotIn("renderDomainState(payload.domain_state)", apply_source)
render_source = function_source(
self.app_source,
"function renderResult(result) {",
"\nasync function submitRequest",
)
ch1_branch = function_source(
render_source,
" if (ch1HardwareResult) {",
" updateTwinExplicitAngles",
)
self.assertIn("applyAuthoritativeVehicleState(result)", ch1_branch)
self.assertIn("} else {", ch1_branch)
self.assertIn("renderSeatState(result.actuator_state)", ch1_branch)
self.assertIn("renderDomainState(result.domain_state)", ch1_branch)
def test_physical_patch_does_not_promote_unmarked_sibling_domains(self) -> None:
node = shutil.which("node")
if node is None:
self.skipTest("Node.js is required to execute the frontend patch helper")
patch_source = function_source(
self.app_source,
"function physicalCh1StatePatch(value) {",
"\nfunction isAuthoritativeVehicleStatePayload",
)
state = {
"climate": {
"feedback_source": "physical_can_ch1",
"power": "on",
},
"roof": {"shade_position_pct": 100},
"window": {
"positions": {"front_left": {"position_pct": 50}}
},
}
script = (
f"{patch_source}\n"
f"const input = {json.dumps(state)};\n"
"process.stdout.write(JSON.stringify(physicalCh1StatePatch(input)));"
)
completed = subprocess.run(
[node, "-e", script],
check=True,
capture_output=True,
text=True,
)
self.assertEqual(
json.loads(completed.stdout),
{"climate": state["climate"]},
)
def test_ch1_mode_never_polls_the_legacy_ch0_seat_endpoint(self) -> None:
sync_source = function_source(
self.app_source,
"async function synchronizePhysicalSeatState() {",
"\nasync function loadAuthStatus()",
)
guard = sync_source.index(
'target_policy === "ch1_body_can_driver_only"'
)
legacy_request = sync_source.index("/api/hardware/seat-state")
self.assertLess(guard, legacy_request)
self.assertIn("return false", sync_source[guard:legacy_request])
def test_vehicle_selection_cannot_replay_unfiltered_state_in_ch1_mode(self) -> None:
select_source = function_source(
self.app_source,
"function selectVehicle(vehicleId, { silent = false } = {}) {",
"\nfunction populateVehicleSelector",
)
driver_branch = select_source.index("if (isDriverOnlyCh1Runtime())")
filtered_snapshot = select_source.index(
"state.vehicleStateSnapshot?.actuatorState",
driver_branch,
)
unfiltered_result = select_source.index("state.result?.actuator_state")
self.assertLess(driver_branch, filtered_snapshot)
self.assertLess(filtered_snapshot, unfiltered_result)
self.assertIn("} else if (state.result?.actuator_state)", select_source)
def test_driver_only_ch1_has_no_hidden_browser_lease_gate(self) -> None:
submit_source = function_source(
self.app_source,
"async function submitRequest(event) {",
"\nasync function copyArtifact",
)
self.assertIn("const driverOnlyCh1 = isDriverOnlyCh1Runtime()", submit_source)
self.assertIn("&& !driverOnlyCh1", submit_source)
self.assertIn(
'state.executionMode === "hardware" && !driverOnlyCh1',
submit_source,
)
startup_source = self.app_source[
self.app_source.index('document.addEventListener("DOMContentLoaded"') :
]
self.assertIn("if (!isDriverOnlyCh1Runtime())", startup_source)
self.assertIn("loadHardwareAccessStatus", startup_source)
def test_state_results_flow_in_both_directions(self) -> None:
self.assertIn(
'window.addEventListener("cognitive-agent:extension-vehicle-result"',
self.app_source,
)
self.assertIn(
'window.addEventListener("cognitive-agent:result"',
self.extension_source,
)
class PhysicalMarkerInvalidationContractTests(unittest.TestCase):
def test_logical_door_and_window_actions_replace_stale_physical_roots(self) -> None:
store = ConversationStateStore()
conversation_id = "conv-frontend-marker-invalidation"
store.synchronize_physical_ch1_feedback(
conversation_id,
[
{
"source": "physical_can_ch1",
"channel": 1,
"frame_id": "0x3B6",
"feedback_frame_id": "0x3B6",
"valid": True,
"verification": {
"authoritative": True,
"channel": 1,
"simulated": False,
"feedback_required": True,
"feedback_observed": True,
"feedback_match": True,
"frame_id": "0x3B6",
},
"domain_state": {
"door": {"locks": {"rear_left": {"state": "lock"}}},
"window": {
"positions": {
"front_left": {
"position_pct": 20,
"closed": False,
}
}
},
},
}
],
)
physical = store.snapshot(conversation_id)["domain_devices"]
self.assertEqual(physical["door"]["feedback_source"], "physical_can_ch1")
self.assertEqual(physical["window"]["feedback_source"], "physical_can_ch1")
updated = store.apply_successful_actions(
conversation_id,
"logical projection must not look physical",
[
{
"domain": "door",
"capability": "door.set_rear_lock",
"target": "rear",
"parameters": {"state": "unlock"},
},
{
"domain": "window",
"capability": "window.set_position",
"target": "front_left",
"parameters": {"position_pct": 60},
},
],
[],
)["domain_devices"]
self.assertEqual(updated["door"]["feedback_source"], "virtual")
self.assertEqual(updated["window"]["feedback_source"], "virtual")
if __name__ == "__main__":
unittest.main()