feat(k1): complete canonical control lifecycle

This commit is contained in:
DCCONSTRUCTIONS
2026-07-19 01:07:02 +03:00
parent d7a2c22faf
commit ffffee1879
42 changed files with 3577 additions and 556 deletions
+145 -20
View File
@@ -31,7 +31,7 @@ from k1link.device_plugins.xgrids_k1.protocol.application_bootstrap import (
ATTESTATION = CompatibilityAttestationRequest(
firmware_version="3.0.2",
topology="direct-lan",
operator_confirmed=True,
verification="live-device-info",
)
PRIMARY_TEST_CREDENTIAL = "x" * 24
SECONDARY_TEST_CREDENTIAL = "y" * 24
@@ -120,12 +120,11 @@ class FakeInteractiveControlSession:
self.state = "workspace-ready"
self.start_projects: list[str] = []
self.stop_calls = 0
self.confirm_calls = 0
def snapshot(self) -> dict[str, object]:
return {
"state": self.state,
"can_confirm_standby": self.state == "awaiting-standby-confirmation",
"can_confirm_standby": False,
}
def open_project_prompt(self) -> dict[str, object]:
@@ -147,12 +146,6 @@ class FakeInteractiveControlSession:
self.state = "awaiting-standby-confirmation"
return self.snapshot()
def confirm_standby(self) -> dict[str, object]:
assert self.state == "awaiting-standby-confirmation"
self.confirm_calls += 1
self.state = "completed"
return self.snapshot()
def close_prestart(self) -> dict[str, object]:
self.state = "closed"
return self.snapshot()
@@ -211,6 +204,8 @@ def test_prepare_creates_provisional_device_session_and_profiled_acquisition(
assert state["device_ref"]["device_id"] != state["device_session"]["device_session_id"]
assert state["acquisition"]["state"] == "prepared"
assert state["acquisition"]["project_name"] == PROJECT_NAME
assert state["acquisition"]["mount_type"] == "handheld"
assert state["acquisition"]["gnss_mode"] == "none"
assert state["acquisition"]["compatibility_profile_id"] == (XGRIDS_K1_COMPATIBILITY_PROFILE_ID)
assert state["compatibility"]["vendor_writes_enabled"] is False
@@ -230,6 +225,29 @@ def test_project_name_is_normalized_and_control_characters_are_rejected() -> Non
host="192.168.1.20",
compatibility_attestation=ATTESTATION,
)
def test_only_physically_accepted_configuration_values_are_admitted() -> None:
with pytest.raises(ValidationError):
ConnectRequest(
device_id="synthetic-device",
ssid="synthetic-network",
password=SecretStr(PRIMARY_TEST_CREDENTIAL),
connection_mode="quick-connect", # type: ignore[arg-type]
compatibility_attestation=ATTESTATION,
)
with pytest.raises(ValidationError):
PrepareAcquisitionRequest(
project_name=PROJECT_NAME,
host="192.168.1.20",
mount_type="uav", # type: ignore[arg-type]
compatibility_attestation=ATTESTATION,
)
with pytest.raises(ValidationError):
PrepareAcquisitionRequest(
project_name=PROJECT_NAME,
host="192.168.1.20",
gnss_mode="rtk", # type: ignore[arg-type]
compatibility_attestation=ATTESTATION,
)
def test_facade_arms_bounded_shadow_lease_without_installing_publish_transport(
@@ -247,7 +265,8 @@ def test_facade_arms_bounded_shadow_lease_without_installing_publish_transport(
service._compatibility_attestation = { # noqa: SLF001
"firmware_version": "3.0.2",
"topology": "direct-lan",
"basis": "operator-attested",
"verification": "live-device-info",
"basis": "selected-profile-live-device-info-required",
"observed_at": "2026-07-18T00:00:00Z",
}
@@ -274,7 +293,7 @@ def test_facade_arms_bounded_shadow_lease_without_installing_publish_transport(
assert disarmed["application_control_execution"]["lease"] is None
def test_shadow_arm_requires_idle_connected_attested_device_before_keychain_read(
def test_shadow_arm_requires_idle_connected_profile_selected_device_before_keychain_read(
tmp_path: Path,
) -> None:
loader = FakeApplicationAuthorityLoader()
@@ -405,21 +424,82 @@ def test_plugin_commanded_acquisition_keeps_start_and_stop_as_explicit_actions(
physical_acceptance=PHYSICAL_ACCEPTANCE,
)
)
stop_operation = stopping["last_operation"]
assert control.stop_calls == 1
assert stopping["acquisition"]["state"] == "awaiting_external_stop"
assert stopping["last_operation"]["status"] == "running"
completed = service.stop_acquisition(
control.state = "completed"
completed = service.state()
assert control.stop_calls == 1
assert completed["acquisition"]["state"] == "completed"
assert completed["acquisition"]["result"]["device_state"] == "ready"
assert completed["last_operation"]["status"] == "succeeded"
assert runtime.stop_calls == 1
def test_device_standby_retires_sources_after_terminal_local_stop_failure(
tmp_path: Path,
) -> None:
service, runtime = service_with_fake_runtime(tmp_path)
control = FakeInteractiveControlSession()
service._application_control_session = control # type: ignore[assignment] # noqa: SLF001
service._k1_ip = "192.168.1.20" # noqa: SLF001
service._compatibility_attestation = {"profile": "exact"} # noqa: SLF001
prepared = service.prepare_acquisition(
PrepareAcquisitionRequest(
project_name="TEST001",
host="192.168.1.20",
compatibility_attestation=ATTESTATION,
)
)
acquisition_id = prepared["acquisition"]["acquisition_id"]
service.start_acquisition(
StartAcquisitionRequest(
acquisition_id=acquisition_id,
physical_acceptance=PHYSICAL_ACCEPTANCE,
)
)
runtime.mark_ready()
runtime.pcl_frames = 1
service.state()
stopping = service.stop_acquisition(
StopAcquisitionRequest(
acquisition_id=acquisition_id,
mode="graceful",
operator_confirmed=True,
operation_id=stop_operation["operation_id"],
physical_acceptance=PHYSICAL_ACCEPTANCE,
)
)
stop_operation = stopping["last_operation"]
with service._lock: # noqa: SLF001
assert service._acquisition is not None # noqa: SLF001
service._acquisition.transition( # noqa: SLF001
"failed",
message_code="acquisition.camera_failed",
result={"camera_failure_code": "camera-source-ended"},
)
service._operations.transition( # noqa: SLF001
stop_operation["operation_id"],
"failed",
stage_code="runtime-failed",
message_code="acquisition.stop.runtime_failed",
error={
"category": "stream",
"code": "runtime-failed",
"retryable": False,
"safe_to_retry": False,
"side_effect_status": "unknown",
},
)
control.state = "completed"
recovered = service.state()
assert control.stop_calls == 1
assert control.confirm_calls == 1
assert completed["acquisition"]["state"] == "completed"
assert control.state == "completed"
assert recovered["acquisition"]["state"] == "failed"
assert recovered["application_control_session"]["state"] == "completed"
assert runtime.stop_calls == 1
@@ -1257,7 +1337,7 @@ def test_prepare_rejects_stream_subsets_and_duplicates(
)
def test_exact_profile_is_inactive_until_explicit_operator_attestation(
def test_exact_profile_is_inactive_until_selected_for_live_device_info_verification(
tmp_path: Path,
) -> None:
service, _ = service_with_fake_runtime(tmp_path)
@@ -1267,7 +1347,7 @@ def test_exact_profile_is_inactive_until_explicit_operator_attestation(
"profile_id": None,
"decision": "unknown",
"permitted_mode": "evidence-only",
"firmware_claim": "exact-3.0.2-profile-not-attested",
"firmware_claim": "exact-3.0.2-profile-not-selected",
"attestation": None,
"vendor_writes_enabled": False,
"camera_preview": "unverified",
@@ -1284,7 +1364,9 @@ def test_exact_profile_is_inactive_until_explicit_operator_attestation(
assert attested["compatibility"]["profile_id"] == XGRIDS_K1_COMPATIBILITY_PROFILE_ID
assert attested["compatibility"]["decision"] == "limited"
assert attested["compatibility"]["attestation"]["basis"] == "operator-attested"
assert attested["compatibility"]["attestation"]["basis"] == (
"selected-profile-live-device-info-required"
)
assert attested["device_session"]["compatibility_profile_id"] == (
XGRIDS_K1_COMPATIBILITY_PROFILE_ID
)
@@ -1722,6 +1804,7 @@ def test_network_provisioning_is_single_flight_and_secret_is_unwrapped_only_at_b
assert boundary_calls == [("k1-a", "lab-network", PRIMARY_TEST_CREDENTIAL)]
assert connected["k1_ip"] == "192.168.1.20"
assert connected["connection_mode"] == "bridge"
assert PRIMARY_TEST_CREDENTIAL not in str(connected)
provision_operations = [
item for item in connected["operations"] if item["action"] == "network.provision"
@@ -1729,6 +1812,48 @@ def test_network_provisioning_is_single_flight_and_secret_is_unwrapped_only_at_b
assert {item["status"] for item in provision_operations} == {"succeeded", "failed"}
def test_network_provisioning_rejects_an_ipv4_owned_by_the_local_host(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
service, _ = service_with_fake_runtime(tmp_path)
service._devices = [{"device_id": "k1-a"}] # noqa: SLF001
async def fake_provision(*_: object, **__: object) -> dict[str, Any]:
return {
"started_at_utc": "2026-07-18T15:19:25Z",
"completed_at_utc": "2026-07-18T15:19:26Z",
"profile_id": "xgrids-k1-fw3-wifi-v1",
"outcome": "lan_address_observed",
"observations": [{"status": {"ipv4": "192.168.68.51"}}],
}
monkeypatch.setattr(facade_module, "provision_wifi_once", fake_provision)
monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: True)
with pytest.raises(RuntimeError, match="уже принадлежит этому компьютеру"):
asyncio.run(
service.connect(
ConnectRequest(
device_id="k1-a",
ssid="lab-network",
password=SecretStr(PRIMARY_TEST_CREDENTIAL),
compatibility_attestation=ATTESTATION,
)
)
)
state = service.state()
assert state["selected_device_id"] is None
assert state["k1_ip"] is None
operation = next(
item for item in state["operations"] if item["action"] == "network.provision"
)
assert operation["status"] == "failed"
assert operation["error"]["safe_to_retry"] is False
assert operation["error"]["side_effect_status"] == "unknown"
def test_provisioning_cannot_switch_device_during_active_acquisition(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,