feat(n7web): refine spatial UI and NFC-gated extension routing
This commit is contained in:
@@ -1331,7 +1331,7 @@ operations:
|
||||
self.assertIn('canvas.addEventListener("webglcontextlost"', app_script)
|
||||
self.assertIn('"cognitive-agent:module-change"', app_script)
|
||||
self.assertIn(
|
||||
'const CACHE_VERSION = "cognitive-agent-pad-v315-vue-vite"',
|
||||
'const CACHE_VERSION = "cognitive-agent-pad-v317-nfc-auth-routing"',
|
||||
service_worker,
|
||||
)
|
||||
self.assertIn('/console-v2.css?v=delivery-state-69', service_worker)
|
||||
@@ -2084,6 +2084,96 @@ operations:
|
||||
finally:
|
||||
SeatDemoHandler.extension = original_extension
|
||||
|
||||
def test_new_tcp_slot_is_immediately_parsed_but_blocked_until_nfc_binding(
|
||||
self,
|
||||
) -> None:
|
||||
original_extension = SeatDemoHandler.extension
|
||||
original_nfc = SeatDemoHandler.nfc
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
extension = SelfExtensionService(
|
||||
SimulationGateway(),
|
||||
catalog_db_path=Path(directory, "unbound-cactus.sqlite3"),
|
||||
)
|
||||
SeatDemoHandler.extension = extension
|
||||
SeatDemoHandler.nfc = SimpleNamespace(
|
||||
snapshot=lambda: {
|
||||
"revision": 1,
|
||||
"reader": {"online": True},
|
||||
"card": None,
|
||||
}
|
||||
)
|
||||
save_request = urllib.request.Request(
|
||||
f"{self.base_url}/api/extension/gscu/slots/11",
|
||||
method="PUT",
|
||||
headers={"Content-Type": "application/json"},
|
||||
data=json.dumps(
|
||||
{
|
||||
"device_id": "toy-cacti-002",
|
||||
"object_names": ["仙人掌"],
|
||||
"action_names": ["打开", "开启"],
|
||||
"source": "tcp",
|
||||
},
|
||||
ensure_ascii=False,
|
||||
).encode("utf-8"),
|
||||
)
|
||||
control_request = urllib.request.Request(
|
||||
f"{self.base_url}/api/requests",
|
||||
method="POST",
|
||||
headers={
|
||||
"Content-Type": "application/json",
|
||||
"Accept": "application/x-ndjson",
|
||||
},
|
||||
data=json.dumps(
|
||||
{
|
||||
"utterance": "打开仙人掌",
|
||||
"provider": "local",
|
||||
"conversation_id": "conv-unbound-cactus-e2e",
|
||||
"execution_mode": "hardware",
|
||||
"client_type": "web_console",
|
||||
},
|
||||
ensure_ascii=False,
|
||||
).encode("utf-8"),
|
||||
)
|
||||
try:
|
||||
with self.opener.open(save_request, timeout=3) as response:
|
||||
self.assertEqual(response.status, 200)
|
||||
with patch.object(
|
||||
extension,
|
||||
"execute_gateway",
|
||||
side_effect=AssertionError("unbound IR command must not be emitted"),
|
||||
):
|
||||
with self.opener.open(control_request, timeout=3) as response:
|
||||
events = [
|
||||
json.loads(line)
|
||||
for line in response.read().decode("utf-8").splitlines()
|
||||
if line.strip()
|
||||
]
|
||||
finally:
|
||||
SeatDemoHandler.extension = original_extension
|
||||
SeatDemoHandler.nfc = original_nfc
|
||||
|
||||
self.assertEqual(events[-1]["type"], "result")
|
||||
result = events[-1]["payload"]
|
||||
self.assertEqual(result["status"], "blocked")
|
||||
self.assertLess(result["local_control_elapsed_ms"], 1000)
|
||||
self.assertEqual(result["parsed_clauses"], ["打开仙人掌"])
|
||||
self.assertEqual(result["unresolved_clauses"], [])
|
||||
self.assertEqual(
|
||||
result["denied_peripheral_actions"][0]["reason"],
|
||||
"nfc_binding_required",
|
||||
)
|
||||
operation = next(
|
||||
operation
|
||||
for config in result["function_configs"].values()
|
||||
for operation in config["spec"]["operations"]
|
||||
)
|
||||
self.assertEqual(operation["target"]["device"], "toy-cacti-002")
|
||||
self.assertEqual(operation["parameters"], {"action": "打开", "slot": 11})
|
||||
self.assertEqual(result["operation_results"][0]["status"], "blocked")
|
||||
self.assertFalse(
|
||||
result["operation_results"][0]["telemetry"]["transport_submitted"]
|
||||
)
|
||||
|
||||
def test_main_request_routes_durable_nfc_peripheral_after_card_removal(self) -> None:
|
||||
original_extension = SeatDemoHandler.extension
|
||||
original_nfc = SeatDemoHandler.nfc
|
||||
|
||||
Reference in New Issue
Block a user