from __future__ import annotations import asyncio import fcntl import hashlib import json import logging import os import subprocess import threading import time from collections.abc import AsyncIterator, Callable, Iterator, Mapping from contextlib import asynccontextmanager, contextmanager from dataclasses import dataclass, replace from datetime import UTC, datetime, timedelta from itertools import count from pathlib import Path from types import MethodType, SimpleNamespace from typing import Any import pytest from missioncore_plugin_sdk.v0alpha2 import RuntimeActionInvocation from pydantic import SecretStr, ValidationError import k1link.device_plugins.xgrids_k1.facade as facade_module import k1link.host_network.wifi as host_wifi_module from k1link.data_plane import ConsumerFrameContext, DecodedPointCloudView from k1link.device_plugins.xgrids_k1.active_acquisition_recovery_checkpoint import ( ActiveAcquisitionRecoveryConnection, ActiveAcquisitionRecoveryIdentity, ActiveAcquisitionRecoveryTransportBinding, active_acquisition_project_name_sha256, ) from k1link.device_plugins.xgrids_k1.application_control_process_lease import ( ApplicationControlProcessLease, ) from k1link.device_plugins.xgrids_k1.ble.runtime_arbiter import ( BleOperationHardTimeout, BleOperationProgress, BleRuntimeBusy, bind_ble_runtime_owner_loop, run_ble_operation, wait_for_ble_runtime_idle, ) from k1link.device_plugins.xgrids_k1.connection_supervisor import ( DEFAULT_TRANSPORT_OBSERVATION_TTL_SECONDS, EndpointTarget, HostPathProbeResult, VerifiedControlEvidence, ) from k1link.device_plugins.xgrids_k1.device_identity_pin_store import ( DeviceIdentityPinStoreCorrupt, ) from k1link.device_plugins.xgrids_k1.facade import ( ACTION_PHYSICAL_COMMAND_REOPEN_RETIRED_RECONCILIATION, ACTION_PHYSICAL_COMMAND_RETIRE_UNAVAILABLE, DEFAULT_LIVE_STREAMS, XGRIDS_K1_COMPATIBILITY_PROFILE_ID, AbortAcquisitionRequest, BleScanRequest, CameraPreviewSelectRequest, CompatibilityAttestationRequest, ConfiguredEndpointProbeRequest, ConnectionVerifyRequest, ConnectRequest, DesiredConnectionModeRequest, EnterApplicationWorkspaceRequest, ForceFinishAcquisitionRequest, OpenApplicationControlSessionRequest, OperatorPresenceRequest, PrepareAcquisitionRequest, PrepareConnectionReconfigurationRequest, ReopenRetiredPhysicalCommandReconciliationRequest, RetireUnavailablePhysicalCommandRequest, ShadowApplicationControlArmRequest, StartAcquisitionRequest, StopAcquisitionRequest, XgridsK1CompatibilityService, XgridsK1PluginFacade, ) from k1link.device_plugins.xgrids_k1.network_mutation_ledger import ( NetworkConnectionMode, NetworkMutationRecord, NetworkStatusEvidence, PreviousConnectionEvidence, ) from k1link.device_plugins.xgrids_k1.network_provisioning_idempotency_journal import ( NetworkProvisioningIdempotencyConflict, derive_request_binding_sha256, ) from k1link.device_plugins.xgrids_k1.physical_command_coordinator import ( LedgerPhysicalCommandCoordinator, PhysicalCommandRuntimeBinding, ) from k1link.device_plugins.xgrids_k1.physical_command_ledger import ( PHYSICAL_COMMAND_APPLICATION_SUCCESS_CODE, PhysicalCommandApplicationResponse, PhysicalCommandBlocked, PhysicalCommandConnectionBinding, PhysicalCommandIdentity, PhysicalCommandLedgerSnapshot, PhysicalCommandStatusEvidence, PhysicalCommandTransitionError, ) from k1link.device_plugins.xgrids_k1.protocol import application_session as session_module from k1link.device_plugins.xgrids_k1.protocol.application_acceptance import ( ApplicationAcceptanceError, ) from k1link.device_plugins.xgrids_k1.protocol.application_bootstrap import ( ApplicationControlAuthority, LiveDeviceControlBinding, ) from k1link.device_plugins.xgrids_k1.protocol.application_mqtt import ( ApplicationMqttDeviceStatusEvidence, ApplicationMqttPublishEvidence, ApplicationMqttResponseEvidence, ApplicationMqttTransportError, ) from k1link.device_plugins.xgrids_k1.protocol.application_publish import ( OneShotPublishEnvelope, ) from k1link.device_plugins.xgrids_k1.protocol.application_session import ( ApplicationConnectionBinding, ApplicationConnectionBindingLost, InteractiveApplicationControlSession, ) from k1link.device_plugins.xgrids_k1.protocol.modeling_control import ( MODELING_STATE_BASE, ) from k1link.device_plugins.xgrids_k1.semantic_topology_store import ( SemanticTopologyStoreCorrupt, ) from k1link.device_plugins.xgrids_k1.viewer.messages import StreamMessage from k1link.host_network import HostWifiAssociationIdentityResult from k1link.viewer.metrics import BridgeMetrics from k1link.web.device_lifecycle import OperationJournal from k1link.web.plugin_runtime import PluginExecutionError ATTESTATION = CompatibilityAttestationRequest( firmware_version="3.0.2", topology="direct-lan", verification="live-device-info", ) QUICK_CONNECT_ATTESTATION = CompatibilityAttestationRequest( firmware_version="3.0.2", topology="device-ap", verification="live-device-info", ) DIRECT_CONNECT_ATTESTATION = CompatibilityAttestationRequest( firmware_version="3.0.2", topology="controller-hotspot", verification="live-device-info", ) PRIMARY_TEST_CREDENTIAL = "x" * 24 SECONDARY_TEST_CREDENTIAL = "y" * 24 PROJECT_NAME = "K1 lifecycle test" PRIVATE_APPLICATION_AUTHORITY = "11111111-2222-3333-4444-555555555555" DURABLE_K1_UUID = "F89438FA-55ED-85AD-EED7-734AC84746D8" _CONNECT_INTENT_SEQUENCE = count(1) _LIFECYCLE_INTENT_SEQUENCE = count(1) _SYNTHETIC_SCAN_CAPTURES: dict[str, facade_module.CapturedDiscoveredDevice] = {} @pytest.fixture(autouse=True) def _synthetic_exact_scan_handoff(monkeypatch: pytest.MonkeyPatch) -> Iterator[None]: """Give facade-only lifecycle fixtures an exact selected scan object. Scanner ownership/object handoff itself is covered in ``test_ble_scanner``. These service tests seed the facade's scan projection directly, so mirror that synthetic scan with one object-bound capture instead of weakening the production admission rule to accept a UUID without a CoreBluetooth object. """ _SYNTHETIC_SCAN_CAPTURES.clear() monkeypatch.setattr( facade_module, "_capture_network_intent_device", lambda device_id: _SYNTHETIC_SCAN_CAPTURES.get(device_id), ) monkeypatch.setattr( facade_module, "pin_connected_device_handle", lambda *_args, **_kwargs: None, ) yield _SYNTHETIC_SCAN_CAPTURES.clear() def _connect_request(**values: Any) -> ConnectRequest: """Give every physical network test an explicit, unique durable intent.""" values.setdefault( "idempotency_key", f"test-network-provision-{next(_CONNECT_INTENT_SEQUENCE)}", ) values.setdefault("expected_mode_revision", 0) values.setdefault("expected_discovery_generation", 0) return ConnectRequest(**values) def _select_connection_mode( service: XgridsK1CompatibilityService, connection_mode: str, ) -> int: """Select a process-local draft exactly as the product dropdown does.""" state = service.select_connection_mode( DesiredConnectionModeRequest( connection_mode=connection_mode, # type: ignore[arg-type] expected_revision=service.state()["desired_connection_mode_revision"], ) ) return int(state["desired_connection_mode_revision"]) def _lifecycle_intent_key(action: str) -> str: return f"test-{action}-{next(_LIFECYCLE_INTENT_SEQUENCE)}" def _prepare_request(**values: Any) -> PrepareAcquisitionRequest: values.setdefault("idempotency_key", _lifecycle_intent_key("acquisition-prepare")) values.setdefault("expected_control_session_generation", 1) values.setdefault("expected_control_state_revision", 1) return PrepareAcquisitionRequest(**values) def _start_request(**values: Any) -> StartAcquisitionRequest: values.setdefault("idempotency_key", _lifecycle_intent_key("acquisition-start")) values.setdefault("expected_control_session_generation", 1) values.setdefault("expected_control_state_revision", 2) return StartAcquisitionRequest(**values) def _stop_request(**values: Any) -> StopAcquisitionRequest: values.setdefault("idempotency_key", _lifecycle_intent_key("acquisition-stop")) values.setdefault("expected_control_session_generation", 1) values.setdefault("expected_control_state_revision", 3) return StopAcquisitionRequest(**values) def _abort_request(**values: Any) -> AbortAcquisitionRequest: values.setdefault("idempotency_key", _lifecycle_intent_key("acquisition-abort")) values.setdefault("expected_control_session_generation", 1) values.setdefault("expected_control_state_revision", 2) return AbortAcquisitionRequest(**values) def _force_finish_request(**values: Any) -> ForceFinishAcquisitionRequest: values.setdefault( "idempotency_key", _lifecycle_intent_key("acquisition-force-finish-local"), ) values.setdefault("operator_confirmed", True) return ForceFinishAcquisitionRequest(**values) def _dispatch_test_network_write( on_write_dispatch: Callable[[dict[str, Any], str], None] | None, ) -> None: """Cross the same durable dispatch boundary as the production BLE helper.""" assert on_write_dispatch is not None on_write_dispatch( { "mode": "WIFI_AP", "ipv4": "192.168.56.1", "status_code": 1, "reserved": 0, }, "with_response", ) async def _reachable_control_endpoint( target: str, *_: object, endpoint_probe: Callable[[str], object] | None = None, **__: object, ) -> object: return endpoint_probe(target) if endpoint_probe is not None else True async def _unreachable_control_endpoint( target: str, *_: object, endpoint_probe: Callable[[str], object] | None = None, **__: object, ) -> object: return endpoint_probe(target) if endpoint_probe is not None else False def _direct_host_path(target_ipv4: str, **_: object) -> HostPathProbeResult: source_ipv4 = ( "10.255.254.2" if target_ipv4.startswith("10.") else "192.168.56.2" if target_ipv4.startswith("192.168.56.") else "192.168.1.2" ) return HostPathProbeResult( available=True, fingerprint=f"test-route:{target_ipv4}", interface="test0", source_ipv4=source_ipv4, route_class="direct", kernel_route_fingerprint=f"test-route:{target_ipv4}", ) def _association_bound_direct_host_path(target_ipv4: str) -> HostPathProbeResult: raw = _direct_host_path(target_ipv4) assert raw.fingerprint is not None return HostPathProbeResult( available=True, fingerprint=facade_module.bind_route_fingerprint_to_wifi_association( raw.fingerprint, DeterministicContendedAssociationProbe.proven_observation(), ), interface=raw.interface, source_ipv4=raw.source_ipv4, route_class=raw.route_class, kernel_route_fingerprint=raw.fingerprint, ) def _tunnel_host_path(target_ipv4: str) -> HostPathProbeResult: return HostPathProbeResult( available=True, fingerprint=f"test-tunnel:{target_ipv4}", interface="utun-test", source_ipv4="100.64.0.2", route_class="tunnel", ) @pytest.mark.parametrize( ("interface", "destination", "expected", "reason_code"), [ ("en0", "192.168.68.0", "direct", None), ("bridge100", "192.168.68.0", "direct", None), ("utun8", "192.168.68.0", "tunnel", "host-route-tunnel"), ("tun0", "192.168.68.0", "tunnel", "host-route-tunnel"), ("tap2", "192.168.68.0", "tunnel", "host-route-tunnel"), ("wg0", "192.168.68.0", "tunnel", "host-route-tunnel"), ("en0", "default", "default", "host-route-default"), ( "vendor-vpn0", "192.168.68.0", "unknown", "host-route-interface-unreviewed", ), (None, "192.168.68.0", "unknown", "host-route-unclassified"), ], ) def test_host_route_classifier_is_fail_closed_for_virtual_and_unknown_interfaces( interface: str | None, destination: str, expected: str, reason_code: str | None, ) -> None: assert facade_module._classify_host_route(interface, destination) == ( # noqa: SLF001 expected, reason_code, ) class FakeHostWifiAssociationProbe: def __init__(self, *continuity_tokens: str) -> None: self._continuity_tokens = continuity_tokens or ("a" * 64,) self.interfaces: list[str | None] = [] self.timeout_seconds: list[float] = [] def observe( self, interface_name: str | None, *, timeout_seconds: float = 30.0, ) -> HostWifiAssociationIdentityResult: assert timeout_seconds > 0 self.timeout_seconds.append(timeout_seconds) token_index = min(len(self.interfaces), len(self._continuity_tokens) - 1) self.interfaces.append(interface_name) return { "schema_version": 1, "adapter": "test-host-association", "wifi_interface": True, "association_state": "associated", "evidence_quality": "bssid-only", "continuity_proven": True, "continuity_token": self._continuity_tokens[token_index], "reason_code": None, } class DeterministicContendedAssociationProbe: """Real probe harness with fake lock/helper clocks and no wall-clock sleep.""" def __init__( self, *, lock_wait_seconds: float, helper_required_seconds: float, on_first_lock_acquired: Callable[[], None] | None = None, ) -> None: self.monotonic = 100.0 self.wall = 1_000.0 self.lock_wait_seconds = lock_wait_seconds self.helper_required_seconds = helper_required_seconds self.on_first_lock_acquired = on_first_lock_acquired self.lock_timeouts: list[float] = [] self.helper_timeouts: list[float] = [] self._lock_acquisitions = 0 self._locked = False def advance(self, seconds: float) -> None: self.monotonic += seconds self.wall += seconds def acquire(self, *, timeout: float) -> bool: self.lock_timeouts.append(timeout) wait = self.lock_wait_seconds if self._lock_acquisitions == 0 else 0.0 self._lock_acquisitions += 1 if wait > timeout: self.advance(timeout) return False self.advance(wait) self._locked = True if self._lock_acquisitions == 1 and self.on_first_lock_acquired is not None: self.on_first_lock_acquired() return True def release(self) -> None: assert self._locked is True self._locked = False def runner( self, argv: list[str], **kwargs: object, ) -> subprocess.CompletedProcess[bytes]: timeout = kwargs.get("timeout") assert isinstance(timeout, (int, float)) and not isinstance(timeout, bool) timeout_seconds = float(timeout) self.helper_timeouts.append(timeout_seconds) if self.helper_required_seconds > timeout_seconds: self.advance(timeout_seconds) raise subprocess.TimeoutExpired(argv, timeout_seconds) self.advance(self.helper_required_seconds) return subprocess.CompletedProcess( argv, 0, stdout=( b'{"ok":true,"adapter":"CoreWLAN","wifi_interface":true,' b'"association_identity":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' b'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","association_evidence":"bssid-only"}' ), stderr=b"", ) def build( self, monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> host_wifi_module.HostWifiAssociationIdentityProbe: helper_path = tmp_path / "deterministic-association-helper.swift" helper_path.write_text("// deterministic test helper\n", encoding="utf-8") monkeypatch.setattr( host_wifi_module, "time", SimpleNamespace(monotonic=lambda: self.monotonic), ) monkeypatch.setattr( host_wifi_module, "sys", SimpleNamespace(platform="darwin"), ) probe = host_wifi_module.HostWifiAssociationIdentityProbe( helper_path, runner=self.runner, continuity_key=b"c" * 32, monotonic_clock=lambda: self.monotonic, wall_clock=lambda: self.wall, ) probe._lock = self # type: ignore[assignment] # noqa: SLF001 return probe @staticmethod def proven_observation() -> HostWifiAssociationIdentityResult: return { "schema_version": 1, "adapter": "CoreWLAN", "wifi_interface": True, "association_state": "associated", "evidence_quality": "bssid-only", "continuity_proven": True, "continuity_token": "a" * 64, "reason_code": None, } class FakeApplicationAuthorityLoader: def __init__(self) -> None: self.calls = 0 def load(self) -> ApplicationControlAuthority: self.calls += 1 return ApplicationControlAuthority(openapi_key=PRIVATE_APPLICATION_AUTHORITY) class FakeVisualizationRuntime: def __init__(self) -> None: self.phase = "idle" self.source_mode = "idle" self.source_ready = False self.producer_generation = 0 self.pcl_frames = 0 self.start_calls: list[tuple[str, Path, float | None, str]] = [] self.stop_calls = 0 self.stop_error: Exception | None = None self.recover_connection: Callable[[int], str] | None = None self.recovery_requests: list[tuple[str, int]] = [] self.recovery_request_pending = False self.recovery_state = "inactive" self.recovery_attempt = 0 def snapshot(self) -> dict[str, Any]: return { "phase": self.phase, "message": "test runtime", "source_mode": self.source_mode, "source_ready": self.source_ready, "producer_generation": self.producer_generation, "foxglove_ws_url": None, "foxglove_viewer_url": None, "rerun_grpc_url": None, "viewer_settings": {}, "metrics": { "messages_received": self.pcl_frames, "payload_bytes": 0, "pcl_frames": self.pcl_frames, "pose_frames": 0, "points_published": 0, "last_point_count": 0, "decode_errors": 0, "preview_dropped": 0, "pcl_fps": 0.0, "pose_fps": 0.0, "mqtt_to_publish_ms": None, "mqtt_to_publish_p50_ms": None, "mqtt_to_publish_p95_ms": None, "decode_publish_ms": None, "trajectory_poses": 0, }, "connection_recovery": { "state": self.recovery_state, "attempt": self.recovery_attempt, "reason_code": None, "started_at_utc": None, "elapsed_ms": None, "recovered_at_utc": None, "automatic_command_retry": False, "device_write_performed": False, "network_mutation_performed": False, }, } def start_live( self, host: str, out_dir: Path, *, duration_seconds: float | None, project_name: str, recover_connection: Callable[[int], str] | None = None, ) -> None: self.producer_generation += 1 self.start_calls.append((host, out_dir, duration_seconds, project_name)) self.phase = "starting_live" self.source_mode = "live" self.recover_connection = recover_connection def mark_ready(self) -> None: self.phase = "live" self.source_ready = True def request_connection_recovery( self, reason_code: str, *, expected_generation: int, ) -> bool: if ( expected_generation != self.producer_generation or self.recover_connection is None or self.source_mode != "live" or self.phase not in {"live", "reconnecting"} ): return False if self.phase == "reconnecting": return True self.phase = "reconnecting" self.source_ready = False self.recovery_state = "reconnecting" self.recovery_requests.append((reason_code, expected_generation)) self.recovery_request_pending = True return True def stop(self) -> None: self.stop_calls += 1 self.recovery_request_pending = False if self.stop_error is not None: raise self.stop_error self.phase = "idle" self.source_mode = "idle" self.source_ready = False self.recovery_state = "inactive" self.recovery_attempt = 0 def close(self) -> None: self.stop() class FakeInteractiveControlSession: def __init__(self, *, initial_state: str = "workspace-ready") -> None: self.state = initial_state self.session_generation = 1 self.state_revision = 1 self.verified_control: dict[str, object] | None = None self.start_projects: list[str] = [] self.start_contexts: list[Any] = [] self.stop_calls = 0 self.stop_contexts: list[Any] = [] self.stop_dispatch_deadlines: list[Callable[[], bool] | None] = [] self.inspection_only = False self.inspection_promotion_allowed = False self.failure: dict[str, object] | None = None self.outcome_unknown = False self.transport_publish_attempts = 0 def snapshot(self) -> dict[str, object]: return { "state": self.state, "session_generation": self.session_generation, "state_revision": self.state_revision, "inspection_only": self.inspection_only, "inspection_promotion_allowed": self.inspection_promotion_allowed, "can_open": self.state in {"idle", "completed", "closed", "failed"}, "can_enter_workspace": self.state == "connection-ready", "can_prepare_project": self.state == "workspace-ready", "can_start": self.state == "project-ready", "can_stop": self.state == "scanning", "can_confirm_standby": False, "failure": self.failure, "outcome_unknown": self.outcome_unknown, "transport": { "state": "failed" if self.state == "failed" else "ready", "publish_attempts": self.transport_publish_attempts, }, "verified_control": self.verified_control, } def open( self, *, connection_binding: ApplicationConnectionBinding, inspection_only: bool = False, **_: object, ) -> dict[str, object]: assert self.state == "idle" self.verified_control = _verified_control_for_binding(connection_binding) self.inspection_only = inspection_only self.inspection_promotion_allowed = not inspection_only self.state = "connection-ready" self.state_revision += 1 return self.snapshot() def release_inspection_for_operator_dialogue( self, *, expected_session_generation: int, expected_state_revision: int, ) -> dict[str, object]: self._accept_checkpoint( expected_session_generation=expected_session_generation, expected_state_revision=expected_state_revision, ) assert self.state == "connection-ready" self.inspection_promotion_allowed = True return self.snapshot() def adopt_reconciled_scanning( self, *, reconciliation_id: str, expected_session_generation: int, expected_state_revision: int, ) -> dict[str, object]: assert reconciliation_id self._accept_checkpoint( expected_session_generation=expected_session_generation, expected_state_revision=expected_state_revision, ) assert self.state == "connection-ready" self.state = "scanning" return self.snapshot() def enter_workspace( self, *, expected_session_generation: int | None = None, expected_state_revision: int | None = None, ) -> dict[str, object]: assert self.state == "connection-ready" self._accept_checkpoint( expected_session_generation=expected_session_generation, expected_state_revision=expected_state_revision, ) self.state = "workspace-ready" return self.snapshot() def _accept_checkpoint( self, *, expected_session_generation: int | None, expected_state_revision: int | None, ) -> None: assert expected_session_generation == self.session_generation assert expected_state_revision == self.state_revision self.state_revision += 1 def validate_connection_binding(self) -> None: return None def validate_physical_reconciliation_binding(self) -> None: return None def open_project_prompt( self, *, expected_session_generation: int | None = None, expected_state_revision: int | None = None, ) -> dict[str, object]: assert self.state == "workspace-ready" self._accept_checkpoint( expected_session_generation=expected_session_generation, expected_state_revision=expected_state_revision, ) self.state = "project-ready" return self.snapshot() def request_start( self, *, project_name: str, confirmation: object, command_context: object, preparation_checkpoint_observer: object | None = None, expected_session_generation: int | None = None, expected_state_revision: int | None = None, ) -> dict[str, object]: del preparation_checkpoint_observer assert confirmation is not None assert command_context is not None assert self.state == "project-ready" self._accept_checkpoint( expected_session_generation=expected_session_generation, expected_state_revision=expected_state_revision, ) self.start_projects.append(project_name) self.start_contexts.append(command_context) self.state = "scanning" return self.snapshot() def request_stop( self, *, confirmation: object, command_context: object, dispatch_admission_deadline_reached: Callable[[], bool] | None = None, expected_session_generation: int | None = None, expected_state_revision: int | None = None, ) -> dict[str, object]: assert confirmation is not None assert command_context is not None assert self.state == "scanning" self._accept_checkpoint( expected_session_generation=expected_session_generation, expected_state_revision=expected_state_revision, ) self.stop_calls += 1 self.stop_contexts.append(command_context) self.stop_dispatch_deadlines.append(dispatch_admission_deadline_reached) self.state = "awaiting-standby-confirmation" return self.snapshot() def close_prestart( self, *, expected_session_generation: int | None = None, expected_state_revision: int | None = None, ) -> dict[str, object]: if expected_session_generation is not None or expected_state_revision is not None: self._accept_checkpoint( expected_session_generation=expected_session_generation, expected_state_revision=expected_state_revision, ) self.state = "closed" self.verified_control = None return self.snapshot() def retire_for_network_change(self, **_: object) -> dict[str, object]: if self.state not in {"idle", "completed", "closed", "failed"}: raise RuntimeError("control session cannot be retired") self.state = "idle" self.verified_control = None return self.snapshot() def close(self) -> None: self.state = "closed" self.verified_control = None PHYSICAL_ACCEPTANCE = OperatorPresenceRequest( operator_present=True, owner_controlled_device=True, lixelgo_closed=True, battery_storage_confirmed=True, expected_physical_state_confirmed=True, ) def _exact_start_physical_proof( *, operation_id: str, acquisition_id: str, binding: ApplicationConnectionBinding, resolved: bool, ) -> dict[str, object]: session_state = "scanning" if resolved else "scan_starting" return { "status": "resolved" if resolved else "unresolved", "reason_code": (None if resolved else "physical-command-reconciliation-required"), "requires_reconciliation": not resolved, "resolved_active_recovery_required": resolved, "reconciled_physical_state": "active" if resolved else None, "physical_active": resolved, "automatic_replay_allowed": False, "record": { "revision": 7, "operation_id": operation_id, "acquisition_id": acquisition_id, "action": "start", "stage": "resolved" if resolved else "observing", "resolution": "start-active-observed" if resolved else None, "publish_call_returned": True, "qos2_completed": True, "packet_id": 14, "application_response": { "operation_id": operation_id, "action": "start", "success": True, }, "baseline_status": { "control_session_id": "fake-control-session", "host_path_epoch": binding.host_path_epoch, "producer_generation": 1, "session_state": "ready", "project_bound": False, "init_ready": False, "mqtt_retained": False, }, "last_status": { "session_state": session_state, "project_bound": resolved, "init_ready": resolved, "mqtt_retained": False, "system_error_code": None, }, "connection": { "intent_id": binding.intent_id, "transport_ref": binding.transport_ref, "connection_mode": binding.connection_mode, "target_ipv4": binding.target_ipv4, "target_port": binding.target_port, "host_path_epoch": binding.host_path_epoch, "control_session_id": "fake-control-session", "producer_generation": 1, }, "identity": { "vendor_device_id_sha256": "a" * 64, "device_serial_sha256": "b" * 64, }, "compatibility_profile_id": XGRIDS_K1_COMPATIBILITY_PROFILE_ID, "reconciliations": [], }, } def test_control_session_transport_metadata_does_not_leak_into_confirmation() -> None: request = OpenApplicationControlSessionRequest( operator_present=True, owner_controlled_device=True, lixelgo_closed=True, battery_storage_confirmed=True, expected_physical_state_confirmed=True, timezone_name="Europe/Moscow", ) assert request.confirmation() == PHYSICAL_ACCEPTANCE.confirmation() async def _synthetic_prestart_control_bootstrap( service: XgridsK1CompatibilityService, *, parent_operation_id: str | None, connection_mode: facade_module.ConnectionMode, inspection_only: bool = False, ) -> None: """Keep network lifecycle tests independent from a live MQTT/Keychain.""" supervisor = service._connection_supervisor.snapshot() # noqa: SLF001 assert supervisor.intent is not None assert supervisor.device_network.target is not None assert supervisor.device_network.transport_ref is not None operation, _ = service._operations.begin( # noqa: SLF001 facade_module.ACTION_CONNECTION_CONTROL_BOOTSTRAP, device_id=service._device_id, # noqa: SLF001 device_session_id=service._device_session_id, # noqa: SLF001 deadline_seconds=1.0, context={ "connection_mode": connection_mode, "parent_operation_id": parent_operation_id, "automatic_retry": False, }, ) service._operations.transition( # noqa: SLF001 operation.operation_id, "running", stage_code="mqtt-device-info", message_code="connection.control_bootstrap.running", ) control = FakeInteractiveControlSession(initial_state="idle") binding = ApplicationConnectionBinding( intent_id=supervisor.intent.intent_id, transport_ref=supervisor.device_network.transport_ref, host_path_epoch=supervisor.host_path.epoch, target_ipv4=supervisor.device_network.target.ipv4, target_port=supervisor.device_network.target.port, connection_mode=connection_mode, ) control.open( connection_binding=binding, inspection_only=inspection_only, ) control.verified_control = _verified_control_for_binding( binding, logical_device_id=str( supervisor.intent.expected_device_id or service._device_id # noqa: SLF001 ), control_session_id=( f"fake-control-{parent_operation_id}" if parent_operation_id is not None else "fake-control-session" ), ) service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 service._reconcile_connection_supervisor( # noqa: SLF001 control.snapshot(), service.runtime.snapshot(), ) if not service._connection_supervisor.snapshot().authority.control_allowed: # noqa: SLF001 failure = facade_module.ConnectionVerificationError( "synthetic DeviceInfo authority was not admitted", reason_code="control-bootstrap-device-identity-unverified", ) service._operations.transition( # noqa: SLF001 operation.operation_id, "failed", stage_code="device-info-failed", message_code="connection.control_bootstrap.failed", error={ "category": "connection", "code": failure.reason_code, "retryable": True, "safe_to_retry": True, "side_effect_status": "none", }, ) raise failure service._operations.transition( # noqa: SLF001 operation.operation_id, "succeeded", stage_code="device-info-confirmed", message_code="connection.control_bootstrap.completed", result={ "connection_mode": connection_mode, "control_verified": True, "device_write_performed": False, "automatic_retry": False, }, ) def service_with_fake_runtime( tmp_path: Path, ) -> tuple[XgridsK1CompatibilityService, FakeVisualizationRuntime]: # Durable network/idempotency records are intentionally global in the real # runtime. Each test needs its own private store while repeated service # construction inside one test must still exercise restart semantics. os.environ["MISSIONCORE_DATA_DIR"] = str(tmp_path / "private-data") os.environ["MISSIONCORE_EVIDENCE_DIR"] = str(tmp_path / "private-evidence") os.environ["MISSIONCORE_LEGACY_SESSIONS_DIR"] = str(tmp_path / "private-legacy-sessions") service = XgridsK1CompatibilityService( tmp_path, host_wifi_association_probe=FakeHostWifiAssociationProbe(), ) runtime = FakeVisualizationRuntime() service.runtime = runtime # type: ignore[assignment] # The broad legacy lifecycle fixture replaces both the real application # session and typed physical coordinator with mapping-only fakes. It has no # durable PREPARED callback from which checkpoint v2 can be constructed. # Keep those older tests scoped to their original lifecycle concern; the # typed checkpoint ordering/CAS seams have dedicated integration tests. service._active_acquisition_checkpoint_matches_current = MethodType( # type: ignore[method-assign] # noqa: SLF001 lambda _service, **_kwargs: True, service, ) legacy_start_operation_id: list[str | None] = [None] def checkpoint_start_operation_id( _service: XgridsK1CompatibilityService, *, local_start_operation_id: str | None, **_kwargs: object, ) -> str | None: if local_start_operation_id is not None: legacy_start_operation_id[0] = local_start_operation_id return legacy_start_operation_id[0] service._active_acquisition_checkpoint_start_operation_id = MethodType( # type: ignore[method-assign] # noqa: SLF001 checkpoint_start_operation_id, service, ) service._record_active_acquisition_checkpoint_gap = MethodType( # type: ignore[method-assign] # noqa: SLF001 lambda _service, _lineage, **_kwargs: True, service, ) service._confirm_active_acquisition_checkpoint_rebind = MethodType( # type: ignore[method-assign] # noqa: SLF001 lambda _service, *_args, **_kwargs: True, service, ) service._cease_active_acquisition_checkpoint_from_physical_head = MethodType( # type: ignore[method-assign] # noqa: SLF001 lambda _service, **_kwargs: True, service, ) service._bootstrap_prestart_control_ready_owned = MethodType( # type: ignore[method-assign] # noqa: SLF001 _synthetic_prestart_control_bootstrap, service, ) return service, runtime def test_service_owns_one_wifi_association_probe_across_monitor_recreation( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: association_probe = FakeHostWifiAssociationProbe() constructed: list[Path] = [] def probe_factory(helper_path: Path) -> FakeHostWifiAssociationProbe: constructed.append(helper_path) return association_probe monkeypatch.setattr( facade_module, "HostWifiAssociationIdentityProbe", probe_factory, ) monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) service = XgridsK1CompatibilityService(tmp_path) _seed_supervised_connection(service, target_ipv4="192.168.1.20") first = service._sample_host_path("192.168.1.20") # noqa: SLF001 service._connection_monitor = service._new_connection_monitor() # noqa: SLF001 second = asyncio.run( # noqa: SLF001 service._monitor_host_path(EndpointTarget("192.168.1.20")) ) assert constructed == [tmp_path / "plugins" / "xgrids-k1" / "macos" / "associate_wifi.swift"] assert association_probe.interfaces == ["test0", "test0"] assert first.fingerprint == second.fingerprint @pytest.mark.parametrize( ("raw_paths", "association_tokens"), [ ( ( _direct_host_path("192.168.1.20"), _direct_host_path("192.168.56.20"), ), ("a" * 64, "a" * 64, "a" * 64), ), ( ( _direct_host_path("192.168.1.20"), _direct_host_path("192.168.1.20"), ), ("a" * 64, "a" * 64, "b" * 64), ), ], ) def test_sync_tcp_success_cannot_cross_route_or_wifi_association_change( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, raw_paths: tuple[HostPathProbeResult, HostPathProbeResult], association_tokens: tuple[str, str, str], ) -> None: association_probe = FakeHostWifiAssociationProbe(*association_tokens) service = XgridsK1CompatibilityService( tmp_path, host_wifi_association_probe=association_probe, ) service.runtime = FakeVisualizationRuntime() # type: ignore[assignment] monkeypatch.setattr(facade_module, "_inspect_host_path", lambda _target: raw_paths[0]) initial_path = service._sample_host_path("192.168.1.20") # noqa: SLF001 _seed_supervised_connection(service, host_path=initial_path) pending_paths = iter(raw_paths) monkeypatch.setattr( facade_module, "_inspect_host_path", lambda _target: next(pending_paths), ) monkeypatch.setattr( facade_module, "_control_endpoint_reachable", lambda _target: True, ) observation = service._probe_control_endpoint("192.168.1.20") # noqa: SLF001 supervisor = service._connection_supervisor.snapshot() # noqa: SLF001 assert observation.reachable is False assert observation.reason_code == "host-path-changed-during-tcp-probe" assert supervisor.host_path.fingerprint == observation.path.fingerprint assert supervisor.endpoint.tcp_state == "unreachable" assert supervisor.authority.control_allowed is False assert supervisor.lease.state != "reachable" def _seed_supervised_connection( service: XgridsK1CompatibilityService, *, target_ipv4: str = "192.168.1.20", connection_mode: facade_module.ConnectionMode = "bridge", transport_ref: str = "test-ble-transport", logical_device_id: str = "known-k1", host_path: HostPathProbeResult | None = None, endpoint_reachable: bool = True, endpoint_reason: str | None = None, with_control: bool = True, ) -> ApplicationConnectionBinding: """Install one internally consistent test-only connection evidence chain. Older lifecycle fixtures used ``_k1_ip`` as if an address implied a live connection. The production supervisor now deliberately requires four independent facts: the K1-reported topology, the current host route, TCP reachability and DeviceInfo bound to that exact intent/route epoch. Tests that exercise already-open plugin control must seed all four explicitly; tests for the pre-DeviceInfo state pass ``with_control=False``. """ intent_id = f"test-intent-{connection_mode}-{transport_ref}-{target_ipv4}" target = EndpointTarget(target_ipv4, facade_module.CONTROL_MQTT_PORT) attestation = { "bridge": ATTESTATION, "quick-connect": QUICK_CONNECT_ATTESTATION, "direct-connect": DIRECT_CONNECT_ATTESTATION, }[connection_mode] service._pin_or_match_device_identity( # noqa: SLF001 transport_ref=transport_ref, logical_device_id=logical_device_id, compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, ) service._connection_supervisor.set_intent( # noqa: SLF001 intent_id=intent_id, requested_mode=connection_mode, expected_device_id=logical_device_id, ) accepted = service._connection_supervisor.observe_device_network_applied( # noqa: SLF001 intent_id=intent_id, transport_ref=transport_ref, connection_mode=connection_mode, target=target, source="ble-read-only-status", ) assert accepted is True host_epoch = service._connection_supervisor.observe_host_path( # noqa: SLF001 host_path or _direct_host_path(target_ipv4) ) endpoint_accepted = service._connection_supervisor.observe_endpoint( # noqa: SLF001 target=target, intent_id=intent_id, host_path_epoch=host_epoch, reachable=endpoint_reachable, reason_code=( None if endpoint_reachable else endpoint_reason or "test-endpoint-unreachable" ), ) assert endpoint_accepted is True binding = ApplicationConnectionBinding( intent_id=intent_id, transport_ref=transport_ref, host_path_epoch=host_epoch, target_ipv4=target_ipv4, target_port=facade_module.CONTROL_MQTT_PORT, connection_mode=connection_mode, ) if with_control: assert endpoint_reachable is True control_accepted = service._connection_supervisor.observe_control_evidence( # noqa: SLF001 VerifiedControlEvidence( intent_id=intent_id, transport_ref=transport_ref, host_path_epoch=host_epoch, target=target, connection_mode=connection_mode, logical_device_id=logical_device_id, compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, control_session_id=f"test-control-{transport_ref}", ) ) assert control_accepted is True with service._lock: # noqa: SLF001 service._selected_device_id = transport_ref # noqa: SLF001 service._connection_mode = connection_mode # noqa: SLF001 service._k1_ip = target_ipv4 # noqa: SLF001 service._device_id = logical_device_id # noqa: SLF001 service._device_session_id = f"test-session-{transport_ref}" # noqa: SLF001 service._device_session_opened_at = "2026-07-20T12:00:00Z" # noqa: SLF001 service._compatibility_attestation = attestation.model_dump(mode="json") # noqa: SLF001 service._connection_lease_generation = ( # noqa: SLF001 service._connection_supervisor.snapshot().lease.generation # noqa: SLF001 ) control = service._application_control_session # noqa: SLF001 if ( with_control and isinstance(control, FakeInteractiveControlSession) and control.verified_control is None ): control.verified_control = _verified_control_for_binding( binding, logical_device_id=logical_device_id, ) return binding def _verified_control_for_binding( binding: ApplicationConnectionBinding, *, logical_device_id: str = "known-k1", control_session_id: str = "fake-control-session", control_proof_revision: int = 1, control_proof_source: str = "correlated-application-response", control_proof_fresh: bool = True, producer_generation: int = 1, ) -> dict[str, object]: return { "logical_device_id": logical_device_id, "compatibility_profile_id": XGRIDS_K1_COMPATIBILITY_PROFILE_ID, "control_session_id": control_session_id, "source": "mqtt-device-info", "intent_id": binding.intent_id, "transport_ref": binding.transport_ref, "host_path_epoch": binding.host_path_epoch, "target_ipv4": binding.target_ipv4, "target_port": binding.target_port, "connection_mode": binding.connection_mode, "producer_generation": producer_generation, "control_proof_revision": control_proof_revision, "control_proof_source": control_proof_source, "control_proof_fresh": control_proof_fresh, } def _seed_unresolved_physical_stop_for_retirement( service: XgridsK1CompatibilityService, binding: ApplicationConnectionBinding, ) -> RetireUnavailablePhysicalCommandRequest: """Persist one accepted STOP whose READY outcome was never observed.""" identity = PhysicalCommandIdentity( vendor_device_id_sha256=hashlib.sha256(b"retirement-vendor").hexdigest(), device_serial_sha256=hashlib.sha256(b"retirement-serial").hexdigest(), ) connection = PhysicalCommandConnectionBinding( intent_id=binding.intent_id, transport_ref=binding.transport_ref, connection_mode=binding.connection_mode, target_ipv4=binding.target_ipv4, target_port=binding.target_port, host_path_epoch=binding.host_path_epoch, control_session_id="retirement-old-control-session", producer_generation=11, ) def status( session_state: str, *, observed_at_utc: str, ) -> PhysicalCommandStatusEvidence: scanning = session_state == "scanning" return PhysicalCommandStatusEvidence( source="live-control-session", vendor_device_id_sha256=identity.vendor_device_id_sha256, device_serial_sha256=identity.device_serial_sha256, control_session_id=connection.control_session_id, host_path_epoch=connection.host_path_epoch, producer_generation=connection.producer_generation, session_state=session_state, # type: ignore[arg-type] session_state_code=302 if scanning else 300, project_bound=scanning, project_id_sha256=("c" * 64 if scanning else None), init_ready=scanning, status_message_sha256=hashlib.sha256( f"{session_state}:{observed_at_utc}".encode() ).hexdigest(), mqtt_retained=False, observed_at_utc=observed_at_utc, ) ledger = service._physical_command_ledger # noqa: SLF001 start_operation_id = "physical-start-before-operator-retirement" stop_operation_id = "physical-stop-before-operator-retirement" acquisition_id = "acquisition-before-operator-retirement" ledger.prepare( operation_id=start_operation_id, parent_operation_id=None, acquisition_id=acquisition_id, action="start", identity=identity, connection=connection, compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, payload_sha256="d" * 64, baseline_status=status( "ready", observed_at_utc="2026-08-10T16:59:00.000Z", ), ) ledger.mark_dispatching(start_operation_id) ledger.mark_observing( start_operation_id, publish_call_returned=True, packet_id=41, ) ledger.mark_qos2_completed(start_operation_id, packet_id=41) ledger.record_application_response( start_operation_id, PhysicalCommandApplicationResponse( operation_id=start_operation_id, action="start", control_session_id=connection.control_session_id, host_path_epoch=connection.host_path_epoch, producer_generation=connection.producer_generation, result_code=PHYSICAL_COMMAND_APPLICATION_SUCCESS_CODE, success=True, payload_sha256="e" * 64, observed_at_utc="2026-08-10T16:59:01.000Z", ), ) ledger.record_status_observation( start_operation_id, status("scanning", observed_at_utc="2026-08-10T16:59:02.000Z"), ) ledger.resolve(start_operation_id, resolution="start-active-observed") ledger.prepare( operation_id=stop_operation_id, parent_operation_id=start_operation_id, acquisition_id=acquisition_id, action="stop", identity=identity, connection=connection, compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, payload_sha256="f" * 64, baseline_status=status( "scanning", observed_at_utc="2026-08-10T17:00:00.000Z", ), ) ledger.mark_dispatching(stop_operation_id) ledger.mark_observing( stop_operation_id, publish_call_returned=True, packet_id=42, ) ledger.mark_qos2_completed(stop_operation_id, packet_id=42) ledger.record_application_response( stop_operation_id, PhysicalCommandApplicationResponse( operation_id=stop_operation_id, action="stop", control_session_id=connection.control_session_id, host_path_epoch=connection.host_path_epoch, producer_generation=connection.producer_generation, result_code=PHYSICAL_COMMAND_APPLICATION_SUCCESS_CODE, success=True, payload_sha256="1" * 64, observed_at_utc="2026-08-10T17:00:01.000Z", ), ) record = ledger.snapshot().record assert record is not None and record.unresolved return RetireUnavailablePhysicalCommandRequest( retirement_id="operator-retirement-stable-request", expected_operation_id=record.operation_id, expected_revision=record.revision, expected_transport_ref=record.connection.transport_ref, operator_confirmed=True, reason="device-permanently-unavailable-or-replaced", ) @pytest.mark.parametrize( "failure_mode", ["stale-visible-checkpoint", "cross-process-ledger-race"], ) def test_physical_retirement_checkpoint_conflict_is_http_409_without_device_io( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, failure_mode: str, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) binding = _seed_supervised_connection( service, transport_ref=DURABLE_K1_UUID, connection_mode="bridge", ) current_request = _seed_unresolved_physical_stop_for_retirement( service, binding, ) request = ( current_request.model_copy( update={ "expected_operation_id": "physical-stop-different-current-checkpoint", } ) if failure_mode == "stale-visible-checkpoint" else current_request ) before = service.state() before_record = service._physical_command_ledger.snapshot().record # noqa: SLF001 before_operations = service._operations.snapshot() # noqa: SLF001 io_calls: list[str] = [] ledger_calls: list[str] = [] async def forbidden_async_io(*_args: object, **_kwargs: object) -> object: io_calls.append("ble-or-wifi") raise AssertionError("retirement checkpoint conflict must not reach device I/O") def forbidden_sync_io(*_args: object, **_kwargs: object) -> object: io_calls.append("mqtt-tcp-monitor") raise AssertionError("retirement checkpoint conflict must not probe the device") def final_ledger_cas(*_args: object, **_kwargs: object) -> object: ledger_calls.append("retire") if failure_mode == "cross-process-ledger-race": raise PhysicalCommandTransitionError( "physical command retirement used a stale record checkpoint" ) raise AssertionError("visible stale checkpoint must fail before the ledger CAS") monkeypatch.setattr(facade_module, "read_wifi_status_once", forbidden_async_io) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_async_io) monkeypatch.setattr(service, "_probe_control_endpoint", forbidden_sync_io) monkeypatch.setattr( service._physical_command_coordinator, # noqa: SLF001 "retire_unavailable_target", final_ledger_cas, ) adapter = XgridsK1PluginFacade(service) with pytest.raises(PluginExecutionError) as raised: asyncio.run( adapter.invoke( RuntimeActionInvocation( invocation_id=f"retirement-{failure_mode}", plugin_id=adapter.plugin_id, action_id=ACTION_PHYSICAL_COMMAND_RETIRE_UNAVAILABLE, requested_at=datetime.now(UTC), parameters={ **request.model_dump(mode="json"), "expected_snapshot_runtime_id": before["snapshot_runtime_id"], }, ) ) ) assert raised.value.http_status_code == 409 assert raised.value.reason_code == "physical-command-retirement-stale-checkpoint" assert ledger_calls == ([] if failure_mode == "stale-visible-checkpoint" else ["retire"]) assert service._physical_command_ledger.snapshot().record == before_record # noqa: SLF001 assert service._operations.snapshot() == before_operations # noqa: SLF001 assert service._application_control_process_lease_holders == set() # noqa: SLF001 assert runtime.start_calls == [] assert runtime.stop_calls == 0 assert io_calls == [] def test_operator_retirement_is_local_only_revokes_old_authority_and_keeps_mode_draft( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) _select_connection_mode(service, "quick-connect") _set_scanned_devices( service, [ { "device_id": "retired-k1", "name": "Original K1", "rssi": -40, "address": None, "connectable": True, "likely_k1": True, }, { "device_id": "replacement-k1", "name": "Replacement K1", "rssi": -45, "address": None, "connectable": True, "likely_k1": True, }, ], ) binding = _seed_supervised_connection( service, transport_ref="RETIRED-K1", connection_mode="bridge", ) request = _seed_unresolved_physical_stop_for_retirement(service, binding) with service._lock: # noqa: SLF001 # CoreBluetooth UUID aliases compare case-insensitively for fencing, # while the durable retirement CAS keeps its original exact spelling. service._selected_device_id = "retired-k1" # noqa: SLF001 _seed_terminal_network_attempt(service) before = service.state() before_operations = service._operations.snapshot() # noqa: SLF001 before_generation = service._ble_discovery_generation # noqa: SLF001 before_devices = list(service._devices) # noqa: SLF001 io_calls: list[str] = [] async def forbidden_io(*_args: object, **_kwargs: object) -> object: io_calls.append("device-or-network-io") raise AssertionError("operator retirement must be local-only") monkeypatch.setattr(facade_module, "read_wifi_status_once", forbidden_io) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_io) monkeypatch.setattr( service, "_probe_control_endpoint", lambda *_args, **_kwargs: io_calls.append("tcp-probe"), ) assert before["physical_command"]["operator_retirement"]["allowed"] is True retirement_action = before["connection_policy"]["actions"]["retire-unavailable-physical-target"] assert retirement_action == { "allowed": True, "reason_codes": [], "target_source": "durable-physical-command", "required_transport_ref": "RETIRED-K1", "requires_live_gatt_validation": False, "physical_command_allowed": False, "physical_outcome": "unknown", "device_write_performed": False, "automatic_retry": False, } assert before["connection_policy"]["recommended_action"] == ( "retire-unavailable-physical-target" ) assert before["connection_attempt"]["safe_next_action"] == ( "retire-unavailable-physical-target" ) result = service.retire_unavailable_physical_command(request) physical = result["physical_command"] assert physical["record"]["resolution"] == "operator-retired-outcome-unknown" assert physical["operator_retirement"]["physical_outcome"] == "unknown" assert physical["operator_retirement"]["allowed"] is False assert result["desired_connection_mode"] == "quick-connect" assert result["selected_device_id"] is None assert result["k1_ip"] is None assert result["connection_lifecycle"]["active_binding"] is None assert result["connection_policy"]["facts"]["retired_transport_refs"] == ["RETIRED-K1"] assert result["connection_policy"]["facts"]["eligible_fresh_transport_refs"] == [ "replacement-k1" ] assert ( result["connection_policy"]["actions"]["retire-unavailable-physical-target"]["allowed"] is False ) assert result["connection_policy"]["actions"]["scan-ble"]["allowed"] is True assert result["connection_attempt"]["safe_next_action"] == ("scan-select-connect") supervisor = service._connection_supervisor.snapshot() # noqa: SLF001 assert supervisor.intent is not None assert supervisor.intent.intent_id == ("physical-retirement-operator-retirement-stable-request") assert supervisor.intent.requested_mode == "quick-connect" assert supervisor.authority.control_allowed is False assert service._operations.snapshot() == before_operations # noqa: SLF001 assert service._ble_discovery_generation == before_generation # noqa: SLF001 assert service._devices == before_devices # noqa: SLF001 assert runtime.start_calls == [] assert runtime.stop_calls == 0 assert io_calls == [] def test_retired_exact_fresh_candidate_reopens_locally_for_explicit_verify_only( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) binding = _seed_supervised_connection( service, transport_ref=DURABLE_K1_UUID, connection_mode="bridge", ) retirement = _seed_unresolved_physical_stop_for_retirement(service, binding) service.retire_unavailable_physical_command(retirement) before_operations = service._operations.snapshot() # noqa: SLF001 before_runtime_starts = list(runtime.start_calls) before_runtime_stops = runtime.stop_calls # A row retained from before retirement is not fresh enough to reopen it. _set_scanned_k1(service, device_id=DURABLE_K1_UUID.lower()) stale = service.state()["physical_command"]["operator_reconciliation_reopen"] assert stale["allowed"] is False assert "physical-command-reconciliation-reopen-target-not-observed" in stale["reason_codes"] with service._lock: # noqa: SLF001 service._ble_discovery_generation += 1 # noqa: SLF001 _set_scanned_k1(service, device_id=DURABLE_K1_UUID.lower()) before = service.state() projection = before["physical_command"]["operator_reconciliation_reopen"] assert projection == { "allowed": True, "reason_codes": [], "expected_revision": retirement.expected_revision + 1, "expected_retirement_id": retirement.retirement_id, "expected_transport_ref": DURABLE_K1_UUID.lower(), "expected_discovery_generation": service._ble_discovery_generation, # noqa: SLF001 "expected_desired_mode": "bridge", "expected_desired_mode_revision": 0, "device_io_performed": False, "automatic_retry": False, } io_calls: list[str] = [] async def forbidden_async_io(*_args: object, **_kwargs: object) -> object: io_calls.append("ble-or-wifi") raise AssertionError("reopen must remain local-only") def forbidden_sync_io(*_args: object, **_kwargs: object) -> object: io_calls.append("mqtt-tcp-monitor") raise AssertionError("reopen must remain local-only") monkeypatch.setattr(facade_module, "read_wifi_status_once", forbidden_async_io) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_async_io) monkeypatch.setattr(service, "_probe_control_endpoint", forbidden_sync_io) reopen_request = ReopenRetiredPhysicalCommandReconciliationRequest( reopening_id="reopening-explicit-fresh-row", expected_revision=projection["expected_revision"], expected_retirement_id=projection["expected_retirement_id"], expected_transport_ref=projection["expected_transport_ref"], expected_discovery_generation=projection["expected_discovery_generation"], expected_desired_mode=projection["expected_desired_mode"], expected_desired_mode_revision=projection["expected_desired_mode_revision"], operator_confirmed=True, reason="device-returned-for-explicit-reconciliation", ) result = service.reopen_retired_physical_command_reconciliation(reopen_request) # A lost HTTP response is retried against the durable audit, not against # the now-consumed projection. The retry must return usable state without # appending another reopen or reacquiring BLE/network ownership. retried = service.reopen_retired_physical_command_reconciliation(reopen_request) physical = result["physical_command"] assert physical["status"] == "unresolved" assert physical["requires_reconciliation"] is True assert physical["record"]["stage"] == "observing" assert physical["record"]["resolution"] is None assert physical["record"]["operator_retirements"][0]["retirement_id"] == ( retirement.retirement_id ) assert ( physical["record"]["operator_reconciliation_reopens"][0]["reopening_id"] == "reopening-explicit-fresh-row" ) assert len(retried["physical_command"]["record"]["operator_reconciliation_reopens"]) == 1 assert ( retried["connection_policy"]["actions"]["observe-fresh-device-network"]["allowed"] is True ) assert result["snapshot_runtime_id"] == before["snapshot_runtime_id"] assert retried["snapshot_runtime_id"] == before["snapshot_runtime_id"] assert result["snapshot_revision"] > before["snapshot_revision"] assert ( service._ble_discovery_generation == projection[ # noqa: SLF001 "expected_discovery_generation" ] ) assert result["k1_lifecycle_process_lease"] == { "held_by_current_service": False, "holders": [], "process_lease_quarantined": False, "reason_code": None, "restart_required": False, } observe_action = result["connection_policy"]["actions"]["observe-fresh-device-network"] assert observe_action["allowed"] is True assert observe_action["required_transport_ref"] == DURABLE_K1_UUID assert observe_action["required_connection_mode"] == "bridge" assert result["connection_policy"]["actions"]["provision-fresh-device"]["allowed"] is False assert result["connection_policy"]["actions"]["start-acquisition"]["allowed"] is False assert result["connection_policy"]["actions"]["stop-acquisition"]["allowed"] is False assert result["connection_lifecycle"]["mode_selection"]["allowed"] is False assert result["connection_policy"]["facts"]["retired_transport_refs"] == [] assert ( DURABLE_K1_UUID.lower() in result["connection_policy"]["facts"]["eligible_fresh_transport_refs"] ) assert service._operations.snapshot() == before_operations # noqa: SLF001 assert runtime.start_calls == before_runtime_starts assert runtime.stop_calls == before_runtime_stops assert io_calls == [] @pytest.mark.parametrize("observed_session_state", ["ready", "scanning"]) def test_casefolded_reopened_uuid_uses_actual_fresh_ref_and_verify_reconciles_state( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, observed_session_state: str, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) binding = _seed_supervised_connection( service, transport_ref=DURABLE_K1_UUID, connection_mode="bridge", ) retirement = _seed_unresolved_physical_stop_for_retirement(service, binding) service.retire_unavailable_physical_command(retirement) # Retirement records the durable UUID exactly as originally observed. A # later CoreBluetooth scan may return the same UUID with different case. _set_scanned_k1(service, device_id=DURABLE_K1_UUID.lower()) with service._lock: # noqa: SLF001 service._ble_discovery_generation += 1 # noqa: SLF001 _set_scanned_k1(service, device_id=DURABLE_K1_UUID.lower()) projection = service._physical_operator_reconciliation_reopen_projection() # noqa: SLF001 reopened = service.reopen_retired_physical_command_reconciliation( ReopenRetiredPhysicalCommandReconciliationRequest( reopening_id="reopening-casefolded-end-to-end", expected_revision=projection["expected_revision"], expected_retirement_id=projection["expected_retirement_id"], expected_transport_ref=projection["expected_transport_ref"], expected_discovery_generation=projection["expected_discovery_generation"], expected_desired_mode=projection["expected_desired_mode"], expected_desired_mode_revision=projection["expected_desired_mode_revision"], operator_confirmed=True, reason="device-returned-for-explicit-reconciliation", ) ) observation = reopened["connection_policy"]["actions"]["observe-fresh-device-network"] assert observation["allowed"] is True assert observation["required_transport_ref"] == DURABLE_K1_UUID actual_ref = DURABLE_K1_UUID.lower() capture = _SYNTHETIC_SCAN_CAPTURES[actual_ref] capture_calls: list[str] = [] status_reads: list[str] = [] forbidden_mutations: list[str] = [] def capture_actual(device_id: str) -> facade_module.CapturedDiscoveredDevice | None: capture_calls.append(device_id) return capture if device_id == actual_ref else None async def read_status( device_id: str, *, captured_device: facade_module.CapturedDiscoveredDevice | None, on_gatt_validated: Callable[[facade_module.CapturedDiscoveredDevice], None], **_: object, ) -> dict[str, Any]: status_reads.append(device_id) assert captured_device is capture on_gatt_validated(capture) return _wifi_status_read("10.255.254.77", device_id=device_id) async def forbidden_provision(*_: object, **__: object) -> object: forbidden_mutations.append("wifi") raise AssertionError("explicit Verify must not provision Wi-Fi") monkeypatch.setattr(facade_module, "capture_discovered_device", capture_actual) monkeypatch.setattr(facade_module, "read_wifi_status_once", read_status) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_provision) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr( facade_module, "_host_route_class", lambda _target: "direct-or-routed", ) monkeypatch.setattr(facade_module, "_control_endpoint_reachable", lambda _target: True) monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) coordinator = service._physical_command_coordinator # noqa: SLF001 async def bootstrap_ready_proof( bound_service: XgridsK1CompatibilityService, *, parent_operation_id: str | None, connection_mode: facade_module.ConnectionMode, inspection_only: bool = False, ) -> None: await _synthetic_prestart_control_bootstrap( bound_service, parent_operation_id=parent_operation_id, connection_mode=connection_mode, inspection_only=inspection_only, ) verified = bound_service._application_control_session.snapshot().get( # noqa: SLF001 "verified_control" ) assert isinstance(verified, dict) coordinator.application_response( ApplicationMqttResponseEvidence( operation_key="bootstrap:casefold:DeviceInfoRequest", response_topic="lixel/application/response/device_info", payload_sha256="9" * 64, modeling_action=None, result_code=None, success=None, observed_at_utc="2026-08-10T12:00:00.000Z", ) ) coordinator.bind_control_session( PhysicalCommandRuntimeBinding( vendor_device_id_sha256=hashlib.sha256(b"retirement-vendor").hexdigest(), device_serial_sha256=hashlib.sha256(b"retirement-serial").hexdigest(), compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, intent_id=str(verified["intent_id"]), transport_ref=str(verified["transport_ref"]), connection_mode=verified["connection_mode"], # type: ignore[arg-type] target_ipv4=str(verified["target_ipv4"]), target_port=int(verified["target_port"]), host_path_epoch=int(verified["host_path_epoch"]), control_session_id=str(verified["control_session_id"]), producer_generation=int(verified["producer_generation"]), ) ) coordinator.device_status( ApplicationMqttDeviceStatusEvidence( vendor_device_id_sha256=hashlib.sha256(b"retirement-vendor").hexdigest(), device_serial_sha256=hashlib.sha256(b"retirement-serial").hexdigest(), session_state=observed_session_state, session_state_code=( MODELING_STATE_BASE + (300 if observed_session_state == "ready" else 302) ), project_bound=observed_session_state == "scanning", project_id_sha256=("5" * 64 if observed_session_state == "scanning" else None), init_ready=observed_session_state == "scanning", status_message_sha256="8" * 64, mqtt_retained=False, observed_at_utc="2026-08-10T12:00:01.000Z", ) ) bound_service._acquire_application_control_process_lease() # noqa: SLF001 service._bootstrap_prestart_control_ready_owned = MethodType( # type: ignore[method-assign] # noqa: SLF001 bootstrap_ready_proof, service, ) result = asyncio.run( service.verify_connection( ConnectionVerifyRequest( # The frontend follows the server policy, whose durable # physical recovery target retains the original uppercase # spelling. Backend lookup must resolve that to the current # lowercase advert before any native BLE call. device_id=observation["required_transport_ref"], source="fresh-scan", compatibility_attestation=ATTESTATION, operation_id="op-00000000-0000-4000-8000-000000001240", expected_discovery_generation=projection["expected_discovery_generation"], ) ) ) assert capture_calls == [actual_ref] assert status_reads == [actual_ref] assert result["selected_device_id"] == actual_ref assert result["physical_command"]["record"]["resolution"] == ( "physical-standby-observed" if observed_session_state == "ready" else "physical-active-observed" ) assert ( result["physical_command"]["record"]["operator_retirements"][0]["retired_transport_ref"] == DURABLE_K1_UUID ) assert ( result["physical_command"]["record"]["operator_reconciliation_reopens"][0][ "reopened_transport_ref" ] == actual_ref ) assert forbidden_mutations == [] assert runtime.start_calls == [] assert runtime.stop_calls == 0 if observed_session_state == "scanning": assert result["connection_policy"]["actions"]["provision-fresh-device"]["allowed"] is False assert result["connection_policy"]["actions"]["start-acquisition"]["allowed"] is False assert result["application_control_session"]["can_stop"] is True assert result["connection_policy"]["actions"]["stop-acquisition"]["allowed"] is True, ( result["connection_policy"]["actions"]["stop-acquisition"] ) assert result["acquisition"]["result"]["recovery_only"] is True def _retired_fresh_reopen_request( service: XgridsK1CompatibilityService, *, reopening_id: str, connection_mode: facade_module.ConnectionMode = "bridge", ) -> ReopenRetiredPhysicalCommandReconciliationRequest: if connection_mode != "bridge": _select_connection_mode(service, connection_mode) binding = _seed_supervised_connection( service, transport_ref=DURABLE_K1_UUID, connection_mode=connection_mode, ) retirement = _seed_unresolved_physical_stop_for_retirement(service, binding) service.retire_unavailable_physical_command(retirement) with service._lock: # noqa: SLF001 service._ble_discovery_generation += 1 # noqa: SLF001 _set_scanned_k1(service, device_id=DURABLE_K1_UUID.lower()) projection = service._physical_operator_reconciliation_reopen_projection() # noqa: SLF001 assert projection["allowed"] is True return ReopenRetiredPhysicalCommandReconciliationRequest( reopening_id=reopening_id, expected_revision=projection["expected_revision"], expected_retirement_id=projection["expected_retirement_id"], expected_transport_ref=projection["expected_transport_ref"], expected_discovery_generation=projection["expected_discovery_generation"], expected_desired_mode=projection["expected_desired_mode"], expected_desired_mode_revision=projection["expected_desired_mode_revision"], operator_confirmed=True, reason="device-returned-for-explicit-reconciliation", ) def test_physical_reopen_final_checkpoint_conflict_is_http_409_without_device_io( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) request = _retired_fresh_reopen_request( service, reopening_id="reopening-cross-process-ledger-race", ) before = service.state() before_record = service._physical_command_ledger.snapshot().record # noqa: SLF001 before_operations = service._operations.snapshot() # noqa: SLF001 io_calls: list[str] = [] ledger_calls: list[str] = [] async def forbidden_async_io(*_args: object, **_kwargs: object) -> object: io_calls.append("ble-or-wifi") raise AssertionError("reopen checkpoint conflict must not reach device I/O") def forbidden_sync_io(*_args: object, **_kwargs: object) -> object: io_calls.append("mqtt-tcp-monitor") raise AssertionError("reopen checkpoint conflict must not probe the device") def conflicting_final_cas(*_args: object, **_kwargs: object) -> object: ledger_calls.append("reopen") raise PhysicalCommandTransitionError( "physical command reconciliation reopen used a stale record revision" ) monkeypatch.setattr(facade_module, "read_wifi_status_once", forbidden_async_io) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_async_io) monkeypatch.setattr(service, "_probe_control_endpoint", forbidden_sync_io) monkeypatch.setattr( service._physical_command_coordinator, # noqa: SLF001 "reopen_retired_reconciliation", conflicting_final_cas, ) adapter = XgridsK1PluginFacade(service) with pytest.raises(PluginExecutionError) as raised: asyncio.run( adapter.invoke( RuntimeActionInvocation( invocation_id="reopening-cross-process-ledger-race", plugin_id=adapter.plugin_id, action_id=(ACTION_PHYSICAL_COMMAND_REOPEN_RETIRED_RECONCILIATION), requested_at=datetime.now(UTC), parameters={ **request.model_dump(mode="json"), "expected_snapshot_runtime_id": before["snapshot_runtime_id"], }, ) ) ) assert raised.value.http_status_code == 409 assert raised.value.reason_code == ("physical-command-reconciliation-reopen-stale-checkpoint") assert ledger_calls == ["reopen"] assert service._physical_command_ledger.snapshot().record == before_record # noqa: SLF001 assert service._operations.snapshot() == before_operations # noqa: SLF001 assert service._application_control_process_lease_holders == set() # noqa: SLF001 assert runtime.start_calls == [] assert runtime.stop_calls == 0 assert io_calls == [] def test_reopen_projection_rejects_a_different_local_mode_draft_without_mutation( tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) request = _retired_fresh_reopen_request( service, reopening_id="reopening-mode-mismatch", ) before_record = service._physical_command_ledger.snapshot().record # noqa: SLF001 before_operations = service._operations.snapshot() # noqa: SLF001 before_generation = service._ble_discovery_generation # noqa: SLF001 switched_revision = _select_connection_mode(service, "quick-connect") projection = service._physical_operator_reconciliation_reopen_projection() # noqa: SLF001 assert switched_revision == 1 assert projection["allowed"] is False assert projection["reason_codes"] == ["physical-command-reconciliation-reopen-mode-mismatch"] with pytest.raises(facade_module.NetworkProvisioningConflict) as blocked: service.reopen_retired_physical_command_reconciliation(request) assert blocked.value.reason_code == ("physical-command-reconciliation-reopen-mode-mismatch") assert service._physical_command_ledger.snapshot().record == before_record # noqa: SLF001 assert service._operations.snapshot() == before_operations # noqa: SLF001 assert service._ble_discovery_generation == before_generation # noqa: SLF001 assert runtime.start_calls == [] assert runtime.stop_calls == 0 def test_reopen_rejects_desired_mode_revision_aba_without_consuming_checkpoint( tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) stale_request = _retired_fresh_reopen_request( service, reopening_id="reopening-mode-revision-aba", ) before_record = service._physical_command_ledger.snapshot().record # noqa: SLF001 before_operations = service._operations.snapshot() # noqa: SLF001 _select_connection_mode(service, "quick-connect") current_revision = _select_connection_mode(service, "bridge") projection = service._physical_operator_reconciliation_reopen_projection() # noqa: SLF001 assert current_revision == 2 assert projection["allowed"] is True assert projection["expected_desired_mode"] == "bridge" assert projection["expected_desired_mode_revision"] == 2 with pytest.raises(facade_module.NetworkProvisioningConflict) as stale: service.reopen_retired_physical_command_reconciliation(stale_request) assert stale.value.reason_code == ("physical-command-reconciliation-reopen-stale-checkpoint") assert service._physical_command_ledger.snapshot().record == before_record # noqa: SLF001 assert service._operations.snapshot() == before_operations # noqa: SLF001 assert runtime.start_calls == [] assert runtime.stop_calls == 0 def test_reopen_freezes_mode_draft_until_physical_observation_terminalizes( tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) request = _retired_fresh_reopen_request( service, reopening_id="reopening-freezes-mode-draft", ) reopened = service.reopen_retired_physical_command_reconciliation(request) reopened_record = service._physical_command_ledger.snapshot().record # noqa: SLF001 assert reopened["physical_command"]["requires_reconciliation"] is True assert reopened["connection_lifecycle"]["mode_selection"]["allowed"] is False assert ( "connection-mode-selection-physical-state-unsafe" in reopened["connection_lifecycle"]["mode_selection"]["reason_codes"] ) with pytest.raises(facade_module.NetworkProvisioningConflict) as blocked: _select_connection_mode(service, "quick-connect") assert blocked.value.reason_code == ("connection-mode-selection-physical-state-unsafe") assert service._physical_command_ledger.snapshot().record == reopened_record # noqa: SLF001 assert service.state()["desired_connection_mode"] == "bridge" assert service.state()["desired_connection_mode_revision"] == 0 assert runtime.start_calls == [] assert runtime.stop_calls == 0 def test_restarted_peer_can_align_only_to_pending_reopen_mode_without_io( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: owner, _ = service_with_fake_runtime(tmp_path) request = _retired_fresh_reopen_request( owner, reopening_id="reopening-quick-restart-mode-alignment", connection_mode="quick-connect", ) owner.reopen_retired_physical_command_reconciliation(request) restarted, restarted_runtime = service_with_fake_runtime(tmp_path) before_record = restarted._physical_command_ledger.snapshot().record # noqa: SLF001 device_edges: list[str] = [] monkeypatch.setattr( facade_module, "scan", lambda *_args, **_kwargs: device_edges.append("scan"), ) monkeypatch.setattr( facade_module, "provision_wifi_once", lambda *_args, **_kwargs: device_edges.append("network-write"), ) before = restarted.state() assert before["desired_connection_mode"] == "bridge" assert before["connection_lifecycle"]["mode_selection"]["allowed"] is True aligned = restarted.select_connection_mode( DesiredConnectionModeRequest( connection_mode="quick-connect", expected_revision=before["desired_connection_mode_revision"], ) ) assert aligned["desired_connection_mode"] == "quick-connect" assert aligned["desired_connection_mode_revision"] == 1 assert aligned["connection_lifecycle"]["mode_selection"]["allowed"] is False assert restarted._physical_command_ledger.snapshot().record == before_record # noqa: SLF001 assert restarted_runtime.start_calls == [] assert restarted_runtime.stop_calls == 0 assert device_edges == [] def _install_real_retirement_ready_bootstrap( service: XgridsK1CompatibilityService, ) -> None: """Feed exact fresh DeviceInfo/READY evidence to the real coordinator.""" coordinator = service._physical_command_coordinator # noqa: SLF001 async def bootstrap_ready_proof( bound_service: XgridsK1CompatibilityService, *, parent_operation_id: str | None, connection_mode: facade_module.ConnectionMode, inspection_only: bool = False, ) -> None: await _synthetic_prestart_control_bootstrap( bound_service, parent_operation_id=parent_operation_id, connection_mode=connection_mode, inspection_only=inspection_only, ) verified = bound_service._application_control_session.snapshot().get( # noqa: SLF001 "verified_control" ) assert isinstance(verified, dict) vendor_hash = hashlib.sha256(b"retirement-vendor").hexdigest() serial_hash = hashlib.sha256(b"retirement-serial").hexdigest() coordinator.application_response( ApplicationMqttResponseEvidence( operation_key="bootstrap:retirement:DeviceInfoRequest", response_topic="lixel/application/response/device_info", payload_sha256="7" * 64, modeling_action=None, result_code=None, success=None, observed_at_utc="2026-08-10T12:10:00.000Z", ) ) coordinator.bind_control_session( PhysicalCommandRuntimeBinding( vendor_device_id_sha256=vendor_hash, device_serial_sha256=serial_hash, compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, intent_id=str(verified["intent_id"]), transport_ref=str(verified["transport_ref"]), connection_mode=verified["connection_mode"], # type: ignore[arg-type] target_ipv4=str(verified["target_ipv4"]), target_port=int(verified["target_port"]), host_path_epoch=int(verified["host_path_epoch"]), control_session_id=str(verified["control_session_id"]), producer_generation=int(verified["producer_generation"]), ) ) coordinator.device_status( ApplicationMqttDeviceStatusEvidence( vendor_device_id_sha256=vendor_hash, device_serial_sha256=serial_hash, session_state="ready", session_state_code=MODELING_STATE_BASE + 300, project_bound=False, project_id_sha256=None, init_ready=False, status_message_sha256="6" * 64, mqtt_retained=False, observed_at_utc="2026-08-10T12:10:01.000Z", ) ) bound_service._acquire_application_control_process_lease() # noqa: SLF001 service._bootstrap_prestart_control_ready_owned = MethodType( # type: ignore[method-assign] # noqa: SLF001 bootstrap_ready_proof, service, ) def test_reopened_verify_network_unavailable_stays_unresolved_and_can_retry_exactly( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) reopen_request = _retired_fresh_reopen_request( service, reopening_id="reopening-network-unavailable-retry", ) reopened = service.reopen_retired_physical_command_reconciliation(reopen_request) observation = reopened["connection_policy"]["actions"]["observe-fresh-device-network"] durable_ref = str(observation["required_transport_ref"]) actual_ref = reopen_request.expected_transport_ref capture = _SYNTHETIC_SCAN_CAPTURES[actual_ref] observed_addresses: list[str | None] = [None] status_reads: list[str] = [] forbidden_mutations: list[str] = [] monkeypatch.setattr( facade_module, "capture_discovered_device", lambda device_id: capture if device_id == actual_ref else None, ) async def read_status( device_id: str, *, captured_device: facade_module.CapturedDiscoveredDevice | None, on_gatt_validated: Callable[[facade_module.CapturedDiscoveredDevice], None], **_: object, ) -> dict[str, Any]: status_reads.append(device_id) assert captured_device is capture on_gatt_validated(capture) return _wifi_status_read(observed_addresses[0], device_id=device_id) async def forbidden_provision(*_: object, **__: object) -> object: forbidden_mutations.append("wifi") raise AssertionError("network-unavailable Verify must not provision") monkeypatch.setattr(facade_module, "read_wifi_status_once", read_status) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_provision) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr( facade_module, "_host_route_class", lambda _target: "direct-or-routed", ) monkeypatch.setattr(facade_module, "_control_endpoint_reachable", lambda _target: True) monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) with pytest.raises(facade_module.ConnectionVerificationError) as unavailable: asyncio.run( service.verify_connection( ConnectionVerifyRequest( device_id=durable_ref, source="fresh-scan", compatibility_attestation=ATTESTATION, operation_id="op-00000000-0000-4000-8000-000000001241", expected_discovery_generation=(reopen_request.expected_discovery_generation), ) ) ) assert unavailable.value.reason_code == "connection-verify-address-unavailable" failed = service.state() assert failed["connection_verification"]["status"] == "unreachable" assert failed["connection_verification"]["network_reachability"] == ("unreachable") assert failed["connection_verification"]["reason_code"] == ( "connection-verify-address-unavailable" ) assert failed["physical_command"]["status"] == "unresolved" assert failed["physical_command"]["requires_reconciliation"] is True assert failed["connection_policy"]["facts"]["retired_transport_refs"] == [] assert failed["physical_command"]["operator_retirement"]["allowed"] is True assert failed["connection_policy"]["actions"]["provision-fresh-device"]["allowed"] is False assert failed["connection_policy"]["actions"]["start-acquisition"]["allowed"] is False assert failed["connection_policy"]["actions"]["stop-acquisition"]["allowed"] is False # The disconnected selector was freely editable before this exact reopen. # The admitted reopen now freezes that mode CAS until the immediately owned # read-only observation terminalizes, so another tab cannot strand it. assert failed["connection_lifecycle"]["mode_selection"]["allowed"] is False assert ( "connection-mode-selection-physical-state-unsafe" in failed["connection_lifecycle"]["mode_selection"]["reason_codes"] ) assert service._application_control_process_lease_holders == set() # noqa: SLF001 # Restoring the old route does not replay anything. The operator can # explicitly run the same server-bound observation against the still-fresh # exact candidate and reconcile READY. observed_addresses[0] = "10.255.254.77" _install_real_retirement_ready_bootstrap(service) recovered = asyncio.run( service.verify_connection( ConnectionVerifyRequest( device_id=durable_ref, source="fresh-scan", compatibility_attestation=ATTESTATION, operation_id="op-00000000-0000-4000-8000-000000001242", expected_discovery_generation=(reopen_request.expected_discovery_generation), ) ) ) assert status_reads == [actual_ref, actual_ref] assert recovered["physical_command"]["record"]["resolution"] == ("physical-standby-observed") assert forbidden_mutations == [] assert runtime.start_calls == [] assert runtime.stop_calls == 0 @pytest.mark.parametrize( ("blocker", "reason_code"), [ ("network", "network-provision-operation-active"), ("control", "control-session-not-admissible-for-network-change"), ("lifecycle", "k1-lifecycle-process-lease-control-owned"), ("ble", "ble-runtime-busy"), ( "nonconnectable", "physical-command-reconciliation-reopen-target-not-connectable", ), ], ) def test_reopen_projection_blocks_live_owners_before_durable_or_device_action( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, blocker: str, reason_code: str, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) request = _retired_fresh_reopen_request( service, reopening_id=f"reopening-blocked-{blocker}", ) before = service._physical_command_ledger.snapshot().record # noqa: SLF001 assert before is not None native = dict(facade_module.ble_runtime_snapshot()) if blocker == "network": service._provisioning_active = True # noqa: SLF001 elif blocker == "control": service._application_control_session = FakeInteractiveControlSession( # type: ignore[assignment] # noqa: SLF001 initial_state="workspace-ready" ) elif blocker == "lifecycle": service._application_control_process_lease_holders.add("control") # noqa: SLF001 elif blocker == "ble": native["active_operation_kind"] = "scan" monkeypatch.setattr(facade_module, "ble_runtime_snapshot", lambda: native) elif blocker == "nonconnectable": service._devices[0]["connectable"] = False # noqa: SLF001 else: # pragma: no cover - exhaustive test table raise AssertionError(blocker) projection = service._physical_operator_reconciliation_reopen_projection() # noqa: SLF001 assert projection["allowed"] is False assert reason_code in projection["reason_codes"] with pytest.raises(facade_module.NetworkProvisioningConflict) as blocked: service.reopen_retired_physical_command_reconciliation(request) assert blocked.value.reason_code == reason_code assert service._physical_command_ledger.snapshot().record == before # noqa: SLF001 assert runtime.start_calls == [] assert runtime.stop_calls == 0 @pytest.mark.parametrize("safe_to_retry", [False, True]) def test_reopen_uses_the_same_failed_control_admission_as_fresh_verify( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, safe_to_retry: bool, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) request = _retired_fresh_reopen_request( service, reopening_id=f"reopening-failed-control-{safe_to_retry}", ) before = service._physical_command_ledger.snapshot().record # noqa: SLF001 control = FakeInteractiveControlSession(initial_state="failed") base_snapshot = control.snapshot def failed_snapshot() -> dict[str, object]: return { **base_snapshot(), "failure": { "safe_to_retry": safe_to_retry, "network_change_admissible": False, }, } monkeypatch.setattr(control, "snapshot", failed_snapshot) service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 projection = service._physical_operator_reconciliation_reopen_projection() # noqa: SLF001 if not safe_to_retry: assert projection["allowed"] is False assert "control-session-not-admissible-for-network-change" in projection["reason_codes"] with pytest.raises(facade_module.NetworkProvisioningConflict) as blocked: service.reopen_retired_physical_command_reconciliation(request) assert blocked.value.reason_code == ("control-session-not-admissible-for-network-change") assert service._physical_command_ledger.snapshot().record == before # noqa: SLF001 else: assert projection["allowed"] is True assert runtime.start_calls == [] assert runtime.stop_calls == 0 @pytest.mark.parametrize( ("blocker", "reason_code"), [ ("supervisor", "connection-supervisor-closed"), ("idempotency-unavailable", "network-provisioning-idempotency-unavailable"), ("idempotency-corrupt", "network-provisioning-idempotency-corrupt"), ("topology-corrupt", "semantic-topology-store-corrupt"), ("identity-corrupt", "device-identity-pin-store-corrupt"), ("network-ledger-corrupt", "network-mutation-ledger-corrupt"), ("foreign-reconciliation", "reconciliation-target-not-observed"), ], ) def test_reopen_rejects_unchanged_post_reopen_verify_blockers_before_commit( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, blocker: str, reason_code: str, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) request = _retired_fresh_reopen_request( service, reopening_id=f"reopening-environment-blocked-{blocker}", ) before = service._physical_command_ledger.snapshot().record # noqa: SLF001 if blocker == "supervisor": monkeypatch.setattr( service._connection_supervisor, # noqa: SLF001 "snapshot", lambda: SimpleNamespace(closed=True), ) elif blocker == "idempotency-unavailable": service._network_provisioning_idempotency_journal = None # noqa: SLF001 elif blocker == "idempotency-corrupt": monkeypatch.setattr( service, "_network_provisioning_idempotency_public_snapshot", lambda: {"status": "corrupt"}, ) elif blocker == "topology-corrupt": monkeypatch.setattr( service, "_semantic_topology_public_snapshot", lambda: {"status": "corrupt"}, ) elif blocker == "identity-corrupt": monkeypatch.setattr( service, "_device_identity_pin_public_snapshot", lambda: {"status": "corrupt"}, ) elif blocker == "network-ledger-corrupt": monkeypatch.setattr( service._network_mutation_ledger, # noqa: SLF001 "snapshot", lambda: SimpleNamespace(status="corrupt", record=None), ) elif blocker == "foreign-reconciliation": monkeypatch.setattr( service, "_network_provisioning_idempotency_public_snapshot", lambda: { "status": "blocked", "active_operation_id": "foreign-network-operation", "active_action": facade_module.ACTION_NETWORK_PROVISION, "active_stage": "unresolved", }, ) monkeypatch.setattr( service._network_mutation_ledger, # noqa: SLF001 "snapshot", lambda: SimpleNamespace( status="unresolved", record=SimpleNamespace( operation_id="foreign-network-operation", stage="dispatching", resolution=None, transport_ref="foreign-transport", intended_mode="bridge", ), ), ) else: # pragma: no cover - exhaustive parameter table raise AssertionError(blocker) projection = service._physical_operator_reconciliation_reopen_projection() # noqa: SLF001 assert projection["allowed"] is False assert reason_code in projection["reason_codes"] with pytest.raises(facade_module.NetworkProvisioningConflict) as blocked: service.reopen_retired_physical_command_reconciliation(request) assert blocked.value.reason_code == reason_code assert service._physical_command_ledger.snapshot().record == before # noqa: SLF001 assert runtime.start_calls == [] assert runtime.stop_calls == 0 @pytest.mark.parametrize( ("audit_shape", "reason_code"), [ ( "different-unresolved-operation", "network-provisioning-idempotency-operation-mismatch", ), ( "unresolved-ledger-without-idempotency", "network-provisioning-idempotency-operation-mismatch", ), ( "active-idempotency-without-ledger", "network-provisioning-idempotency-ledger-mismatch", ), ( "same-operation-prepared-prepared", "network-provisioning-idempotency-ledger-mismatch", ), ], ) def test_reopen_rejects_unexecutable_network_audit_pairing_before_lease_or_io( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, audit_shape: str, reason_code: str, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) request = _retired_fresh_reopen_request( service, reopening_id=f"reopening-audit-blocked-{audit_shape}", ) operation_id = f"network-audit-{audit_shape}" if audit_shape == "different-unresolved-operation": _seed_unresolved_network_mutation( service, operation_id=operation_id, idempotency_operation_id=f"{operation_id}-other", transport_ref=request.expected_transport_ref, ) elif audit_shape == "unresolved-ledger-without-idempotency": prepared = _prepare_network_mutation_for_reopen( service, operation_id=operation_id, transport_ref=request.expected_transport_ref, intended_mode="bridge", ) service._network_mutation_ledger.mark_dispatching( # noqa: SLF001 operation_id, expected_revision=prepared.revision, ) elif audit_shape == "active-idempotency-without-ledger": _begin_network_idempotency_for_reopen( service, operation_id=operation_id, mark_unresolved=True, ) elif audit_shape == "same-operation-prepared-prepared": _prepare_network_mutation_for_reopen( service, operation_id=operation_id, transport_ref=request.expected_transport_ref, intended_mode="bridge", ) _begin_network_idempotency_for_reopen( service, operation_id=operation_id, mark_unresolved=False, ) else: # pragma: no cover - exhaustive parameter table raise AssertionError(audit_shape) physical_before = service._physical_command_ledger.snapshot().record # noqa: SLF001 network_before = service._network_mutation_ledger.snapshot() # noqa: SLF001 idempotency_before = ( # noqa: SLF001 service._require_network_provisioning_idempotency_journal().snapshot() ) operations_before = service._operations.snapshot() # noqa: SLF001 lease_calls: list[str] = [] io_calls: list[str] = [] def forbidden_lease(*_args: object, **_kwargs: object) -> None: lease_calls.append("lease") raise AssertionError("rejected reopen must not acquire the lifecycle lease") async def forbidden_async_io(*_args: object, **_kwargs: object) -> object: io_calls.append("device-io") raise AssertionError("rejected reopen must not perform device I/O") monkeypatch.setattr(service, "_acquire_k1_lifecycle_process_lease", forbidden_lease) monkeypatch.setattr(facade_module, "read_wifi_status_once", forbidden_async_io) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_async_io) monkeypatch.setattr( service, "_probe_control_endpoint", lambda *_args, **_kwargs: io_calls.append("endpoint-io"), ) projection = service._physical_operator_reconciliation_reopen_projection() # noqa: SLF001 assert projection["allowed"] is False assert reason_code in projection["reason_codes"] with pytest.raises(facade_module.NetworkProvisioningConflict) as blocked: service.reopen_retired_physical_command_reconciliation(request) assert blocked.value.reason_code == reason_code assert service._physical_command_ledger.snapshot().record == physical_before # noqa: SLF001 assert service._network_mutation_ledger.snapshot() == network_before # noqa: SLF001 assert ( # noqa: SLF001 service._require_network_provisioning_idempotency_journal().snapshot() == idempotency_before ) assert service._operations.snapshot() == operations_before # noqa: SLF001 assert lease_calls == [] assert io_calls == [] assert runtime.start_calls == [] assert runtime.stop_calls == 0 def test_reopen_rejects_unresolved_network_mode_conflict_before_lease_or_io( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) request = _retired_fresh_reopen_request( service, reopening_id="reopening-network-mode-conflict", ) _seed_unresolved_network_mutation( service, operation_id="network-mode-conflict", transport_ref=request.expected_transport_ref.upper(), intended_mode="quick-connect", ) physical_before = service._physical_command_ledger.snapshot().record # noqa: SLF001 network_before = service._network_mutation_ledger.snapshot() # noqa: SLF001 idempotency_before = ( # noqa: SLF001 service._require_network_provisioning_idempotency_journal().snapshot() ) lease_calls: list[str] = [] io_calls: list[str] = [] monkeypatch.setattr( service, "_acquire_k1_lifecycle_process_lease", lambda *_args, **_kwargs: lease_calls.append("lease"), ) monkeypatch.setattr( facade_module, "read_wifi_status_once", lambda *_args, **_kwargs: io_calls.append("gatt-read"), ) monkeypatch.setattr( facade_module, "provision_wifi_once", lambda *_args, **_kwargs: io_calls.append("gatt-write"), ) projection = service._physical_operator_reconciliation_reopen_projection() # noqa: SLF001 assert projection["allowed"] is False assert "reconciliation-target-mode-mismatch" in projection["reason_codes"] with pytest.raises(facade_module.NetworkProvisioningConflict) as blocked: service.reopen_retired_physical_command_reconciliation(request) assert blocked.value.reason_code == "reconciliation-target-mode-mismatch" assert service._physical_command_ledger.snapshot().record == physical_before # noqa: SLF001 assert service._network_mutation_ledger.snapshot() == network_before # noqa: SLF001 assert ( # noqa: SLF001 service._require_network_provisioning_idempotency_journal().snapshot() == idempotency_before ) assert lease_calls == [] assert io_calls == [] assert runtime.start_calls == [] assert runtime.stop_calls == 0 @pytest.mark.parametrize( "audit_shape", [ "prepared-without-idempotency", "prepared-with-matching-unresolved-idempotency", "resolved-not-dispatched-with-matching-unresolved-idempotency", "resolved-target-observed-with-matching-unresolved-idempotency", ], ) def test_reopen_admits_network_audit_shapes_verify_can_repair_exactly( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, audit_shape: str, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) request = _retired_fresh_reopen_request( service, reopening_id=f"reopening-repairable-{audit_shape}", ) operation_id = f"network-repairable-{audit_shape}" prepared = _prepare_network_mutation_for_reopen( service, operation_id=operation_id, transport_ref=request.expected_transport_ref, # PREPARED is deterministically closed as not-dispatched before Verify # chooses the physical recovery mode, so this difference is repairable. intended_mode=("quick-connect" if audit_shape.startswith("prepared-") else "bridge"), ) if "matching-unresolved-idempotency" in audit_shape: _begin_network_idempotency_for_reopen( service, operation_id=operation_id, mark_unresolved=True, ) if audit_shape.startswith("resolved-not-dispatched"): service._network_mutation_ledger.resolve( # noqa: SLF001 operation_id, expected_revision=prepared.revision, resolution="not-dispatched", ) elif audit_shape.startswith("resolved-target-observed"): dispatching = service._network_mutation_ledger.mark_dispatching( # noqa: SLF001 operation_id, expected_revision=prepared.revision, ) service._network_mutation_ledger.resolve( # noqa: SLF001 operation_id, expected_revision=dispatching.revision, resolution="target-observed", observation=NetworkStatusEvidence( mode="WIFI_CLIENT", ipv4="192.168.68.51", status_code=1, reserved=0, ), ) network_before = service._network_mutation_ledger.snapshot() # noqa: SLF001 idempotency_before = ( # noqa: SLF001 service._require_network_provisioning_idempotency_journal().snapshot() ) io_calls: list[str] = [] monkeypatch.setattr( facade_module, "read_wifi_status_once", lambda *_args, **_kwargs: io_calls.append("gatt-read"), ) monkeypatch.setattr( facade_module, "provision_wifi_once", lambda *_args, **_kwargs: io_calls.append("gatt-write"), ) projection = service._physical_operator_reconciliation_reopen_projection() # noqa: SLF001 assert projection["allowed"] is True, projection reopened = service.reopen_retired_physical_command_reconciliation(request) assert reopened["physical_command"]["requires_reconciliation"] is True assert ( reopened["connection_policy"]["actions"]["observe-fresh-device-network"]["allowed"] is True ) assert service._network_mutation_ledger.snapshot() == network_before # noqa: SLF001 assert ( # noqa: SLF001 service._require_network_provisioning_idempotency_journal().snapshot() == idempotency_before ) assert io_calls == [] assert runtime.start_calls == [] assert runtime.stop_calls == 0 def test_fresh_observation_requires_network_and_physical_recovery_same_target( tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_devices( service, [ {"device_id": "physical-k1", "connectable": True}, {"device_id": "network-k1", "connectable": True}, ], ) _seed_unresolved_network_mutation( service, operation_id="network-other-fresh-target", transport_ref="network-k1", intended_mode="bridge", ) policy = _project_connection_policy_for_test( service, physical_command=_resolved_active_physical_snapshot( transport_ref="physical-k1", connection_mode="bridge", ), ) observation = policy["actions"]["observe-fresh-device-network"] assert observation["allowed"] is False assert "reconciliation-target-physical-recovery-mismatch" in observation["reason_codes"] assert observation["required_transport_ref"] == "physical-k1" def test_reopen_rejects_discovery_generation_drift_before_durable_commit( tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) request = _retired_fresh_reopen_request( service, reopening_id="reopening-stale-discovery-generation", ) before = service._physical_command_ledger.snapshot().record # noqa: SLF001 with service._lock: # noqa: SLF001 service._ble_discovery_generation += 1 # noqa: SLF001 _set_scanned_k1(service, device_id=DURABLE_K1_UUID.lower()) with pytest.raises(facade_module.NetworkProvisioningConflict) as stale: service.reopen_retired_physical_command_reconciliation(request) assert stale.value.reason_code == ("physical-command-reconciliation-reopen-stale-checkpoint") assert service._physical_command_ledger.snapshot().record == before # noqa: SLF001 assert service._application_control_process_lease_holders == set() # noqa: SLF001 assert runtime.start_calls == [] assert runtime.stop_calls == 0 def test_reopen_two_tab_lost_response_retry_uses_one_durable_audit( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: first, _ = service_with_fake_runtime(tmp_path) request = _retired_fresh_reopen_request( first, reopening_id="reopening-two-tab-lost-response", ) second, second_runtime = service_with_fake_runtime(tmp_path) with second._lock: # noqa: SLF001 second._ble_discovery_generation = request.expected_discovery_generation # noqa: SLF001 _set_scanned_k1(second, device_id=request.expected_transport_ref) committed = first.reopen_retired_physical_command_reconciliation(request) monkeypatch.setattr( second, "_acquire_k1_lifecycle_process_lease", lambda *_args, **_kwargs: (_ for _ in ()).throw( AssertionError("durable lost-response retry must not reacquire the lease") ), ) observed = second.reopen_retired_physical_command_reconciliation(request) assert committed["physical_command"]["status"] == "unresolved" reopens = observed["physical_command"]["record"]["operator_reconciliation_reopens"] assert [item["reopening_id"] for item in reopens] == ["reopening-two-tab-lost-response"] assert ( observed["connection_policy"]["actions"]["observe-fresh-device-network"]["allowed"] is True ) assert second_runtime.start_calls == [] assert second_runtime.stop_calls == 0 def test_reopen_quick_restart_retry_is_durable_and_does_not_require_local_draft( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: owner, _ = service_with_fake_runtime(tmp_path) request = _retired_fresh_reopen_request( owner, reopening_id="reopening-quick-restart-lost-response", connection_mode="quick-connect", ) owner.reopen_retired_physical_command_reconciliation(request) restarted, restarted_runtime = service_with_fake_runtime(tmp_path) assert restarted.state()["desired_connection_mode"] == "bridge" monkeypatch.setattr( restarted, "_acquire_k1_lifecycle_process_lease", lambda *_args, **_kwargs: (_ for _ in ()).throw( AssertionError("durable reopen retry must not reacquire the lease") ), ) observed = restarted.reopen_retired_physical_command_reconciliation(request) after_release = restarted.state() assert observed["desired_connection_mode"] == "bridge" assert after_release["connection_lifecycle"]["mode_selection"]["allowed"] is True assert [ item["reopening_id"] for item in observed["physical_command"]["record"]["operator_reconciliation_reopens"] ] == ["reopening-quick-restart-lost-response"] assert restarted_runtime.start_calls == [] assert restarted_runtime.stop_calls == 0 def test_reopen_cross_process_lifecycle_owner_blocks_before_ledger_commit( tmp_path: Path, ) -> None: owner, _ = service_with_fake_runtime(tmp_path) request = _retired_fresh_reopen_request( owner, reopening_id="reopening-cross-process-owner", ) actor, actor_runtime = service_with_fake_runtime(tmp_path) with actor._lock: # noqa: SLF001 actor._ble_discovery_generation = request.expected_discovery_generation # noqa: SLF001 _set_scanned_k1(actor, device_id=request.expected_transport_ref) assert ( actor._physical_operator_reconciliation_reopen_projection()[ # noqa: SLF001 "allowed" ] is False ) with actor._lock: # noqa: SLF001 actor._ble_discovery_generation += 1 # noqa: SLF001 _set_scanned_k1(actor, device_id=request.expected_transport_ref) actor_projection = actor._physical_operator_reconciliation_reopen_projection() # noqa: SLF001 assert actor_projection["allowed"] is True actor_request = ReopenRetiredPhysicalCommandReconciliationRequest( reopening_id=request.reopening_id, expected_revision=actor_projection["expected_revision"], expected_retirement_id=actor_projection["expected_retirement_id"], expected_transport_ref=actor_projection["expected_transport_ref"], expected_discovery_generation=actor_projection["expected_discovery_generation"], expected_desired_mode=actor_projection["expected_desired_mode"], expected_desired_mode_revision=actor_projection["expected_desired_mode_revision"], operator_confirmed=True, reason=request.reason, ) before = actor._physical_command_ledger.snapshot().record # noqa: SLF001 owner._acquire_k1_lifecycle_process_lease("control") # noqa: SLF001 try: with pytest.raises(facade_module.ApplicationControlProcessLeaseUnavailable): actor.reopen_retired_physical_command_reconciliation(actor_request) finally: owner._release_k1_lifecycle_process_lease("control") # noqa: SLF001 assert actor._physical_command_ledger.snapshot().record == before # noqa: SLF001 assert actor._application_control_process_lease_holders == set() # noqa: SLF001 assert actor_runtime.start_calls == [] assert actor_runtime.stop_calls == 0 def test_peer_requires_a_new_scan_after_observing_shared_physical_retirement( tmp_path: Path, ) -> None: owner, owner_runtime = service_with_fake_runtime(tmp_path) binding = _seed_supervised_connection( owner, transport_ref=DURABLE_K1_UUID, connection_mode="bridge", ) retirement = _seed_unresolved_physical_stop_for_retirement(owner, binding) peer, peer_runtime = service_with_fake_runtime(tmp_path) with peer._lock: # noqa: SLF001 peer._ble_discovery_generation += 1 # noqa: SLF001 stale_generation = peer._ble_discovery_generation # noqa: SLF001 _set_scanned_k1(peer, device_id=DURABLE_K1_UUID.lower()) owner.retire_unavailable_physical_command(retirement) retired_before = peer._physical_command_ledger.snapshot().record # noqa: SLF001 stale = peer._physical_operator_reconciliation_reopen_projection() # noqa: SLF001 assert stale["allowed"] is False assert "physical-command-reconciliation-reopen-target-not-observed" in stale["reason_codes"] assert ( # noqa: SLF001 peer._physical_retirement_reopen_generation_floors[retirement.retirement_id] == stale_generation ) assert peer._physical_command_ledger.snapshot().record == retired_before # noqa: SLF001 with peer._lock: # noqa: SLF001 peer._ble_discovery_generation += 1 # noqa: SLF001 _set_scanned_k1(peer, device_id=DURABLE_K1_UUID.lower()) fresh = peer._physical_operator_reconciliation_reopen_projection() # noqa: SLF001 assert fresh["allowed"] is True, fresh reopened = peer.reopen_retired_physical_command_reconciliation( ReopenRetiredPhysicalCommandReconciliationRequest( reopening_id="reopening-after-peer-post-retirement-scan", expected_revision=fresh["expected_revision"], expected_retirement_id=fresh["expected_retirement_id"], expected_transport_ref=fresh["expected_transport_ref"], expected_discovery_generation=fresh["expected_discovery_generation"], expected_desired_mode=fresh["expected_desired_mode"], expected_desired_mode_revision=fresh["expected_desired_mode_revision"], operator_confirmed=True, reason="device-returned-for-explicit-reconciliation", ) ) assert reopened["physical_command"]["requires_reconciliation"] is True assert owner_runtime.start_calls == [] assert owner_runtime.stop_calls == 0 assert peer_runtime.start_calls == [] assert peer_runtime.stop_calls == 0 def test_exact_retirement_retry_repairs_local_revocation_without_process_lease_or_io( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) binding = _seed_supervised_connection(service, transport_ref="retired-k1") request = _seed_unresolved_physical_stop_for_retirement(service, binding) real_revoke = service._revoke_retired_physical_target_locally # noqa: SLF001 def fail_after_durable_commit(*_args: object, **_kwargs: object) -> None: raise RuntimeError("injected crash after ledger commit") monkeypatch.setattr( service, "_revoke_retired_physical_target_locally", fail_after_durable_commit, ) with pytest.raises(RuntimeError, match="injected crash"): service.retire_unavailable_physical_command(request) committed = service._physical_command_ledger.snapshot().record # noqa: SLF001 assert committed is not None assert committed.resolution == "operator-retired-outcome-unknown" assert service._selected_device_id == "retired-k1" # noqa: SLF001 # A replacement backend may legitimately advance the shared ledger before # the original browser retries its lost retirement response. The carried # retirement audit, not the current operation, is the idempotency key. replacement_identity = PhysicalCommandIdentity( vendor_device_id_sha256="7" * 64, device_serial_sha256="8" * 64, ) replacement_connection = PhysicalCommandConnectionBinding( intent_id="replacement-intent", transport_ref="replacement-k1", connection_mode="bridge", target_ipv4="192.168.1.21", target_port=facade_module.CONTROL_MQTT_PORT, host_path_epoch=21, control_session_id="replacement-control-session", producer_generation=22, ) replacement_status = PhysicalCommandStatusEvidence( source="live-control-session", vendor_device_id_sha256=replacement_identity.vendor_device_id_sha256, device_serial_sha256=replacement_identity.device_serial_sha256, control_session_id=replacement_connection.control_session_id, host_path_epoch=replacement_connection.host_path_epoch, producer_generation=replacement_connection.producer_generation, session_state="ready", session_state_code=300, project_bound=False, project_id_sha256=None, init_ready=False, status_message_sha256="9" * 64, mqtt_retained=False, observed_at_utc="2026-08-10T17:01:00.000Z", ) replacement = service._physical_command_ledger.prepare( # noqa: SLF001 operation_id="replacement-start-after-retirement", parent_operation_id=committed.operation_id, acquisition_id="replacement-acquisition-after-retirement", action="start", identity=replacement_identity, connection=replacement_connection, compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, payload_sha256="2" * 64, baseline_status=replacement_status, ) advanced = service._physical_command_ledger.resolve( # noqa: SLF001 replacement.operation_id, resolution="not-dispatched", ) monkeypatch.setattr(service, "_revoke_retired_physical_target_locally", real_revoke) monkeypatch.setattr( service, "_acquire_k1_lifecycle_process_lease", lambda *_args, **_kwargs: (_ for _ in ()).throw( AssertionError("exact retry must not acquire the shared process lease") ), ) repaired = service.retire_unavailable_physical_command(request) persisted = service._physical_command_ledger.snapshot().record # noqa: SLF001 assert persisted == advanced assert repaired["selected_device_id"] is None assert repaired["connection_lifecycle"]["active_binding"] is None def test_stale_peer_blocks_every_retired_target_contact_path_before_io( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: owner, _ = service_with_fake_runtime(tmp_path) owner_binding = _seed_supervised_connection(owner, transport_ref="RETIRED-K1") request = _seed_unresolved_physical_stop_for_retirement(owner, owner_binding) stale_peer, stale_runtime = service_with_fake_runtime(tmp_path) _set_scanned_k1(stale_peer, device_id="retired-k1") _seed_supervised_connection(stale_peer, transport_ref="retired-k1") connect_request = _connect_request( device_id="retired-k1", ssid="DCCONSTRUCTIONS", password=SecretStr(PRIMARY_TEST_CREDENTIAL), connection_mode="bridge", compatibility_attestation=ATTESTATION, ) owner.retire_unavailable_physical_command(request) io_calls: list[str] = [] async def forbidden_async_io(*_args: object, **_kwargs: object) -> object: io_calls.append("ble-or-network") raise AssertionError("retired target must be rejected before I/O") def forbidden_sync_io(*_args: object, **_kwargs: object) -> object: io_calls.append("host-tcp-mqtt-http") raise AssertionError("retired target must be rejected before I/O") monkeypatch.setattr(facade_module, "read_wifi_status_once", forbidden_async_io) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_async_io) monkeypatch.setattr(facade_module, "_control_endpoint_reachable", forbidden_sync_io) monkeypatch.setattr(stale_peer, "_sample_host_path", forbidden_sync_io) monkeypatch.setattr(stale_peer, "_probe_control_endpoint", forbidden_sync_io) monkeypatch.setattr(stale_peer, "_refresh_live_lan_address", forbidden_sync_io) monkeypatch.setattr(stale_peer.camera_preview, "select", forbidden_sync_io) monkeypatch.setattr( stale_peer._calibration_snapshot_reader, # noqa: SLF001 "capture", forbidden_sync_io, ) monkeypatch.setattr( SecretStr, "get_secret_value", lambda _self: (_ for _ in ()).throw( AssertionError("retired Connect must not unwrap the credential") ), ) with pytest.raises(facade_module.NetworkProvisioningConflict) as connect_error: asyncio.run(stale_peer.connect(connect_request)) assert connect_error.value.reason_code == "physical-command-target-retired" with pytest.raises(facade_module.ConnectionVerificationError) as verify_error: asyncio.run( stale_peer.verify_connection( ConnectionVerifyRequest( device_id="retired-k1", source="fresh-scan", compatibility_attestation=ATTESTATION, expected_discovery_generation=0, ) ) ) assert verify_error.value.reason_code == "physical-command-target-retired" with pytest.raises(facade_module.ConnectionVerificationError) as open_error: stale_peer.open_application_control_session( OpenApplicationControlSessionRequest( operator_present=True, owner_controlled_device=True, lixelgo_closed=True, battery_storage_confirmed=True, expected_physical_state_confirmed=True, timezone_name="Europe/Moscow", ) ) assert open_error.value.reason_code == "physical-command-target-retired" with pytest.raises(facade_module.ConfiguredEndpointProbeError) as probe_error: asyncio.run(stale_peer.probe_configured_endpoint(ConfiguredEndpointProbeRequest())) assert probe_error.value.reason_code == "physical-command-target-retired" with pytest.raises(facade_module.ConnectionVerificationError) as calibration_error: stale_peer.read_device_calibration_snapshot() assert calibration_error.value.reason_code == "physical-command-target-retired" assert stale_peer._connection_monitor_target() is None # noqa: SLF001 asyncio.run(stale_peer._connection_monitor.poll_once()) # noqa: SLF001 with pytest.raises(facade_module.ConnectionVerificationError): asyncio.run( stale_peer._monitor_control_endpoint( # noqa: SLF001 EndpointTarget("192.168.1.20", facade_module.CONTROL_MQTT_PORT) ) ) with pytest.raises(facade_module.ConnectionVerificationError): stale_peer.prepare_acquisition( _prepare_request( project_name="RETIRED01", host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) with pytest.raises(facade_module.ConnectionVerificationError): stale_peer.start_live( "RETIRED02", "192.168.1.20", None, ATTESTATION, ) with pytest.raises(facade_module.ConnectionVerificationError) as camera_error: stale_peer.select_camera_preview( CameraPreviewSelectRequest( source_id=facade_module.DEFAULT_ACQUISITION_CAMERA_SOURCE, device_session_id="test-session-retired-k1", ) ) assert camera_error.value.reason_code == "physical-command-target-retired" inspected = stale_peer.inspect_device() assert inspected["physical_command"]["record"]["resolution"] == ( "operator-retired-outcome-unknown" ) assert stale_runtime.start_calls == [] assert stale_runtime.stop_calls == 0 assert io_calls == [] def test_selected_camera_holds_retirement_fence_and_stale_generation_cannot_spawn( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: camera_service, _ = service_with_fake_runtime(tmp_path) binding = _seed_supervised_connection( camera_service, transport_ref="retired-k1", ) request = _seed_unresolved_physical_stop_for_retirement( camera_service, binding, ) camera_service.camera_preview._ffmpeg_path = ( # noqa: SLF001 tmp_path / "synthetic-ffmpeg" ) selected = camera_service.select_camera_preview( CameraPreviewSelectRequest( source_id=facade_module.DEFAULT_ACQUISITION_CAMERA_SOURCE, device_session_id="test-session-retired-k1", ) ) generation = selected["camera_preview"]["generation"] assert isinstance(generation, int) assert "camera" in ( # noqa: SLF001 camera_service._application_control_process_lease_holders # noqa: SLF001 ) retirement_service, _ = service_with_fake_runtime(tmp_path) with pytest.raises(facade_module.ApplicationControlProcessLeaseUnavailable): retirement_service.retire_unavailable_physical_command(request) stopped = camera_service.stop_camera_preview( facade_module.CameraPreviewStopRequest( generation=generation, device_session_id="test-session-retired-k1", ) ) assert stopped["camera_preview"]["active_source_id"] is None assert "camera" not in ( # noqa: SLF001 camera_service._application_control_process_lease_holders # noqa: SLF001 ) retired = retirement_service.retire_unavailable_physical_command(request) assert retired["physical_command"]["record"]["resolution"] == ( "operator-retired-outcome-unknown" ) popen_calls: list[str] = [] def forbidden_popen(*_args: object, **_kwargs: object) -> object: popen_calls.append("popen") raise AssertionError("retired stale camera generation must not spawn FFmpeg") monkeypatch.setattr( "k1link.device_plugins.xgrids_k1.camera.subprocess.Popen", forbidden_popen, ) with pytest.raises(ValueError, match="generation не активно"): camera_service.camera_preview.open_delivery(generation) assert popen_calls == [] def test_cancelled_target_probe_retains_retirement_fence_until_thread_finishes( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: probe_service, _ = service_with_fake_runtime(tmp_path) binding = _seed_supervised_connection( probe_service, transport_ref="retired-k1", ) request = _seed_unresolved_physical_stop_for_retirement( probe_service, binding, ) retirement_service, _ = service_with_fake_runtime(tmp_path) probe_entered = threading.Event() release_probe = threading.Event() def blocked_host_path( _target: str, *, association_timeout_seconds: float = 30.0, fail_closed_unproven_association: bool = False, ) -> HostPathProbeResult: assert association_timeout_seconds == ( facade_module.CONNECTION_MONITOR_ASSOCIATION_TIMEOUT_SECONDS ) assert fail_closed_unproven_association is True probe_entered.set() assert release_probe.wait(timeout=5.0) return _direct_host_path(_target) monkeypatch.setattr(probe_service, "_sample_host_path", blocked_host_path) async def scenario() -> None: target = EndpointTarget(binding.target_ipv4, binding.target_port) probe_task = asyncio.create_task( probe_service._monitor_host_path(target) # noqa: SLF001 ) assert await asyncio.to_thread(probe_entered.wait, 5.0) before = retirement_service._physical_command_ledger.snapshot().record # noqa: SLF001 probe_task.cancel() await asyncio.sleep(0) probe_task.cancel() await asyncio.sleep(0.01) assert probe_task.done() is False with pytest.raises(facade_module.ApplicationControlProcessLeaseUnavailable): await asyncio.to_thread( retirement_service.retire_unavailable_physical_command, request, ) assert ( retirement_service._physical_command_ledger.snapshot().record # noqa: SLF001 == before ) release_probe.set() with pytest.raises(asyncio.CancelledError): await probe_task retired = await asyncio.to_thread( retirement_service.retire_unavailable_physical_command, request, ) assert retired["physical_command"]["record"]["resolution"] == ( "operator-retired-outcome-unknown" ) asyncio.run(scenario()) def test_calibration_process_lease_blocks_cross_service_retirement_until_capture_finishes( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: calibration_service, _ = service_with_fake_runtime(tmp_path) binding = _seed_supervised_connection( calibration_service, transport_ref="retired-k1", ) request = _seed_unresolved_physical_stop_for_retirement( calibration_service, binding, ) retirement_service, _ = service_with_fake_runtime(tmp_path) capture_entered = threading.Event() release_capture = threading.Event() outcome: dict[str, object] = {} class BlockingCalibrationReader: def capture(self, **_kwargs: object) -> dict[str, object]: capture_entered.set() assert release_capture.wait(timeout=5) return {"status": "available", "snapshot_id": "blocking-test"} calibration_service._calibration_snapshot_reader = ( # type: ignore[assignment] # noqa: SLF001 BlockingCalibrationReader() ) monkeypatch.setattr( calibration_service, "_refresh_live_lan_address", lambda: "192.168.1.20", ) def capture() -> None: try: outcome["result"] = calibration_service.read_device_calibration_snapshot() except BaseException as exc: # pragma: no cover - asserted below outcome["error"] = exc worker = threading.Thread(target=capture, daemon=True) worker.start() assert capture_entered.wait(timeout=5) projection = calibration_service.state()["physical_command"]["operator_retirement"] assert projection["allowed"] is False assert "device-calibration-read-active" in projection["reason_codes"] before = retirement_service._physical_command_ledger.snapshot().record # noqa: SLF001 with pytest.raises(facade_module.ApplicationControlProcessLeaseUnavailable): retirement_service.retire_unavailable_physical_command(request) unchanged = retirement_service._physical_command_ledger.snapshot().record # noqa: SLF001 assert unchanged == before release_capture.set() worker.join(timeout=5) assert not worker.is_alive() assert "error" not in outcome assert outcome["result"] == { "status": "available", "snapshot_id": "blocking-test", } def test_calibration_hard_timeout_retains_retirement_fence_until_ble_cleanup( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: calibration_service, _ = service_with_fake_runtime(tmp_path) binding = _seed_supervised_connection( calibration_service, transport_ref="retired-k1", ) request = _seed_unresolved_physical_stop_for_retirement( calibration_service, binding, ) retirement_service, _ = service_with_fake_runtime(tmp_path) async def scenario() -> None: cleanup_entered = asyncio.Event() cleanup_release = asyncio.Event() async def detached_status_read( _device_id: str, **_kwargs: object, ) -> dict[str, Any]: async def stubborn_cleanup(_progress: BleOperationProgress) -> None: try: await asyncio.Event().wait() except asyncio.CancelledError: cleanup_entered.set() await cleanup_release.wait() raise return await run_ble_operation( # type: ignore[return-value] "status-read", hard_timeout_seconds=0.01, operation=stubborn_cleanup, ) runtime_loop = asyncio.get_running_loop() bind_ble_runtime_owner_loop(runtime_loop) with calibration_service._lock: # noqa: SLF001 calibration_service._runtime_event_loop = runtime_loop # noqa: SLF001 monkeypatch.setattr( facade_module, "read_wifi_status_once", detached_status_read, ) monkeypatch.setattr( facade_module, "_host_route_class", lambda _target: "default-route", ) with pytest.raises(RuntimeError, match="BLE status-read не завершился"): await asyncio.to_thread(calibration_service.read_device_calibration_snapshot) await cleanup_entered.wait() with pytest.raises(facade_module.NetworkProvisioningConflict): await asyncio.to_thread( retirement_service.retire_unavailable_physical_command, request, ) cleanup_release.set() assert await wait_for_ble_runtime_idle() retired = await asyncio.to_thread( retirement_service.retire_unavailable_physical_command, request, ) assert retired["physical_command"]["record"]["resolution"] == ( "operator-retired-outcome-unknown" ) asyncio.run(scenario()) def test_operator_manual_live_retains_cross_process_fence_until_receiver_stops( tmp_path: Path, ) -> None: live_service, live_runtime = service_with_fake_runtime(tmp_path) prepared = live_service.prepare_acquisition( _prepare_request( project_name="MANUAL01", host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] retirement_service, _ = service_with_fake_runtime(tmp_path) binding = _seed_supervised_connection( retirement_service, transport_ref="retired-k1", ) request = _seed_unresolved_physical_stop_for_retirement( retirement_service, binding, ) started = live_service.start_acquisition(_start_request(acquisition_id=acquisition_id)) assert started["acquisition"]["state"] == "starting" assert live_runtime.start_calls assert ( live_service._operator_manual_acquisition_process_lease_id # noqa: SLF001 == acquisition_id ) with pytest.raises(facade_module.ApplicationControlProcessLeaseUnavailable): retirement_service.retire_unavailable_physical_command(request) unresolved = retirement_service._physical_command_ledger.snapshot().record # noqa: SLF001 assert unresolved is not None and unresolved.unresolved stopped = live_service.stop_acquisition( _stop_request( acquisition_id=acquisition_id, mode="capture-only", ) ) assert stopped["acquisition"]["state"] == "completed" assert live_service._operator_manual_acquisition_process_lease_id is None # noqa: SLF001 retired = retirement_service.retire_unavailable_physical_command(request) assert retired["physical_command"]["record"]["resolution"] == ( "operator-retired-outcome-unknown" ) def test_ambiguous_manual_start_cleanup_keeps_retirement_fenced_until_retry( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: live_service, live_runtime = service_with_fake_runtime(tmp_path) prepared = live_service.prepare_acquisition( _prepare_request( project_name="MANUALFAIL", host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] retirement_service, _ = service_with_fake_runtime(tmp_path) binding = _seed_supervised_connection( retirement_service, transport_ref="retired-k1", ) request = _seed_unresolved_physical_stop_for_retirement( retirement_service, binding, ) original_start_live = live_runtime.start_live def fail_after_receiver_start( host: str, out_dir: Path, *, duration_seconds: float | None, project_name: str, recover_connection: Callable[[int], str] | None = None, ) -> None: original_start_live( host, out_dir, duration_seconds=duration_seconds, project_name=project_name, recover_connection=recover_connection, ) raise RuntimeError("injected receiver start failure") monkeypatch.setattr(live_runtime, "start_live", fail_after_receiver_start) live_runtime.stop_error = RuntimeError("injected receiver cleanup failure") camera_arm_calls: list[Path] = [] monkeypatch.setattr( live_service, "_arm_camera_recording", lambda out_dir, **_kwargs: camera_arm_calls.append(out_dir), ) with pytest.raises(RuntimeError, match="receiver start failure"): live_service.start_acquisition(_start_request(acquisition_id=acquisition_id)) assert live_runtime.start_calls assert camera_arm_calls == [] assert ( live_service._operator_manual_acquisition_process_lease_id # noqa: SLF001 == acquisition_id ) with pytest.raises(facade_module.ApplicationControlProcessLeaseUnavailable): retirement_service.retire_unavailable_physical_command(request) unresolved = retirement_service._physical_command_ledger.snapshot().record # noqa: SLF001 assert unresolved is not None and unresolved.unresolved live_runtime.stop_error = None live_service._stop_acquisition_sources( # noqa: SLF001 camera_status="failed", camera_failure_code="cleanup-retry-after-start-failure", ) assert live_service._operator_manual_acquisition_process_lease_id is None # noqa: SLF001 retirement_service.retire_unavailable_physical_command(request) def test_state_snapshot_stamp_is_runtime_scoped_and_monotonic(tmp_path: Path) -> None: service, _ = service_with_fake_runtime(tmp_path / "first-runtime") first = service.state() second = service.state() replacement, _ = service_with_fake_runtime(tmp_path / "replacement-runtime") replacement_state = replacement.state() assert first["snapshot_runtime_id"].startswith("snapshot-runtime-") assert first["snapshot_runtime_id"] == second["snapshot_runtime_id"] assert first["snapshot_runtime_started_at_utc"] == (second["snapshot_runtime_started_at_utc"]) assert ( first["snapshot_runtime_started_monotonic_ns"] == (second["snapshot_runtime_started_monotonic_ns"]) ) assert second["snapshot_revision"] == first["snapshot_revision"] + 1 assert replacement_state["snapshot_runtime_id"] != first["snapshot_runtime_id"] assert int(replacement_state["snapshot_runtime_started_monotonic_ns"]) > int( first["snapshot_runtime_started_monotonic_ns"] ) assert replacement_state["snapshot_revision"] == 1 def test_runtime_start_allocator_is_strictly_increasing_for_equal_clock_ticks( monkeypatch: pytest.MonkeyPatch, ) -> None: with facade_module._SNAPSHOT_RUNTIME_START_LOCK: # noqa: SLF001 previous = facade_module._LAST_SNAPSHOT_RUNTIME_STARTED_MONOTONIC_NS # noqa: SLF001 facade_module._LAST_SNAPSHOT_RUNTIME_STARTED_MONOTONIC_NS = 100 # noqa: SLF001 try: monkeypatch.setattr(facade_module.time, "monotonic_ns", lambda: 100) first = facade_module._allocate_snapshot_runtime_started_monotonic_ns() # noqa: SLF001 second = facade_module._allocate_snapshot_runtime_started_monotonic_ns() # noqa: SLF001 assert (first, second) == ("101", "102") finally: with facade_module._SNAPSHOT_RUNTIME_START_LOCK: # noqa: SLF001 facade_module._LAST_SNAPSHOT_RUNTIME_STARTED_MONOTONIC_NS = max( # noqa: SLF001 previous, 102, ) def _wifi_status_read( ipv4: str | None, *, device_id: str = "test-ble-transport", ) -> dict[str, Any]: return { "schema_version": 1, "profile_id": "xgrids-k1-fw3-wifi-v1", "observed_at_utc": "2026-07-20T12:00:00Z", "adapter": "CoreBluetooth", "bleak_version": "test", "device_macos_uuid": device_id, "device_name": "XGR-K1", "service_uuid": "00007f00-0000-1000-8000-00805f9b34fb", "write_characteristic_uuid": "00007f01-0000-1000-8000-00805f9b34fb", "write_characteristic_properties": ["read", "write"], "max_write_without_response_size": 253, "mtu_size": 256, "status_characteristic_uuid": "00007f02-0000-1000-8000-00805f9b34fb", "operation": "single_reviewed_wifi_status_read", "write_performed": False, "status": { "value_length": 54, "mode": "WIFI_CLIENT", "ipv4": ipv4, "status_code": 1, "reserved": 0, "trailer_hex": "", }, } def _durable_status_capture( device_id: str = DURABLE_K1_UUID, ) -> facade_module.CapturedDiscoveredDevice: return facade_module.CapturedDiscoveredDevice( device=SimpleNamespace(address=device_id), # type: ignore[arg-type] macos_uuid=device_id, owner_epoch=7, source="retrieved-durable", ) def _ap_ready_wifi_status() -> dict[str, Any]: return { "value_length": 54, "mode": "WIFI_AP", "ipv4": "192.168.56.1", "status_code": 1, "reserved": 1, "trailer_hex": "", } @pytest.mark.parametrize("mode", [None, "UNKNOWN", "WIFI_AP"]) def test_applied_bridge_target_requires_explicit_wifi_client_mode( mode: str | None, ) -> None: status = { "mode": mode, "ipv4": "192.168.68.52", "status_code": 1, "reserved": 0, } assert facade_module._applied_network_target("bridge", status) is None # noqa: SLF001 assert ( facade_module._applied_network_target("direct-connect", status) # noqa: SLF001 is None ) @pytest.mark.parametrize( ("connection_mode", "baseline", "observed", "previous", "expected"), [ ( "bridge", NetworkStatusEvidence("WIFI_CLIENT", "192.168.68.40", 1, 0), {"mode": "WIFI_CLIENT", "ipv4": "192.168.68.40", "status_code": 1, "reserved": 0}, None, None, ), ( "bridge", NetworkStatusEvidence("WIFI_CLIENT", "192.168.68.40", 1, 0), {"mode": "WIFI_CLIENT", "ipv4": "192.168.68.99", "status_code": 1, "reserved": 0}, None, None, ), ( "direct-connect", NetworkStatusEvidence("WIFI_CLIENT", None, 1, 0), {"mode": "WIFI_CLIENT", "ipv4": "172.20.10.2", "status_code": 1, "reserved": 0}, None, None, ), ( "quick-connect", NetworkStatusEvidence("WIFI_AP", "192.168.56.1", 1, 1), {"mode": "WIFI_AP", "ipv4": "192.168.56.1", "status_code": 2, "reserved": 1}, None, None, ), ( "bridge", NetworkStatusEvidence("WIFI_AP", "192.168.56.1", 1, 1), {"mode": "WIFI_CLIENT", "ipv4": "192.168.68.50", "status_code": 1, "reserved": 0}, None, "192.168.68.50", ), ( "direct-connect", NetworkStatusEvidence("WIFI_AP", "192.168.56.1", 1, 1), {"mode": "WIFI_CLIENT", "ipv4": "172.20.10.2", "status_code": 1, "reserved": 0}, None, "172.20.10.2", ), ( "quick-connect", NetworkStatusEvidence("WIFI_CLIENT", "192.168.68.50", 1, 0), {"mode": "WIFI_AP", "ipv4": "192.168.56.1", "status_code": 1, "reserved": 1}, None, "192.168.56.1", ), ( "quick-connect", NetworkStatusEvidence("WIFI_AP", "192.168.56.1", 1, 0), {"mode": "WIFI_AP", "ipv4": "192.168.56.1", "status_code": 1, "reserved": 1}, None, "192.168.56.1", ), ( "quick-connect", NetworkStatusEvidence("WIFI_CLIENT", "192.168.68.50", 1, 0), {"mode": "WIFI_AP", "ipv4": "192.168.56.1", "status_code": 1, "reserved": 1}, PreviousConnectionEvidence("same-k1", "quick-connect", "192.168.56.1", "old-session"), None, ), ( "bridge", NetworkStatusEvidence("WIFI_AP", "192.168.56.1", 1, 1), {"mode": "WIFI_CLIENT", "ipv4": "192.168.68.99", "status_code": 1, "reserved": 0}, PreviousConnectionEvidence("same-k1", "bridge", "192.168.68.40", "old-session"), None, ), ( "direct-connect", NetworkStatusEvidence("WIFI_AP", "192.168.56.1", 1, 1), {"mode": "WIFI_CLIENT", "ipv4": "172.20.10.2", "status_code": 1, "reserved": 0}, PreviousConnectionEvidence("same-k1", "bridge", "172.20.10.2", "old-session"), None, ), ( "bridge", NetworkStatusEvidence("WIFI_AP", "192.168.56.1", 1, 1), {"mode": "WIFI_CLIENT", "ipv4": "172.20.10.2", "status_code": 1, "reserved": 0}, PreviousConnectionEvidence("same-k1", "direct-connect", "172.20.10.2", "old-session"), None, ), ( "bridge", NetworkStatusEvidence("WIFI_AP", "192.168.56.1", 1, 1), {"mode": "WIFI_CLIENT", "ipv4": "192.168.68.50", "status_code": 1, "reserved": 0}, PreviousConnectionEvidence("other-k1", "bridge", "192.168.68.50", "old-session"), "192.168.68.50", ), ], ) def test_post_dispatch_target_requires_status_distinguishable_from_baseline( connection_mode: facade_module.ConnectionMode, baseline: NetworkStatusEvidence, observed: dict[str, object], previous: PreviousConnectionEvidence | None, expected: str | None, ) -> None: assert ( facade_module._post_dispatch_network_target( # noqa: SLF001 connection_mode, observed, transport_ref="same-k1", baseline_status=baseline, previous_connection=previous, ) == expected ) def test_post_dispatch_bridge_accepts_exact_fw302_network_name_when_baseline_is_same() -> None: """An idempotent same-network Bridge request proves the requested target.""" status = { "mode": "WIFI_CLIENT", "network_name": "LAB_NETWORK", "ipv4": "192.168.68.51", "status_code": 1, "reserved": 0, } assert ( facade_module._post_dispatch_network_target( # noqa: SLF001 "bridge", status, transport_ref="same-k1", baseline_status=NetworkStatusEvidence("WIFI_CLIENT", "192.168.68.51", 1, 0), previous_connection=PreviousConnectionEvidence( "same-k1", "bridge", "192.168.68.51", "old-session", ), expected_network_name="LAB_NETWORK", ) == "192.168.68.51" ) def test_post_dispatch_bridge_rejects_another_fw302_network_name() -> None: status = { "mode": "WIFI_CLIENT", "network_name": "ANOTHER_NETWORK", "ipv4": "192.168.68.51", "status_code": 1, "reserved": 0, } assert ( facade_module._post_dispatch_network_target( # noqa: SLF001 "bridge", status, transport_ref="same-k1", baseline_status=NetworkStatusEvidence("WIFI_AP", "192.168.56.1", 1, 1), expected_network_name="LAB_NETWORK", ) is None ) def _seed_unresolved_network_mutation( service: XgridsK1CompatibilityService, *, operation_id: str = "ambiguous-operation", idempotency_operation_id: str | None = None, transport_ref: str = "test-ble-transport", intended_mode: NetworkConnectionMode = "bridge", baseline_status: NetworkStatusEvidence | None = None, previous_connection: PreviousConnectionEvidence | None = None, ) -> dict[str, Any]: resolved_idempotency_operation_id = idempotency_operation_id or operation_id idempotency_key = f"test-reconciliation-{resolved_idempotency_operation_id}" idempotency_journal = ( service._require_network_provisioning_idempotency_journal() # noqa: SLF001 ) idempotency_admission = idempotency_journal.begin( idempotency_key=idempotency_key, action=facade_module.ACTION_NETWORK_PROVISION, operation_id=resolved_idempotency_operation_id, request_binding_sha256=facade_module.derive_request_binding_sha256( idempotency_key, action=facade_module.ACTION_NETWORK_PROVISION, canonical_request=b'{"test":"read-only-reconciliation"}', ), ) ledger = service._network_mutation_ledger # noqa: SLF001 prepared = ledger.prepare( operation_id=operation_id, transport_ref=transport_ref, intended_mode=intended_mode, write_mode="with_response", baseline_status=baseline_status or NetworkStatusEvidence( mode="WIFI_AP", ipv4="192.168.56.1", status_code=1, reserved=1, ), previous_connection=previous_connection, ) idempotency_journal.mark_unresolved( resolved_idempotency_operation_id, expected_revision=idempotency_admission.record.revision, ) ledger.mark_dispatching( operation_id, expected_revision=prepared.revision, ) fence = service.state()["network_write_reconciliation"] assert fence is not None return fence def _prepare_network_mutation_for_reopen( service: XgridsK1CompatibilityService, *, operation_id: str, transport_ref: str, intended_mode: NetworkConnectionMode, ) -> NetworkMutationRecord: return service._network_mutation_ledger.prepare( # noqa: SLF001 operation_id=operation_id, transport_ref=transport_ref, intended_mode=intended_mode, write_mode="with_response", baseline_status=NetworkStatusEvidence( mode="WIFI_AP", ipv4="192.168.56.1", status_code=1, reserved=1, ), ) def _begin_network_idempotency_for_reopen( service: XgridsK1CompatibilityService, *, operation_id: str, mark_unresolved: bool, ) -> None: idempotency_key = f"reopen-audit-{operation_id}" journal = service._require_network_provisioning_idempotency_journal() # noqa: SLF001 admission = journal.begin( idempotency_key=idempotency_key, action=facade_module.ACTION_NETWORK_PROVISION, operation_id=operation_id, request_binding_sha256=facade_module.derive_request_binding_sha256( idempotency_key, action=facade_module.ACTION_NETWORK_PROVISION, canonical_request=b'{"test":"reopen-precommit"}', ), ) if mark_unresolved: journal.mark_unresolved( operation_id, expected_revision=admission.record.revision, ) def _seed_legacy_network_mutation_without_idempotency( service: XgridsK1CompatibilityService, *, operation_id: str = "legacy-network-operation", stage: str = "dispatching", ) -> None: """Create the durable shape emitted before the idempotency journal existed.""" ledger = service._network_mutation_ledger # noqa: SLF001 prepared = ledger.prepare( operation_id=operation_id, transport_ref="test-ble-transport", intended_mode="bridge", write_mode="with_response", baseline_status=NetworkStatusEvidence( mode="WIFI_AP", ipv4="192.168.56.1", status_code=1, reserved=1, ), ) if stage == "prepared": return dispatching = ledger.mark_dispatching( operation_id, expected_revision=prepared.revision, ) if stage == "observing": ledger.mark_observing( operation_id, expected_revision=dispatching.revision, write_confirmed=True, observation=NetworkStatusEvidence( mode="WIFI_CLIENT", ipv4="192.168.68.50", status_code=1, reserved=0, ), ) elif stage != "dispatching": raise ValueError("unsupported legacy test stage") def _set_scanned_devices( service: XgridsK1CompatibilityService, devices: list[dict[str, Any]], ) -> None: service._devices = devices # noqa: SLF001 _SYNTHETIC_SCAN_CAPTURES.clear() _SYNTHETIC_SCAN_CAPTURES.update( { str(item["device_id"]): facade_module.CapturedDiscoveredDevice( device=SimpleNamespace(address=str(item["device_id"])), # type: ignore[arg-type] macos_uuid=str(item["device_id"]), owner_epoch=1, scan_generation=service._ble_discovery_generation, # noqa: SLF001 ) for item in devices } ) observed_monotonic = facade_module.time.monotonic() observed_suspend_aware = facade_module.time.time() service._ble_device_last_seen_monotonic = { # noqa: SLF001 str(item["device_id"]): observed_monotonic for item in devices } service._ble_device_last_seen_suspend_aware = { # noqa: SLF001 str(item["device_id"]): observed_suspend_aware for item in devices } def _set_scanned_k1( service: XgridsK1CompatibilityService, *, device_id: str = "test-ble-transport", ) -> None: _set_scanned_devices( service, [ { "device_id": device_id, "name": "XGR-K1", "rssi": -44, "address": None, "connectable": True, "likely_k1": True, } ], ) def _ble_scan_result(device_id: str) -> dict[str, Any]: return { "devices": [ { "macos_uuid": device_id, "name": "XGR-K1", "local_name": "XGR-K1", "rssi": -44, "k1_name_candidate": True, } ] } def _resolved_active_physical_snapshot( *, transport_ref: str = "k1-original", connection_mode: str = "bridge", ) -> dict[str, object]: return { "status": "resolved", "reason_code": None, "requires_reconciliation": False, "resolved_active_recovery_required": True, "automatic_replay_allowed": False, "normal_session_recovery_supported": False, "recovery_requirement": ("explicit-read-only-deviceinfo-and-non-retained-devicestatus"), "runtime_bound": False, "reconciliation_ready": False, "observed_session_state": None, "active_operation_id": None, "record": { "operation_id": "persisted-start-active", "action": "start", "stage": "resolved", "resolution": "start-active-observed", "connection": { "transport_ref": transport_ref, "connection_mode": connection_mode, }, "reconciliations": [], }, } def _pending_reopened_physical_snapshot( *, transport_ref: str = "k1-a", connection_mode: str = "bridge", ) -> dict[str, object]: """Project a classified STOP whose retired target was reopened for Verify.""" operation_id = "pending-reopened-prepared-stop" retirement_id = "retirement-before-pending-reopen" return { "status": "resolved", "reason_code": "physical-command-reconciliation-required", "requires_reconciliation": False, "resolved_active_recovery_required": True, "reopened_physical_state_recovery_required": True, "physical_active": False, "reconciled_physical_state": None, "automatic_replay_allowed": False, "normal_session_recovery_supported": False, "recovery_requirement": "explicit-read-only-reconciliation", "runtime_bound": False, "active_operation_id": None, "record": { "operation_id": operation_id, "acquisition_id": "pending-reopened-acquisition", "action": "stop", "stage": "resolved", "resolution": "not-dispatched", "revision": 9, "connection": { "transport_ref": transport_ref, "connection_mode": connection_mode, }, "operator_retirements": [ { "retirement_id": retirement_id, "retired_transport_ref": transport_ref, "original_attempt": {"operation_id": operation_id}, } ], "operator_reconciliation_reopens": [ { "retirement_id": retirement_id, "retired_record_revision": 8, } ], "reconciliations": [], }, } def test_physical_recovery_policy_pins_original_ref_and_mode_but_keeps_scan_read_only( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_devices( service, [ { "device_id": "k1-original", "name": "Original K1", "rssi": -40, "address": None, "connectable": True, "likely_k1": True, }, { "device_id": "k1-nearby", "name": "Nearby K1", "rssi": -35, "address": None, "connectable": True, "likely_k1": True, }, ], ) monkeypatch.setattr( service._physical_command_coordinator, # noqa: SLF001 "snapshot", lambda: _resolved_active_physical_snapshot(), ) state = service.state() policy = state["connection_policy"]["actions"] assert policy["scan-ble"]["allowed"] is True assert "physical-device-already-active" not in policy["scan-ble"]["reason_codes"] assert policy["provision-fresh-device"]["allowed"] is False assert "physical-device-already-active" in policy["provision-fresh-device"]["reason_codes"] assert policy["observe-fresh-device-network"] == { "allowed": True, "reason_codes": [], "target_source": "fresh-scan", "required_transport_ref": "k1-original", "required_connection_mode": "bridge", "requires_live_gatt_validation": True, "automatic_retry": False, } def test_physical_recovery_rejects_wrong_nearby_k1_before_topology_or_ble_io( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_devices( service, [ { "device_id": "k1-original", "name": "Original K1", "rssi": -40, "address": None, "connectable": True, "likely_k1": True, }, { "device_id": "k1-nearby", "name": "Nearby K1", "rssi": -35, "address": None, "connectable": True, "likely_k1": True, }, ], ) monkeypatch.setattr( service._physical_command_coordinator, # noqa: SLF001 "snapshot", lambda: _resolved_active_physical_snapshot(), ) io_calls: list[str] = [] monkeypatch.setattr( facade_module, "read_wifi_status_once", lambda *_args, **_kwargs: io_calls.append("gatt-read"), ) monkeypatch.setattr( service, "_apply_read_only_device_topology", lambda *_args, **_kwargs: io_calls.append("topology-commit"), ) semantic_before = service._semantic_topology_public_snapshot() # noqa: SLF001 supervisor_before = service._connection_supervisor.snapshot() # noqa: SLF001 network_ledger_before = service._network_mutation_ledger.snapshot() # noqa: SLF001 with pytest.raises(facade_module.ConnectionVerificationError) as rejected: asyncio.run( service.verify_connection( ConnectionVerifyRequest( device_id="k1-nearby", source="fresh-scan", compatibility_attestation=ATTESTATION, expected_discovery_generation=0, ) ) ) assert rejected.value.reason_code == "physical-command-recovery-target-mismatch" assert io_calls == [] assert service._semantic_topology_public_snapshot() == semantic_before # noqa: SLF001 assert service._connection_supervisor.snapshot() == supervisor_before # noqa: SLF001 assert service._network_mutation_ledger.snapshot() == network_ledger_before # noqa: SLF001 def test_connect_is_fenced_before_gatt_or_wifi_when_physical_state_is_active( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service, device_id="k1-original") monkeypatch.setattr( service._physical_command_coordinator, # noqa: SLF001 "snapshot", lambda: _resolved_active_physical_snapshot(), ) io_calls: list[str] = [] async def forbidden_network_io(*_args: object, **_kwargs: object) -> dict[str, Any]: io_calls.append("network-io") raise AssertionError("physical admission must fail before GATT/Wi-Fi") monkeypatch.setattr(facade_module, "read_wifi_status_once", forbidden_network_io) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_network_io) with pytest.raises(facade_module.NetworkProvisioningConflict) as rejected: asyncio.run( service.connect( _connect_request( device_id="k1-original", ssid="DCCONSTRUCTIONS", password=SecretStr(PRIMARY_TEST_CREDENTIAL), connection_mode="bridge", compatibility_attestation=ATTESTATION, ) ) ) assert rejected.value.reason_code == "physical-device-already-active" assert io_calls == [] def test_latest_scan_candidate_survives_wall_clock_age_but_requires_exact_capture( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service, device_id="k1-a") service._ble_device_last_seen_monotonic["k1-a"] = -1.0 # noqa: SLF001 service._ble_device_last_seen_suspend_aware["k1-a"] = -1.0 # noqa: SLF001 monkeypatch.setattr(facade_module, "_capture_network_intent_device", lambda _device_id: None) async def forbidden_write(*_: object, **__: object) -> dict[str, Any]: raise AssertionError("a missing exact scan capture must fail before GATT write") monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_write) state = service.state() assert [item["device_id"] for item in state["devices"]] == ["k1-a"] assert state["selected_device_id"] is None assert state["device_session"] is None assert state["connection_lifecycle"]["active_binding"] is None assert state["connection_lifecycle"]["active_binding_key"] is None assert state["connection_policy"]["actions"]["provision-fresh-device"]["allowed"] is True with pytest.raises(facade_module.NetworkProvisioningConflict) as raised: asyncio.run( service.connect( _connect_request( device_id="k1-a", ssid="lab-router", password=SecretStr(PRIMARY_TEST_CREDENTIAL), connection_mode="bridge", compatibility_attestation=ATTESTATION, ) ) ) assert raised.value.reason_code == "network-provision-candidate-not-fresh" def test_candidate_wall_clock_age_does_not_close_an_admitted_connection_session( tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _seed_supervised_connection(service, transport_ref="k1-a") _set_scanned_k1(service, device_id="k1-a") service._ble_device_last_seen_monotonic["k1-a"] = -1.0 # noqa: SLF001 service._ble_device_last_seen_suspend_aware["k1-a"] = -1.0 # noqa: SLF001 state = service.state() assert [item["device_id"] for item in state["devices"]] == ["k1-a"] assert state["selected_device_id"] == "k1-a" assert state["device_session"] is not None assert state["device_session"]["connectivity"] in {"connected", "degraded"} def test_ble_scan_lists_twenty_candidates_without_selecting_or_opening_gatt( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) low_level_calls: list[str] = [] async def twenty_candidate_scan( _duration_seconds: float, *, on_admitted: Callable[[], None] | None = None, ) -> dict[str, Any]: if on_admitted is not None: on_admitted() return { "devices": [ { "macos_uuid": f"K1-CANDIDATE-{index:02d}", "name": f"XGR-K1-{index:02d}", "local_name": f"XGR-K1-{index:02d}", "rssi": -40 - index, "k1_name_candidate": True, } for index in range(20) ] } async def forbidden_gatt(*_: object, **__: object) -> dict[str, Any]: low_level_calls.append("gatt") raise AssertionError("scan must not open GATT or write K1") monkeypatch.setattr(facade_module, "scan", twenty_candidate_scan) monkeypatch.setattr(facade_module, "read_wifi_status_once", forbidden_gatt) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_gatt) state = asyncio.run(service.scan_ble(1.0)) assert len(state["devices"]) == 20 assert state["selected_device_id"] is None assert state["device_session"] is None assert state["connection_mode"] is None assert low_level_calls == [] def _attempt_competing_scan_from_sync_boundary( service: XgridsK1CompatibilityService, *, operation_id: str, ) -> object: outcomes: list[object] = [] def worker() -> None: try: outcomes.append( asyncio.run( service.scan_ble( BleScanRequest( duration_seconds=1.0, operation_id=operation_id, ) ) ) ) except BaseException as exc: outcomes.append(exc) thread = threading.Thread(target=worker, daemon=True) thread.start() thread.join(timeout=1.0) assert not thread.is_alive() assert len(outcomes) == 1 return outcomes[0] def test_explicit_new_scan_invalidates_previous_candidate_authority( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service) async def empty_scan( _duration_seconds: float, *, on_admitted: Callable[[], None] | None = None, ) -> dict[str, Any]: assert on_admitted is not None on_admitted() return {"devices": []} monkeypatch.setattr(facade_module, "scan", empty_scan) state = asyncio.run(service.scan_ble(1.0)) assert state["devices"] == [] assert state["connection_policy"]["actions"]["provision-fresh-device"]["allowed"] is False assert state["connection_policy"]["facts"]["fresh_transport_refs"] == [] def test_uuid_without_exact_latest_scan_capture_cannot_retire_existing_session( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service, device_id="k1-a") service._selected_device_id = "k1-a" # noqa: SLF001 service._connection_mode = "bridge" # noqa: SLF001 service._device_session_id = "existing-session" # noqa: SLF001 service._k1_ip = "192.168.68.50" # noqa: SLF001 monkeypatch.setattr(facade_module, "_capture_network_intent_device", lambda _device_id: None) monkeypatch.setattr( service, "_retire_application_control_for_network_change", lambda: (_ for _ in ()).throw( AssertionError("missing exact capture must fail before ownership handoff") ), ) with pytest.raises(facade_module.NetworkProvisioningConflict) as raised: asyncio.run( service.connect( _connect_request( device_id="k1-a", ssid="lab-router", password=SecretStr(PRIMARY_TEST_CREDENTIAL), connection_mode="bridge", compatibility_attestation=ATTESTATION, ) ) ) assert raised.value.reason_code == "network-provision-candidate-not-fresh" assert service._selected_device_id == "k1-a" # noqa: SLF001 assert service._connection_mode == "bridge" # noqa: SLF001 assert service._device_session_id == "existing-session" # noqa: SLF001 assert service._k1_ip == "192.168.68.50" # noqa: SLF001 def test_stale_runtime_generation_cannot_revive_live_data_plane( tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) runtime.source_mode = "live" runtime.phase = "live" runtime.producer_generation = 2 consumed = service._observe_runtime_message( # noqa: SLF001 StreamMessage( sequence=7, topic="RealtimePointcloud", payload=b"stale", received_at_epoch_ns=1, received_monotonic_ns=1, source="live_mqtt", producer_generation=1, ), BridgeMetrics(), ) assert consumed is True assert service._last_live_data_monotonic is None # noqa: SLF001 assert service._last_live_data_suspend_aware is None # noqa: SLF001 assert service._last_live_data_session_id is None # noqa: SLF001 @pytest.mark.parametrize("loss_boundary", ["control", "host"]) def test_bound_live_data_session_expires_after_control_or_host_lease_loss( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, loss_boundary: str, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) binding = _seed_supervised_connection(service) with service._lock: # noqa: SLF001 service._compatibility_attestation = ATTESTATION.model_dump(mode="json") # noqa: SLF001 runtime.source_mode = "live" runtime.phase = "live" monotonic_now = [100.0] monkeypatch.setattr(facade_module.time, "monotonic", lambda: monotonic_now[0]) supervisor = service._connection_supervisor # noqa: SLF001 data_session_id = "bound-live-data-session" assert supervisor.observe_data_plane( intent_id=binding.intent_id, host_path_epoch=binding.host_path_epoch, state="healthy", session_id=data_session_id, ) with service._lock: # noqa: SLF001 service._last_live_data_monotonic = monotonic_now[0] # noqa: SLF001 service._last_live_data_session_id = data_session_id # noqa: SLF001 if loss_boundary == "control": assert supervisor.observe_control_loss( intent_id=binding.intent_id, host_path_epoch=binding.host_path_epoch, control_session_id="test-control-test-ble-transport", reason_code="test-control-loss", ) else: supervisor.observe_host_path( HostPathProbeResult( available=False, fingerprint=None, interface=None, source_ipv4=None, route_class="unavailable", reason_code="test-host-loss", ) ) revoked = supervisor.snapshot() assert revoked.lease.state != "reachable" assert revoked.data_plane.state == "healthy" assert revoked.data_plane.host_path_epoch == binding.host_path_epoch monotonic_now[0] += facade_module.LIVE_DATA_PLANE_STALL_SECONDS + 0.01 service._reconcile_connection_supervisor( # noqa: SLF001 {"state": "unknown"}, runtime.snapshot(), ) stalled = supervisor.snapshot() assert stalled.data_plane.state == "stalled" assert stalled.data_plane.reason_code == "live-data-stalled" assert stalled.data_plane.session_id == data_session_id assert stalled.data_plane.host_path_epoch == binding.host_path_epoch monotonic_now[0] = 100.0 + facade_module.LIVE_DATA_PLANE_LOST_SECONDS + 0.01 service._reconcile_connection_supervisor( # noqa: SLF001 {"state": "unknown"}, runtime.snapshot(), ) lost = supervisor.snapshot() assert lost.data_plane.state == "lost" assert lost.data_plane.reason_code == "live-data-lost" assert lost.data_plane.session_id == data_session_id assert lost.data_plane.host_path_epoch == binding.host_path_epoch assert ( supervisor.observe_data_plane( intent_id=binding.intent_id, host_path_epoch=binding.host_path_epoch, state="healthy", session_id="new-data-session-without-current-lease", ) is False ) def test_bound_live_data_session_expires_across_host_suspend( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) binding = _seed_supervised_connection(service) runtime.source_mode = "live" runtime.phase = "live" monotonic_now = [300.0] suspend_aware_now = [3_000.0] monkeypatch.setattr(facade_module.time, "monotonic", lambda: monotonic_now[0]) monkeypatch.setattr(facade_module.time, "time", lambda: suspend_aware_now[0]) supervisor = service._connection_supervisor # noqa: SLF001 data_session_id = "pre-suspend-data-session" assert supervisor.observe_data_plane( intent_id=binding.intent_id, host_path_epoch=binding.host_path_epoch, state="healthy", session_id=data_session_id, ) with service._lock: # noqa: SLF001 service._last_live_data_monotonic = monotonic_now[0] # noqa: SLF001 service._last_live_data_suspend_aware = suspend_aware_now[0] # noqa: SLF001 service._last_live_data_session_id = data_session_id # noqa: SLF001 supervisor.observe_host_path( HostPathProbeResult( available=False, fingerprint=None, interface=None, source_ipv4=None, route_class="unavailable", reason_code="host-suspended", ) ) suspend_aware_now[0] += facade_module.LIVE_DATA_PLANE_STALL_SECONDS + 0.01 service._reconcile_connection_supervisor( # noqa: SLF001 {"state": "unknown"}, runtime.snapshot(), ) assert supervisor.snapshot().data_plane.state == "stalled" suspend_aware_now[0] = 3_000.0 + facade_module.LIVE_DATA_PLANE_LOST_SECONDS + 0.01 service._reconcile_connection_supervisor( # noqa: SLF001 {"state": "unknown"}, runtime.snapshot(), ) lost = supervisor.snapshot() assert lost.data_plane.state == "lost" assert lost.data_plane.reason_code == "live-data-lost" assert lost.data_plane.host_path_epoch == binding.host_path_epoch def test_only_exact_bound_live_data_session_can_refresh_after_lease_loss( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) binding = _seed_supervised_connection(service) runtime.source_mode = "live" runtime.phase = "live" runtime.source_ready = True runtime.producer_generation = 4 monotonic_now = [200.0] monkeypatch.setattr(facade_module.time, "monotonic", lambda: monotonic_now[0]) def published_point_cloud(sequence: int) -> DecodedPointCloudView: return DecodedPointCloudView( context=ConsumerFrameContext( sequence=sequence, captured_at_epoch_ns=sequence, received_monotonic_ns=sequence, processing_started_monotonic_ns=sequence, encoded_size_bytes=16, live=True, ), frame_id="map", positions_xyz=((0.0, 0.0, 0.0),), ) runtime.pcl_frames = 1 service._observe_published_runtime_envelope( # noqa: SLF001 published_point_cloud(1), runtime.producer_generation, ) supervisor = service._connection_supervisor # noqa: SLF001 bound = supervisor.snapshot().data_plane assert bound.state == "healthy" assert bound.session_id == "test-session-test-ble-transport" assert bound.host_path_epoch == binding.host_path_epoch assert supervisor.observe_control_loss( intent_id=binding.intent_id, host_path_epoch=binding.host_path_epoch, control_session_id="test-control-test-ble-transport", reason_code="test-control-loss", ) assert supervisor.observe_data_plane( intent_id=binding.intent_id, host_path_epoch=binding.host_path_epoch, state="stalled", session_id="test-session-test-ble-transport", reason_code="test-data-stall", ) monotonic_now[0] += 1.0 runtime.pcl_frames = 2 service._observe_published_runtime_envelope( # noqa: SLF001 published_point_cloud(2), runtime.producer_generation, ) refreshed = supervisor.snapshot() assert refreshed.data_plane.state == "healthy" assert refreshed.data_plane.session_id == "test-session-test-ble-transport" assert refreshed.authority.control_allowed is False assert refreshed.authority.data_ingest_authoritative is False with service._lock: # noqa: SLF001 service._device_session_id = "new-session-without-current-lease" # noqa: SLF001 monotonic_now[0] += 1.0 runtime.pcl_frames = 3 service._observe_published_runtime_envelope( # noqa: SLF001 published_point_cloud(3), runtime.producer_generation, ) rejected_new_session = supervisor.snapshot() assert rejected_new_session.data_plane.session_id == ("test-session-test-ble-transport") assert service._last_live_data_session_id == ( # noqa: SLF001 "test-session-test-ble-transport" ) def test_postpublished_pcl_rolls_same_session_to_fresh_control_epoch_after_wifi_rebind( tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) binding = _seed_supervised_connection(service) runtime.source_mode = "live" runtime.phase = "live" runtime.source_ready = True runtime.producer_generation = 4 def published_point_cloud(sequence: int) -> DecodedPointCloudView: return DecodedPointCloudView( context=ConsumerFrameContext( sequence=sequence, captured_at_epoch_ns=sequence, received_monotonic_ns=sequence, processing_started_monotonic_ns=sequence, encoded_size_bytes=16, live=True, ), frame_id="map", positions_xyz=((0.0, 0.0, 0.0),), ) runtime.pcl_frames = 1 service._observe_published_runtime_envelope( # noqa: SLF001 published_point_cloud(1), runtime.producer_generation, ) supervisor = service._connection_supervisor # noqa: SLF001 before_loss = supervisor.snapshot() data_session_id = "test-session-test-ble-transport" assert before_loss.host_path.epoch == binding.host_path_epoch assert before_loss.data_plane.session_id == data_session_id assert before_loss.data_plane.host_path_epoch == binding.host_path_epoch supervisor.observe_host_path( HostPathProbeResult( available=False, fingerprint=None, interface=None, source_ipv4=None, route_class="unavailable", reason_code="host-route-unavailable", ) ) rebound_epoch = supervisor.observe_host_path( HostPathProbeResult( available=True, fingerprint="route-after-wifi-return", interface="test0", source_ipv4="192.168.1.2", route_class="direct", kernel_route_fingerprint="route-after-wifi-return", ) ) target = EndpointTarget(binding.target_ipv4, binding.target_port) assert supervisor.observe_endpoint( target=target, intent_id=binding.intent_id, host_path_epoch=rebound_epoch, reachable=True, ) assert supervisor.observe_control_evidence( VerifiedControlEvidence( intent_id=binding.intent_id, transport_ref=binding.transport_ref, host_path_epoch=rebound_epoch, target=target, connection_mode=binding.connection_mode, logical_device_id="known-k1", compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, control_session_id="post-wifi-control", control_proof_revision=2, control_proof_source="correlated-application-response", ) ) rebound = supervisor.snapshot() assert rebound.host_path.epoch == rebound_epoch assert rebound.authority.control_allowed is True assert rebound.data_plane.session_id == data_session_id assert rebound.data_plane.host_path_epoch == binding.host_path_epoch assert rebound.authority.data_ingest_authoritative is False runtime.pcl_frames = 2 service._observe_published_runtime_envelope( # noqa: SLF001 published_point_cloud(2), runtime.producer_generation, ) recovered = supervisor.snapshot() assert recovered.data_plane.state == "healthy" assert recovered.data_plane.session_id == data_session_id assert recovered.data_plane.host_path_epoch == rebound_epoch assert recovered.data_plane.host_path_epoch == recovered.host_path.epoch assert recovered.authority.data_ingest_authoritative is True def test_pose_only_traffic_cannot_refresh_point_cloud_health_during_recovery( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) binding = _seed_supervised_connection(service) runtime.source_mode = "live" runtime.phase = "live" runtime.source_ready = True runtime.producer_generation = 4 now = [100.0] monkeypatch.setattr(facade_module.time, "monotonic", lambda: now[0]) monkeypatch.setattr(facade_module.time, "time", lambda: now[0]) def packet(sequence: int, topic: str) -> StreamMessage: return StreamMessage( sequence=sequence, topic=topic, payload=b"data-plane-evidence", received_at_epoch_ns=sequence, received_monotonic_ns=sequence, source="live_mqtt", producer_generation=4, ) baseline = DecodedPointCloudView( context=ConsumerFrameContext( sequence=1, captured_at_epoch_ns=1, received_monotonic_ns=1, processing_started_monotonic_ns=1, encoded_size_bytes=16, live=True, ), frame_id="map", positions_xyz=((0.0, 0.0, 0.0),), ) runtime.pcl_frames = 1 service._observe_published_runtime_envelope( # noqa: SLF001 baseline, runtime.producer_generation, ) assert service._last_live_data_monotonic == 100.0 # noqa: SLF001 assert service._connection_supervisor.snapshot().data_plane.state == "healthy" # noqa: SLF001 runtime.phase = "reconnecting" runtime.source_ready = False runtime.recovery_state = "reconnecting" now[0] += facade_module.LIVE_DATA_PLANE_STALL_SECONDS + 0.01 service._observe_runtime_message( # noqa: SLF001 packet(2, "lixel/application/report/lio_pose"), BridgeMetrics(), ) assert service._last_live_data_monotonic == 100.0 # noqa: SLF001 service._observe_runtime_message( # noqa: SLF001 packet(3, "RealtimePointcloud"), BridgeMetrics(), ) assert service._last_live_data_monotonic == 100.0 # noqa: SLF001 service._reconcile_connection_supervisor( # noqa: SLF001 {"state": "unknown"}, runtime.snapshot(), ) assert service._connection_supervisor.snapshot().data_plane.state == "stalled" # noqa: SLF001 now[0] = 100.0 + facade_module.LIVE_DATA_PLANE_LOST_SECONDS + 0.01 service._observe_runtime_message( # noqa: SLF001 packet(4, "RealtimePath"), BridgeMetrics(), ) assert service._last_live_data_monotonic == 100.0 # noqa: SLF001 service._reconcile_connection_supervisor( # noqa: SLF001 {"state": "unknown"}, runtime.snapshot(), ) lost = service._connection_supervisor.snapshot().data_plane # noqa: SLF001 assert lost.state == "lost" assert lost.reason_code == "live-data-lost" assert lost.host_path_epoch == binding.host_path_epoch def test_new_ble_scan_generation_invalidates_old_candidates_before_io_and_on_failure( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service, device_id="old-scan-device") async def scenario() -> None: entered = asyncio.Event() release = asyncio.Event() async def failing_scan( _duration_seconds: float, *, on_admitted: Callable[[], None] | None = None, ) -> dict[str, Any]: if on_admitted is not None: on_admitted() entered.set() await release.wait() raise RuntimeError("synthetic BLE scan failure") monkeypatch.setattr(facade_module, "scan", failing_scan) scan_task = asyncio.create_task(service.scan_ble(6.0)) await asyncio.wait_for(entered.wait(), timeout=1.0) assert service.state()["devices"] == [] release.set() with pytest.raises(RuntimeError, match="synthetic BLE scan failure"): await asyncio.wait_for(scan_task, timeout=1.0) asyncio.run(scenario()) failed_state = service.state() assert failed_state["devices"] == [] assert service._devices == [] # noqa: SLF001 assert service._ble_device_last_seen_monotonic == {} # noqa: SLF001 failed_operation = failed_state["last_operation"] assert failed_operation["status"] == "failed" assert failed_operation["error"] == { "category": "transport", "code": "RuntimeError", "retryable": True, "safe_to_retry": True, "side_effect_status": "none", } def test_ble_scan_operation_id_is_exactly_once_and_request_bound( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) transport_calls = 0 async def successful_scan( _duration_seconds: float, *, on_admitted: Callable[[], None] | None = None, ) -> dict[str, Any]: nonlocal transport_calls if on_admitted is not None: on_admitted() transport_calls += 1 return _ble_scan_result("exactly-once-device") monkeypatch.setattr(facade_module, "scan", successful_scan) operation_id = "op-00000000-0000-4000-8000-000000000001" request = BleScanRequest(duration_seconds=6.0, operation_id=operation_id) first = asyncio.run(service.scan_ble(request)) repeated = asyncio.run(service.scan_ble(request)) assert transport_calls == 1 assert first["devices"][0]["connectable"] is None assert first["last_operation"]["operation_id"] == operation_id assert repeated["last_operation"]["operation_id"] == operation_id with pytest.raises(ValueError, match="different request"): asyncio.run( service.scan_ble( BleScanRequest( duration_seconds=7.0, operation_id=operation_id, ) ) ) def test_ble_scan_maps_process_runtime_busy_to_operation_journal( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service, device_id="active-scan-result") service._operation_phase = "scanning" # noqa: SLF001 async def scenario() -> tuple[Any, dict[str, Any]]: async def busy_scan( _duration_seconds: float, *, on_admitted: Callable[[], None] | None = None, ) -> dict[str, Any]: del on_admitted raise BleRuntimeBusy( active_operation_kind="status-read", cleanup_pending=False, ) monkeypatch.setattr(facade_module, "scan", busy_scan) with pytest.raises(BleRuntimeBusy, match="уже выполняется"): await service.scan_ble(6.0) assert service._operation_phase == "scanning" # noqa: SLF001 rejected_state = service.state() async def recovered_scan( _duration_seconds: float, *, on_admitted: Callable[[], None] | None = None, ) -> dict[str, Any]: if on_admitted is not None: on_admitted() return _ble_scan_result("second-generation") monkeypatch.setattr(facade_module, "scan", recovered_scan) recovered_state = await service.scan_ble(6.0) return rejected_state, recovered_state rejected_state, recovered_state = asyncio.run(scenario()) assert [item["device_id"] for item in rejected_state["devices"]] == ["active-scan-result"] rejected_operation = rejected_state["last_operation"] assert rejected_operation["status"] == "failed" assert rejected_operation["stage_code"] == "busy" assert rejected_operation["message_code"] == "discovery.scan.already_running" assert rejected_operation["error"] == { "category": "conflict", "code": "ble-runtime-busy", "retryable": True, "safe_to_retry": True, "side_effect_status": "none", } assert [item["device_id"] for item in recovered_state["devices"]] == ["second-generation"] def test_ble_scan_does_not_block_owner_loop_on_sync_lifecycle_gate( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) gate_held = threading.Event() release_gate = threading.Event() def hold_sync_lifecycle_gate() -> None: with service._acquisition_lifecycle_gate: # noqa: SLF001 gate_held.set() release_gate.wait(timeout=2.0) holder = threading.Thread(target=hold_sync_lifecycle_gate) holder.start() assert gate_held.wait(timeout=1.0) async def admitted_scan( _duration_seconds: float, *, on_admitted: Callable[[], None] | None = None, ) -> dict[str, Any]: if on_admitted is not None: on_admitted() release_gate.set() return _ble_scan_result("nonblocking-scan") monkeypatch.setattr(facade_module, "scan", admitted_scan) started_at = time.monotonic() started = asyncio.run(service.scan_ble(6.0)) elapsed = time.monotonic() - started_at holder.join(timeout=1.0) assert not holder.is_alive() assert elapsed < 0.5 assert [item["device_id"] for item in started["devices"]] == ["nonblocking-scan"] def test_ble_scan_maps_hard_timeout_to_operation_journal( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) async def scenario() -> tuple[dict[str, Any], dict[str, Any]]: async def timed_out_scan( _duration_seconds: float, *, on_admitted: Callable[[], None] | None = None, ) -> dict[str, Any]: if on_admitted is not None: on_admitted() raise BleOperationHardTimeout( "scan", BleOperationProgress(operation_stage="discovery"), ) monkeypatch.setattr(facade_module, "scan", timed_out_scan) with pytest.raises(BleOperationHardTimeout, match="не завершилась"): await service.scan_ble(6.0) assert service._operation_phase is None # noqa: SLF001 failed_state = service.state() async def recovered_scan( _duration_seconds: float, *, on_admitted: Callable[[], None] | None = None, ) -> dict[str, Any]: if on_admitted is not None: on_admitted() return _ble_scan_result("after-timeout") monkeypatch.setattr(facade_module, "scan", recovered_scan) recovered_state = await service.scan_ble(6.0) return failed_state, recovered_state failed_state, recovered_state = asyncio.run(scenario()) assert failed_state["devices"] == [] failed_operation = failed_state["last_operation"] assert failed_operation["status"] == "failed" assert failed_operation["error"] == { "category": "transport", "code": "ble-discovery-timeout", "retryable": True, "safe_to_retry": True, "side_effect_status": "none", "operation_stage": "discovery", "device_write_attempted": False, "device_write_confirmed": False, "host_diagnostic": { "schema_version": "missioncore.host-failure-diagnostic/v1", "code": "host.bluetooth.operation-timeout", "domain": "corebluetooth", "impact": "discovery", "operator_action": "explicit-retry", "automatic_retry": False, "redacted": True, }, } assert [item["device_id"] for item in recovered_state["devices"]] == ["after-timeout"] def test_cancelled_ble_scan_is_journaled_and_releases_process_gate( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) async def scenario() -> tuple[dict[str, Any], dict[str, Any]]: transport_entered = asyncio.Event() transport_cancelled = asyncio.Event() async def blocked_scan( _duration_seconds: float, *, on_admitted: Callable[[], None] | None = None, ) -> dict[str, Any]: if on_admitted is not None: on_admitted() transport_entered.set() try: await asyncio.Event().wait() except asyncio.CancelledError: transport_cancelled.set() raise monkeypatch.setattr(facade_module, "scan", blocked_scan) scan_task = asyncio.create_task(service.scan_ble(6.0)) await asyncio.wait_for(transport_entered.wait(), timeout=1.0) scan_task.cancel() with pytest.raises(asyncio.CancelledError): await scan_task assert transport_cancelled.is_set() assert service._operation_phase is None # noqa: SLF001 cancelled_state = service.state() async def recovered_scan( _duration_seconds: float, *, on_admitted: Callable[[], None] | None = None, ) -> dict[str, Any]: if on_admitted is not None: on_admitted() return _ble_scan_result("after-cancellation") monkeypatch.setattr(facade_module, "scan", recovered_scan) recovered_state = await service.scan_ble(6.0) return cancelled_state, recovered_state cancelled_state, recovered_state = asyncio.run(scenario()) assert cancelled_state["devices"] == [] cancelled_operation = cancelled_state["last_operation"] assert cancelled_operation["status"] == "cancelled" assert cancelled_operation["stage_code"] == "cancelled" assert cancelled_operation["message_code"] == "discovery.scan.cancelled" assert cancelled_operation["error"] == { "category": "transport", "code": "ble-discovery-cancelled", "retryable": True, "safe_to_retry": True, "side_effect_status": "none", } assert [item["device_id"] for item in recovered_state["devices"]] == ["after-cancellation"] def test_connect_owns_lifecycle_while_safe_preflight_rejects_a_competing_scan( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service) mode_revision = _select_connection_mode(service, "quick-connect") preflight_entered = threading.Event() release_preflight = threading.Event() def delayed_preflight(*_: object, **__: object) -> dict[str, Any]: preflight_entered.set() if not release_preflight.wait(timeout=1.0): raise RuntimeError("test preflight release timed out") return { "schema_version": 1, "adapter": "macOS Keychain", "available": False, "profile_enrolled": False, "credential_source": "exact-firmware-profile", } async def replacement_scan( _duration_seconds: float, *, on_admitted: Callable[[], None] | None = None, ) -> dict[str, Any]: if on_admitted is not None: on_admitted() return { "devices": [ { "macos_uuid": "replacement-device", "name": "XGR-NEW", "local_name": "XGR-NEW", "rssi": -40, "k1_name_candidate": True, } ] } @asynccontextmanager async def forbidden_activation( *_args: object, **_kwargs: object, ) -> AsyncIterator[dict[str, Any]]: raise AssertionError("changed discovery generation must stop before BLE write") yield {} monkeypatch.setattr( facade_module, "ensure_wifi_profile_from_credential_source", delayed_preflight, ) monkeypatch.setattr(facade_module, "scan", replacement_scan) monkeypatch.setattr(facade_module, "device_ap_activation_session", forbidden_activation) async def scenario() -> None: connect_task = asyncio.create_task( service.connect( _connect_request( device_id="test-ble-transport", connection_mode="quick-connect", compatibility_attestation=QUICK_CONNECT_ATTESTATION, expected_mode_revision=mode_revision, ) ) ) entered = await asyncio.wait_for( asyncio.to_thread(preflight_entered.wait, 1.0), timeout=1.5, ) assert entered is True with pytest.raises( facade_module.BleDiscoveryUnavailable, match="настройки Wi-Fi", ) as scan_failure: await service.scan_ble(6.0) assert scan_failure.value.reason_code == "ble-discovery-blocked-by-provisioning" release_preflight.set() with pytest.raises(facade_module.HostWifiProfileError): await asyncio.wait_for(connect_task, timeout=1.0) try: asyncio.run(scenario()) finally: release_preflight.set() def test_provision_scan_is_rejected_after_atomic_fence_before_control_retirement( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service, device_id="k1-a") generation_before = service._ble_discovery_generation # noqa: SLF001 scan_outcomes: list[object] = [] provision_calls = 0 async def racing_scan( _duration_seconds: float, *, on_admitted: Callable[[], None] | None = None, ) -> dict[str, Any]: assert on_admitted is not None on_admitted() return _ble_scan_result("racing-scan") original_retire = service._retire_application_control_for_network_change # noqa: SLF001 def retire_with_competing_scan() -> None: assert service._provisioning_active is True # noqa: SLF001 scan_outcomes.append( _attempt_competing_scan_from_sync_boundary( service, operation_id="op-00000000-0000-4000-8000-000000000101", ) ) original_retire() async def fake_provision( *_: object, on_write_dispatch: Callable[[dict[str, Any], str], None] | None = None, **__: object, ) -> dict[str, Any]: nonlocal provision_calls provision_calls += 1 assert service._provisioning_active is True # noqa: SLF001 _dispatch_test_network_write(on_write_dispatch) return { "started_at_utc": "2026-08-06T12:00:00Z", "completed_at_utc": "2026-08-06T12:00:01Z", "profile_id": "xgrids-k1-fw3-wifi-v1", "outcome": "lan_address_observed", "write_mode": "with_response", "observations": [ { "status": { "mode": "WIFI_CLIENT", "ipv4": "192.168.68.50", "status_code": 1, "reserved": 0, } } ], } monkeypatch.setattr(facade_module, "scan", racing_scan) monkeypatch.setattr( service, "_retire_application_control_for_network_change", retire_with_competing_scan, ) monkeypatch.setattr(facade_module, "provision_wifi_once", fake_provision) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr(facade_module, "_host_route_class", lambda _target: "direct-or-routed") monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) monkeypatch.setattr(facade_module, "_control_endpoint_reachable", lambda _target: True) monkeypatch.setattr( facade_module, "_await_control_endpoint_reachable", _reachable_control_endpoint, ) connected = asyncio.run( service.connect( _connect_request( device_id="k1-a", ssid="lab-router", password=SecretStr(PRIMARY_TEST_CREDENTIAL), connection_mode="bridge", compatibility_attestation=ATTESTATION, ) ) ) assert len(scan_outcomes) == 1 scan_error = scan_outcomes[0] assert isinstance(scan_error, facade_module.BleDiscoveryUnavailable) assert scan_error.reason_code == "ble-discovery-blocked-by-provisioning" assert service._ble_discovery_generation == generation_before # noqa: SLF001 assert [item["device_id"] for item in connected["devices"]] == ["k1-a"] assert provision_calls == 1 assert connected["connection_mode"] == "bridge" assert service._provisioning_active is False # noqa: SLF001 scan_operation = next( item for item in connected["operations"] if item["operation_id"] == "op-00000000-0000-4000-8000-000000000101" ) assert scan_operation["status"] == "failed" assert scan_operation["error"]["code"] == "ble-discovery-blocked-by-provisioning" def test_corrupt_identity_pin_store_fails_after_new_intent_retires_old_control( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service, device_id="k1-a") retire_calls = 0 def corrupt_identity_lookup(_transport_ref: str) -> None: raise DeviceIdentityPinStoreCorrupt("synthetic corrupt pin store") def record_retirement() -> None: nonlocal retire_calls retire_calls += 1 async def forbidden_provision(*_: object, **__: object) -> dict[str, Any]: raise AssertionError("identity preflight must fail before the BLE write boundary") monkeypatch.setattr(service, "_expected_vendor_device_id", corrupt_identity_lookup) monkeypatch.setattr( service, "_retire_application_control_for_network_change", record_retirement, ) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_provision) with pytest.raises( DeviceIdentityPinStoreCorrupt, match="synthetic corrupt pin store", ): asyncio.run( service.connect( _connect_request( device_id="k1-a", ssid="lab-router", password=SecretStr(PRIMARY_TEST_CREDENTIAL), connection_mode="bridge", compatibility_attestation=ATTESTATION, ) ) ) assert retire_calls == 1 assert service._provisioning_active is False # noqa: SLF001 assert service._ble_discovery_generation == 0 # noqa: SLF001 assert [item["device_id"] for item in service.state()["devices"]] == ["k1-a"] def test_unavailable_semantic_topology_store_fails_after_new_intent_retirement_without_write( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service, device_id="k1-a") service._semantic_topology_store = None # noqa: SLF001 retire_calls = 0 def record_retirement() -> None: nonlocal retire_calls retire_calls += 1 async def forbidden_provision(*_: object, **__: object) -> dict[str, Any]: raise AssertionError("semantic store preflight must fail before the BLE write boundary") monkeypatch.setattr( service, "_retire_application_control_for_network_change", record_retirement, ) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_provision) with pytest.raises( SemanticTopologyStoreCorrupt, match="semantic topology store is unavailable", ): asyncio.run( service.connect( _connect_request( device_id="k1-a", ssid="lab-router", password=SecretStr(PRIMARY_TEST_CREDENTIAL), connection_mode="bridge", compatibility_attestation=ATTESTATION, ) ) ) assert retire_calls == 1 assert service._provisioning_active is False # noqa: SLF001 assert service._provisioning_gate.locked() is False # noqa: SLF001 assert service._ble_discovery_generation == 0 # noqa: SLF001 assert [item["device_id"] for item in service.state()["devices"]] == ["k1-a"] def test_verify_connection_adopts_scanned_existing_lan_without_device_write( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) # Ordinary topology adoption must still retire unrelated terminal local # history. Only a later exact physical SCANNING reconciliation may # materialize the bounded recovery-only STOP identity. service._acquisition = facade_module.AcquisitionRecord( # noqa: SLF001 acquisition_id="stale-terminal-acquisition", device_id="stale-device", device_session_id="stale-device-session", compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, control_mode="plugin-commanded", requested_streams=(), target_host="192.168.68.99", duration_seconds=None, evidence_policy="disabled", state="failed", ) service._acquisition_project_name = "STALE" # noqa: SLF001 _set_scanned_k1(service) status_reads: list[tuple[str, float, bool]] = [] async def fake_status_read( device_id: str, *, timeout_seconds: float, rediscover: bool, **_: object, ) -> dict[str, Any]: status_reads.append((device_id, timeout_seconds, rediscover)) return _wifi_status_read("10.255.254.77") async def forbidden_provision(*_: object, **__: object) -> dict[str, Any]: raise AssertionError("connection.verify must never call Wi-Fi provisioning") monkeypatch.setattr(facade_module, "read_wifi_status_once", fake_status_read) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_provision) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr(facade_module, "_host_route_class", lambda _target: "direct-or-routed") monkeypatch.setattr(facade_module, "_control_endpoint_reachable", lambda _target: True) monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) state = asyncio.run( service.verify_connection( ConnectionVerifyRequest( device_id="test-ble-transport", compatibility_attestation=ATTESTATION, expected_discovery_generation=0, ) ) ) assert status_reads == [("test-ble-transport", 20.0, False)] assert state["selected_device_id"] == "test-ble-transport" assert state["k1_ip"] == "10.255.254.77" assert state["connection_mode"] == "bridge" assert state["device_ref"]["transport_alias"] == "test-ble-transport" assert state["device_session"]["connectivity"] == "connected" assert state["compatibility"]["attestation"]["topology"] == "direct-lan" assert state["connection_verification"] == { "status": "reachable", "lease_state": "reachable", "lease_generation": state["connection_supervisor"]["lease"]["generation"], "endpoint_validation": "ble-wifi-status-read+mqtt-tcp-connect", "network_reachability": "reachable", "host_route_class": "direct-or-routed", "address_source": "ble-wifi-status-read", "connection_origin": "external-existing-network", "admission_source": "connection.verify", "address_changed": True, "previous_address_present": False, "write_performed": False, "observed_at": "2026-07-20T12:00:00Z", "reason_code": None, "supervisor_revision": state["connection_verification"]["supervisor_revision"], } assert state["last_operation"]["action"] == "connection.verify" assert state["last_operation"]["status"] == "succeeded" assert state["last_operation"]["result"]["write_performed"] is False assert state["last_operation"]["result"]["control_verified"] is True assert state["connection_lifecycle"]["connection_ready"] is True assert state["connection_lifecycle"]["active_mode"] == "bridge" assert state["acquisition"] is None assert service._acquisition_project_name is None # noqa: SLF001 def test_read_only_verify_scan_is_rejected_after_atomic_fence_before_admission( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service) generation_before = service._ble_discovery_generation # noqa: SLF001 scan_outcomes: list[object] = [] admission_calls = 0 async def racing_scan( _duration_seconds: float, *, on_admitted: Callable[[], None] | None = None, ) -> dict[str, Any]: assert on_admitted is not None on_admitted() return _ble_scan_result("racing-scan") async def fake_status_read(*_: object, **__: object) -> dict[str, Any]: return _wifi_status_read("10.255.254.77") original_retire = service._retire_application_control_for_network_change # noqa: SLF001 original_apply = service._apply_read_only_device_topology # noqa: SLF001 def retire_with_competing_scan() -> None: assert service._provisioning_active is True # noqa: SLF001 scan_outcomes.append( _attempt_competing_scan_from_sync_boundary( service, operation_id="op-00000000-0000-4000-8000-000000000102", ) ) original_retire() def apply_with_fence_assertion(**kwargs: Any) -> str: nonlocal admission_calls admission_calls += 1 assert service._provisioning_active is True # noqa: SLF001 return original_apply(**kwargs) monkeypatch.setattr(facade_module, "scan", racing_scan) monkeypatch.setattr(facade_module, "read_wifi_status_once", fake_status_read) monkeypatch.setattr( service, "_retire_application_control_for_network_change", retire_with_competing_scan, ) monkeypatch.setattr( service, "_apply_read_only_device_topology", apply_with_fence_assertion, ) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr(facade_module, "_host_route_class", lambda _target: "direct-or-routed") monkeypatch.setattr(facade_module, "_control_endpoint_reachable", lambda _target: True) monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) verified = asyncio.run( service.verify_connection( ConnectionVerifyRequest( device_id="test-ble-transport", compatibility_attestation=ATTESTATION, expected_discovery_generation=0, ) ) ) assert len(scan_outcomes) == 1 scan_error = scan_outcomes[0] assert isinstance(scan_error, facade_module.BleDiscoveryUnavailable) assert scan_error.reason_code == "ble-discovery-blocked-by-provisioning" assert service._ble_discovery_generation == generation_before # noqa: SLF001 assert [item["device_id"] for item in verified["devices"]] == ["test-ble-transport"] assert admission_calls == 1 assert verified["connection_mode"] == "bridge" assert verified["k1_ip"] == "10.255.254.77" assert service._provisioning_active is False # noqa: SLF001 scan_operation = next( item for item in verified["operations"] if item["operation_id"] == "op-00000000-0000-4000-8000-000000000102" ) assert scan_operation["status"] == "failed" assert scan_operation["error"]["code"] == "ble-discovery-blocked-by-provisioning" def test_connection_verify_operation_id_is_exactly_once_and_request_bound( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service) status_reads = 0 async def fake_status_read(*_: object, **__: object) -> dict[str, Any]: nonlocal status_reads status_reads += 1 return _wifi_status_read("10.255.254.77") monkeypatch.setattr(facade_module, "read_wifi_status_once", fake_status_read) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr(facade_module, "_host_route_class", lambda _target: "direct-or-routed") monkeypatch.setattr(facade_module, "_control_endpoint_reachable", lambda _target: True) monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) operation_id = "op-00000000-0000-4000-8000-000000000002" request = ConnectionVerifyRequest( device_id="test-ble-transport", compatibility_attestation=ATTESTATION, operation_id=operation_id, expected_discovery_generation=0, ) first = asyncio.run(service.verify_connection(request)) repeated = asyncio.run(service.verify_connection(request)) assert status_reads == 1 assert first["last_operation"]["operation_id"] == operation_id assert repeated["last_operation"]["operation_id"] == operation_id assert first["last_operation"]["result"]["lease_state"] == "reachable" assert first["last_operation"]["result"]["lease_generation"] == ( first["connection_supervisor"]["lease"]["generation"] ) with pytest.raises(ValueError, match="different request"): asyncio.run( service.verify_connection( ConnectionVerifyRequest( device_id="different-k1", compatibility_attestation=ATTESTATION, operation_id=operation_id, expected_discovery_generation=0, ) ) ) def test_verify_connection_adoption_requires_current_scan_candidate( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) async def forbidden_status_read(*_: object, **__: object) -> dict[str, Any]: raise AssertionError("an unscanned device must not be probed") async def forbidden_provision(*_: object, **__: object) -> dict[str, Any]: raise AssertionError("connection.verify must never call Wi-Fi provisioning") monkeypatch.setattr(facade_module, "read_wifi_status_once", forbidden_status_read) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_provision) with pytest.raises( facade_module.ConnectionVerificationError, match="свежего кандидата", ) as raised: asyncio.run( service.verify_connection( ConnectionVerifyRequest( device_id="not-in-current-scan", compatibility_attestation=ATTESTATION, expected_discovery_generation=0, ) ) ) assert raised.value.reason_code == "connection-verify-candidate-not-fresh" operation = service.state()["last_operation"] assert operation["action"] == "connection.verify" assert operation["status"] == "failed" assert operation["error"] == { "category": "connection", "code": "connection-verify-candidate-not-fresh", "retryable": True, "safe_to_retry": True, "side_effect_status": "none", } def test_verify_connection_timeout_is_journaled_without_device_side_effect( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, caplog: pytest.LogCaptureFixture, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service) async def timed_out_status_read(*_: object, **__: object) -> dict[str, Any]: failure = TimeoutError("synthetic private transport detail") failure.operation_stage = "exact-uuid-scan" # type: ignore[attr-defined] raise failure monkeypatch.setattr(facade_module, "read_wifi_status_once", timed_out_status_read) with ( caplog.at_level(logging.INFO, logger=facade_module.__name__), pytest.raises( facade_module.ConnectionVerificationError, match="не завершил ожидание точного", ) as raised, ): asyncio.run( service.verify_connection( ConnectionVerifyRequest( device_id="test-ble-transport", compatibility_attestation=ATTESTATION, expected_discovery_generation=0, ) ) ) assert raised.value.reason_code == "connection-verify-exact-uuid-scan-timeout" operation = service.state()["last_operation"] assert operation["error"] == { "category": "connection", "code": "connection-verify-exact-uuid-scan-timeout", "retryable": True, "safe_to_retry": True, "side_effect_status": "none", "operation_stage": "exact-uuid-scan", } accepted_at = datetime.fromisoformat(operation["accepted_at"]) deadline_at = datetime.fromisoformat(operation["deadline_at"]) assert (deadline_at - accepted_at).total_seconds() == ( facade_module.CONNECTION_VERIFY_HARD_TIMEOUT_SECONDS ) failure_log = next( record for record in caplog.records if getattr(record, "event_code", None) == "k1_connection_verify_failed" ) assert failure_log.operation_stage == "exact-uuid-scan" assert failure_log.reason_code == "connection-verify-exact-uuid-scan-timeout" assert failure_log.failure_category == "timeout" assert failure_log.device_write_performed is False assert failure_log.automatic_retry is False assert "private" not in str(operation) assert "private" not in caplog.text def test_connection_lease_probe_race_is_an_expected_state_conflict() -> None: failure = facade_module._connection_verification_error( # noqa: SLF001 facade_module.ConnectionLeaseUnavailable( "private concurrent lease mutation detail", reason_code="connection_lease_changed_during_probe", ) ) assert failure.reason_code == "connection-verify-lease-changed" assert str(failure) == "Подключение K1 изменилось во время read-only проверки" assert "private" not in str(failure) def test_read_only_gatt_contract_is_logged_before_missing_dhcp_rejection( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, caplog: pytest.LogCaptureFixture, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service) async def status_without_lan_address(*_: object, **__: object) -> dict[str, Any]: return _wifi_status_read(None) monkeypatch.setattr( facade_module, "read_wifi_status_once", status_without_lan_address, ) with ( caplog.at_level(logging.INFO, logger=facade_module.__name__), pytest.raises(facade_module.ConnectionVerificationError) as raised, ): asyncio.run( service.verify_connection( ConnectionVerifyRequest( device_id="test-ble-transport", compatibility_attestation=ATTESTATION, expected_discovery_generation=0, ) ) ) assert raised.value.reason_code == "connection-verify-address-unavailable" contract_log = next( record for record in caplog.records if getattr(record, "event_code", None) == "k1_ble_gatt_contract_observed" ) assert contract_log.write_characteristic_properties == ["read", "write"] assert contract_log.max_write_without_response_size == 253 assert contract_log.mtu_size == 256 assert contract_log.bridge_frame_length == 99 assert contract_log.quick_connect_frame_length == 100 assert contract_log.device_write_performed is False assert contract_log.automatic_retry is False assert "device_macos_uuid" not in contract_log.__dict__ assert "write_characteristic_uuid" not in contract_log.__dict__ @pytest.mark.parametrize( ("cleanup_pending", "reason_code"), [ (False, "connection-verify-busy"), (True, "connection-verify-cleanup-pending"), ], ) def test_verify_connection_preserves_process_ble_busy_state( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, cleanup_pending: bool, reason_code: str, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service) async def busy_status_read(*_: object, **__: object) -> dict[str, Any]: raise BleRuntimeBusy( active_operation_kind="scan", cleanup_pending=cleanup_pending, ) monkeypatch.setattr(facade_module, "read_wifi_status_once", busy_status_read) with pytest.raises(facade_module.ConnectionVerificationError) as raised: asyncio.run( service.verify_connection( ConnectionVerifyRequest( device_id="test-ble-transport", compatibility_attestation=ATTESTATION, expected_discovery_generation=0, ) ) ) assert raised.value.reason_code == reason_code operation = service.state()["last_operation"] assert operation["error"] == { "category": "connection", "code": reason_code, "retryable": True, "safe_to_retry": True, "side_effect_status": "none", } @pytest.mark.parametrize( ("ipv4", "is_local", "route_class", "endpoint_reachable", "reason_code"), [ (None, False, "direct-or-routed", True, "connection-verify-address-unavailable"), ( "192.168.56.1", False, "device-ap", True, "connection-verify-address-unavailable", ), ( "10.255.254.77", True, "direct-or-routed", True, "connection-verify-local-address-conflict", ), ("10.255.254.77", False, "tunnel", True, "connection-verify-route-mismatch"), ( "10.255.254.77", False, "default-route", True, "connection-verify-route-mismatch", ), ( "10.255.254.77", False, "direct-or-routed", False, "connection-verify-mqtt-unreachable", ), ], ) def test_verify_connection_adoption_fails_closed_before_establishing_lease( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ipv4: str | None, is_local: bool, route_class: str, endpoint_reachable: bool, reason_code: str, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service) async def fake_status_read(*_: object, **__: object) -> dict[str, Any]: return _wifi_status_read(ipv4) async def forbidden_provision(*_: object, **__: object) -> dict[str, Any]: raise AssertionError("connection.verify must never call Wi-Fi provisioning") monkeypatch.setattr(facade_module, "read_wifi_status_once", fake_status_read) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_provision) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: is_local) monkeypatch.setattr(facade_module, "_host_route_class", lambda _target: route_class) monkeypatch.setattr( facade_module, "_control_endpoint_reachable", lambda _target: endpoint_reachable, ) monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) with pytest.raises(facade_module.ConnectionVerificationError) as raised: asyncio.run( service.verify_connection( ConnectionVerifyRequest( device_id="test-ble-transport", compatibility_attestation=ATTESTATION, expected_discovery_generation=0, ) ) ) assert raised.value.reason_code == reason_code state = service.state() assert [item["device_id"] for item in state["devices"]] == ["test-ble-transport"] # Fresh Bridge 7f02 evidence is provisional until route/TCP and exact # DeviceInfo identity all succeed. Any failure before that point retires # only the ephemeral projection, retains the fresh candidate for a later # explicit choice, and never publishes untrusted durable topology. assert state["selected_device_id"] is None assert state["k1_ip"] is None assert state["connection_mode"] is None assert state["device_session"] is None assert state["semantic_topology_store"]["status"] == "empty" assert state["connection_supervisor"]["authority"]["control_allowed"] is False assert state["connection_verification"].get("write_performed") is not True def test_apply_owned_rescan_after_unreachable_verify_dispatches_exactly_one_write( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) device_id = "k1-verify-then-apply" _set_scanned_k1(service, device_id=device_id) old_capture = _SYNTHETIC_SCAN_CAPTURES[device_id] replacement_capture = facade_module.CapturedDiscoveredDevice( device=SimpleNamespace(address=device_id), # type: ignore[arg-type] macos_uuid=device_id, owner_epoch=old_capture.owner_epoch, scan_generation=old_capture.scan_generation + 1, ) active_capture = old_capture invalidated_capture_ids: set[int] = set() pinned_by_session: dict[str, facade_module.CapturedDiscoveredDevice] = {} def exact_capture(requested_device_id: str) -> object | None: assert requested_device_id == device_id if id(active_capture) in invalidated_capture_ids: return None return active_capture def pin_exact_capture( capture: facade_module.CapturedDiscoveredDevice, *, device_session_id: str, ) -> None: assert capture is active_capture pinned_by_session[device_session_id] = capture def invalidate_exact_session( requested_device_id: str, *, device_session_id: str, ) -> bool: assert requested_device_id == device_id retired = pinned_by_session.pop(device_session_id, None) if retired is None: return False invalidated_capture_ids.add(id(retired)) return True async def status_on_unreachable_existing_network( *_: object, captured_device: facade_module.CapturedDiscoveredDevice | None = None, on_gatt_validated: Callable[[facade_module.CapturedDiscoveredDevice], None] | None = None, **__: object, ) -> dict[str, Any]: assert captured_device is old_capture assert on_gatt_validated is not None on_gatt_validated(old_capture) return _wifi_status_read("192.168.1.20", device_id=device_id) monkeypatch.setattr(facade_module, "_capture_network_intent_device", exact_capture) monkeypatch.setattr(facade_module, "capture_discovered_device", exact_capture) monkeypatch.setattr(facade_module, "pin_connected_device_handle", pin_exact_capture) monkeypatch.setattr( facade_module, "invalidate_connected_device_session", invalidate_exact_session, ) monkeypatch.setattr( facade_module, "read_wifi_status_once", status_on_unreachable_existing_network, ) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr( facade_module, "_host_route_class", lambda _target: "direct-or-routed", ) monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) monkeypatch.setattr( facade_module, "_control_endpoint_reachable", lambda _target: False, ) with pytest.raises(facade_module.ConnectionVerificationError) as unavailable: asyncio.run( service.verify_connection( ConnectionVerifyRequest( device_id=device_id, source="fresh-scan", compatibility_attestation=ATTESTATION, expected_discovery_generation=0, ) ) ) assert unavailable.value.reason_code == "connection-verify-mqtt-unreachable" after_verify = service.state() assert [item["device_id"] for item in after_verify["devices"]] == [device_id] assert after_verify["selected_device_id"] is None assert invalidated_capture_ids == {id(old_capture)} assert exact_capture(device_id) is None async def apply_owned_scan( _duration_seconds: float, *, on_admitted: Callable[[], None] | None = None, ) -> dict[str, Any]: nonlocal active_capture assert on_admitted is not None on_admitted() active_capture = replacement_capture return _ble_scan_result(device_id) monkeypatch.setattr(facade_module, "scan", apply_owned_scan) rescanned = asyncio.run(service.scan_ble(BleScanRequest(duration_seconds=1.0))) assert rescanned["ble_discovery_generation"] == 1 assert exact_capture(device_id) is replacement_capture dispatched_writes: list[facade_module.CapturedDiscoveredDevice] = [] async def provision_once( *_: object, captured_device: facade_module.CapturedDiscoveredDevice | None = None, on_write_dispatch: Callable[[dict[str, Any], str], None] | None = None, **__: object, ) -> dict[str, Any]: assert captured_device is replacement_capture _dispatch_test_network_write(on_write_dispatch) dispatched_writes.append(captured_device) return { "started_at_utc": "2026-08-11T07:00:00Z", "completed_at_utc": "2026-08-11T07:00:01Z", "profile_id": "xgrids-k1-fw3-wifi-v1", "outcome": "lan_address_observed", "write_mode": "with_response", "baseline_status": _wifi_status_read(None)["status"], "observations": [{"status": _wifi_status_read("192.168.1.20")["status"]}], } monkeypatch.setattr(facade_module, "provision_wifi_once", provision_once) monkeypatch.setattr( facade_module, "_control_endpoint_reachable", lambda _target: True, ) monkeypatch.setattr( facade_module, "_await_control_endpoint_reachable", _reachable_control_endpoint, ) connected = asyncio.run( service.connect( _connect_request( device_id=device_id, ssid="lab-network", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, expected_discovery_generation=rescanned["ble_discovery_generation"], ) ) ) assert dispatched_writes == [replacement_capture] assert connected["connection_lifecycle"]["connection_ready"] is True network_operations = [ item for item in connected["operations"] if item["action"] == "network.provision" ] assert len(network_operations) == 1 assert network_operations[0]["status"] == "succeeded" verify_operations = [ item for item in connected["operations"] if item["action"] == "connection.verify" ] assert len(verify_operations) == 1 assert verify_operations[0]["status"] == "failed" assert verify_operations[0]["error"]["side_effect_status"] == "none" def test_connection_verify_request_requires_paired_exact_firmware_attestation() -> None: with pytest.raises(ValidationError, match="compatibility_attestation"): ConnectionVerifyRequest(device_id="test-ble-transport") with pytest.raises(ValidationError, match="device_id"): ConnectionVerifyRequest(compatibility_attestation=ATTESTATION) with pytest.raises(ValidationError, match="3.0.2"): ConnectionVerifyRequest( device_id="test-ble-transport", compatibility_attestation={ "firmware_version": "3.0.3", "topology": "direct-lan", "verification": "live-device-info", }, ) with pytest.raises(ValidationError, match="expected_discovery_generation"): ConnectionVerifyRequest( device_id="test-ble-transport", compatibility_attestation=ATTESTATION, ) quick_connect = ConnectionVerifyRequest( device_id="test-ble-transport", compatibility_attestation=QUICK_CONNECT_ATTESTATION, expected_discovery_generation=0, ) assert quick_connect.compatibility_attestation == QUICK_CONNECT_ATTESTATION def test_verify_connection_refreshes_dynamic_dhcp_address_and_rotates_session( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) service._selected_device_id = "test-ble-transport" # noqa: SLF001 service._connection_mode = "bridge" # noqa: SLF001 service._k1_ip = "10.255.254.54" # noqa: SLF001 service._device_id = "known-k1" # noqa: SLF001 service._device_session_id = "old-device-session" # noqa: SLF001 service._device_session_opened_at = "2026-07-20T10:00:00Z" # noqa: SLF001 service._device_calibration = {"status": "available"} # noqa: SLF001 service._compatibility_attestation = ATTESTATION.model_dump(mode="json") # noqa: SLF001 _set_scanned_k1(service) async def fake_status_read(*_: object, **__: object) -> dict[str, Any]: return _wifi_status_read("10.255.254.77") monkeypatch.setattr(facade_module, "read_wifi_status_once", fake_status_read) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr(facade_module, "_host_route_class", lambda _target: "direct-or-routed") monkeypatch.setattr( facade_module, "_control_endpoint_reachable", lambda target: target == "10.255.254.77", ) monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) state = asyncio.run( service.verify_connection( ConnectionVerifyRequest( device_id="test-ble-transport", compatibility_attestation=ATTESTATION, expected_discovery_generation=0, ) ) ) assert state["k1_ip"] == "10.255.254.77" assert state["device_session"]["device_session_id"] != "old-device-session" assert state["connection_verification"] == { "status": "reachable", "lease_state": "reachable", "lease_generation": state["connection_supervisor"]["lease"]["generation"], "endpoint_validation": "ble-wifi-status-read+mqtt-tcp-connect", "network_reachability": "reachable", "host_route_class": "direct-or-routed", "address_source": "ble-wifi-status-read", "connection_origin": "external-existing-network", "admission_source": "connection.verify", "address_changed": True, "previous_address_present": True, "write_performed": False, "observed_at": "2026-07-20T12:00:00Z", "reason_code": None, "supervisor_revision": state["connection_verification"]["supervisor_revision"], } assert state["device_calibration"]["status"] == "unavailable" def test_bridge_read_only_verify_never_shortcuts_fresh_ble_status( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) service._selected_device_id = "test-ble-transport" # noqa: SLF001 service._connection_mode = "bridge" # noqa: SLF001 service._k1_ip = "10.255.254.54" # noqa: SLF001 service._compatibility_attestation = ATTESTATION.model_dump(mode="json") # noqa: SLF001 service._device_id = "known-k1" # noqa: SLF001 service._device_session_id = "known-device-session" # noqa: SLF001 _set_scanned_k1(service) _seed_supervised_connection( service, target_ipv4="10.255.254.54", with_control=False, ) service._device_session_id = "known-device-session" # noqa: SLF001 monkeypatch.setattr(facade_module, "_host_route_class", lambda _target: "direct-or-routed") monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr(facade_module, "_control_endpoint_reachable", lambda _target: True) monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) status_reads: list[tuple[str, float, bool]] = [] async def exact_status_read( device_id: str, *, timeout_seconds: float, rediscover: bool, **_: object, ) -> dict[str, Any]: status_reads.append((device_id, timeout_seconds, rediscover)) return _wifi_status_read("10.255.254.54") monkeypatch.setattr(facade_module, "read_wifi_status_once", exact_status_read) state = asyncio.run( service.verify_connection( ConnectionVerifyRequest( device_id="test-ble-transport", compatibility_attestation=ATTESTATION, expected_discovery_generation=0, ) ) ) assert status_reads == [("test-ble-transport", 20.0, False)] assert state["k1_ip"] == "10.255.254.54" # A fresh exact BLE observation creates a new intent/session fence even # when DHCP returned the same address. Similar endpoint text is not # continuity authority. assert state["device_session"]["device_session_id"] != "known-device-session" assert state["connection_verification"] == { "status": "reachable", "lease_state": "reachable", "lease_generation": state["connection_supervisor"]["lease"]["generation"], "endpoint_validation": "ble-wifi-status-read+mqtt-tcp-connect", "network_reachability": "reachable", "host_route_class": "direct-or-routed", "address_source": "ble-wifi-status-read", "connection_origin": "external-existing-network", "admission_source": "connection.verify", "address_changed": False, "previous_address_present": True, "write_performed": False, "observed_at": "2026-07-20T12:00:00Z", "reason_code": None, "supervisor_revision": state["connection_verification"]["supervisor_revision"], } assert state["last_operation"]["status"] == "succeeded" def test_implicit_acquisition_target_uses_current_ble_dhcp_address( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) service._selected_device_id = "test-ble-transport" # noqa: SLF001 service._connection_mode = "bridge" # noqa: SLF001 service._k1_ip = "10.255.254.54" # noqa: SLF001 service._compatibility_attestation = ATTESTATION.model_dump(mode="json") # noqa: SLF001 status_loop: asyncio.AbstractEventLoop | None = None runtime_loop: asyncio.AbstractEventLoop | None = None async def fake_status_read(*_: object, **__: object) -> dict[str, Any]: nonlocal status_loop status_loop = asyncio.get_running_loop() return _wifi_status_read("10.255.254.77") monkeypatch.setattr(facade_module, "read_wifi_status_once", fake_status_read) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr(facade_module, "_host_route_class", lambda _target: "direct-or-routed") monkeypatch.setattr( facade_module, "_control_endpoint_reachable", lambda target: target == "10.255.254.77", ) monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) async def scenario() -> dict[str, Any]: nonlocal runtime_loop runtime_loop = asyncio.get_running_loop() service.bind_runtime_event_loop() return await asyncio.to_thread( service.prepare_acquisition, _prepare_request( project_name=PROJECT_NAME, compatibility_attestation=ATTESTATION, ), ) state = asyncio.run(scenario()) assert state["k1_ip"] == "10.255.254.77" assert state["acquisition"]["target_host"] == "10.255.254.77" assert status_loop is runtime_loop def test_control_session_reuses_reachable_process_owned_connection_lease( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _seed_supervised_connection( service, target_ipv4="10.255.254.54", with_control=False, ) service._device_session_id = "known-session" # noqa: SLF001 service._compatibility_attestation = ATTESTATION.model_dump(mode="json") # noqa: SLF001 opened_hosts: list[str] = [] class FakeOpenControlSession: def __init__(self) -> None: self.state = "idle" self.verified_control: dict[str, object] | None = None def snapshot(self) -> dict[str, object]: return { "state": self.state, "can_confirm_standby": False, "verified_control": self.verified_control, } def open( self, *, host: str, connection_binding: ApplicationConnectionBinding, **_: object, ) -> dict[str, object]: opened_hosts.append(host) self.state = "connection-ready" self.verified_control = _verified_control_for_binding(connection_binding) return self.snapshot() async def forbidden_status_read(*_: object, **__: object) -> dict[str, Any]: raise AssertionError("reachable connection lease must not reopen BLE") service._application_control_session = FakeOpenControlSession() # type: ignore[assignment] # noqa: SLF001 monkeypatch.setattr(facade_module, "read_wifi_status_once", forbidden_status_read) monkeypatch.setattr(facade_module, "_control_endpoint_reachable", lambda _target: True) monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) admission_generation = service._connection_supervisor.snapshot().lease.generation # noqa: SLF001 state = service.open_application_control_session( OpenApplicationControlSessionRequest( operator_present=True, owner_controlled_device=True, lixelgo_closed=True, battery_storage_confirmed=True, expected_physical_state_confirmed=True, timezone_name="Europe/Moscow", ) ) assert opened_hosts == ["10.255.254.54"] assert state["k1_ip"] == "10.255.254.54" assert state["connection_verification"]["lease_state"] == "reachable" assert state["connection_verification"]["network_reachability"] == "reachable" open_operation = next( operation for operation in state["operations"] if operation["action"] == "application-control.session.open" ) assert open_operation["status"] == "succeeded" assert open_operation["result"] == { "lease_generation": admission_generation, "connection_lease_reused": True, "recovery_performed": False, "address_changed": False, "device_write_performed": False, } service._release_application_control_process_lease() # noqa: SLF001 def test_reachable_connection_lease_supports_repeated_independent_control_sessions( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _seed_supervised_connection( service, target_ipv4="10.255.254.54", with_control=False, ) service._device_session_id = "known-session" # noqa: SLF001 service._compatibility_attestation = ATTESTATION.model_dump(mode="json") # noqa: SLF001 opened_hosts: list[str] = [] class FakeCompletedControlSession: def __init__(self) -> None: self.state = "completed" self.verified_control: dict[str, object] | None = None def snapshot(self) -> dict[str, object]: return { "state": self.state, "can_open": True, "can_confirm_standby": False, "verified_control": self.verified_control, } def open( self, *, host: str, connection_binding: ApplicationConnectionBinding, **_: object, ) -> dict[str, object]: opened_hosts.append(host) self.state = "connection-ready" self.verified_control = _verified_control_for_binding( connection_binding, control_session_id=f"fake-control-session-{len(opened_hosts)}", ) return self.snapshot() async def forbidden_status_read(*_: object, **__: object) -> dict[str, Any]: raise AssertionError("repeated scans must not repeat BLE or Wi-Fi setup") service._application_control_session = FakeCompletedControlSession() # type: ignore[assignment] # noqa: SLF001 monkeypatch.setattr(facade_module, "read_wifi_status_once", forbidden_status_read) monkeypatch.setattr(facade_module, "_control_endpoint_reachable", lambda _target: True) monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) request = OpenApplicationControlSessionRequest( operator_present=True, owner_controlled_device=True, lixelgo_closed=True, battery_storage_confirmed=True, expected_physical_state_confirmed=True, timezone_name="Europe/Moscow", ) service.open_application_control_session(request) fake_session = service._application_control_session # noqa: SLF001 fake_session.state = "completed" # type: ignore[attr-defined] state = service.open_application_control_session(request) assert opened_hosts == ["10.255.254.54", "10.255.254.54"] assert state["device_session"]["device_session_id"] == "known-session" assert ( state["connection_verification"]["lease_generation"] == (state["connection_supervisor"]["lease"]["generation"]) ) open_operations = [ operation for operation in state["operations"] if operation["action"] == "application-control.session.open" ] assert len(open_operations) == 2 assert {operation["status"] for operation in open_operations} == {"succeeded"} assert all( operation["result"]["connection_lease_reused"] is True for operation in open_operations ) service._release_application_control_process_lease() # noqa: SLF001 @pytest.mark.parametrize("continuity_change", ["host-epoch", "bridge-to-quick"]) def test_old_device_info_binding_cannot_regain_authority_after_connection_change( tmp_path: Path, continuity_change: str, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) old_binding = _seed_supervised_connection( service, target_ipv4=facade_module.AP_FALLBACK_IPV4, connection_mode="bridge", logical_device_id="known-k1", with_control=False, ) old_control_snapshot = { "state": "connection-ready", "verified_control": _verified_control_for_binding(old_binding), } service._reconcile_connection_supervisor( # noqa: SLF001 old_control_snapshot, runtime.snapshot(), ) assert service._connection_supervisor.snapshot().authority.control_allowed is True # noqa: SLF001 target = EndpointTarget( facade_module.AP_FALLBACK_IPV4, facade_module.CONTROL_MQTT_PORT, ) if continuity_change == "host-epoch": new_epoch = service._connection_supervisor.observe_host_path( # noqa: SLF001 HostPathProbeResult( available=True, fingerprint="test-route-after-wifi-reassociation", interface="test1", source_ipv4="192.168.56.3", route_class="direct", ) ) current_intent = service._connection_supervisor.snapshot().intent # noqa: SLF001 assert current_intent is not None assert service._connection_supervisor.observe_endpoint( # noqa: SLF001 target=target, intent_id=current_intent.intent_id, host_path_epoch=new_epoch, reachable=True, ) else: new_intent_id = "test-intent-quick-after-bridge" service._connection_supervisor.set_intent( # noqa: SLF001 intent_id=new_intent_id, requested_mode="quick-connect", expected_device_id="known-k1", ) assert service._connection_supervisor.observe_device_network_applied( # noqa: SLF001 intent_id=new_intent_id, transport_ref="test-ble-transport", connection_mode="quick-connect", target=target, source="ble-post-write-status", ) epoch = service._connection_supervisor.snapshot().host_path.epoch # noqa: SLF001 assert service._connection_supervisor.observe_endpoint( # noqa: SLF001 target=target, intent_id=new_intent_id, host_path_epoch=epoch, reachable=True, ) # The old application worker may still publish its old DeviceInfo snapshot. # Reconciliation must compare the immutable binding, never relabel it with # the new intent/route merely because the same TCP address answers. service._reconcile_connection_supervisor( # noqa: SLF001 old_control_snapshot, runtime.snapshot(), ) supervisor = service._connection_supervisor.snapshot() # noqa: SLF001 assert supervisor.endpoint.tcp_state == "reachable" assert supervisor.authority.control_allowed is False assert supervisor.authority.acquisition_start_allowed is False assert supervisor.device_identity.state != "verified" assert supervisor.lease.state == "configured-unverified" def test_application_command_binding_guard_rejects_changed_host_epoch( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) binding = _seed_supervised_connection(service) monkeypatch.setattr(service, "_sample_host_path", _direct_host_path) monkeypatch.setattr( service._application_control_session, # noqa: SLF001 "snapshot", lambda: { "state": "connection-ready", "verified_control": _verified_control_for_binding( binding, control_session_id="test-control-test-ble-transport", ), }, ) service._validate_application_connection_binding(binding) # noqa: SLF001 service._connection_supervisor.observe_host_path( # noqa: SLF001 HostPathProbeResult( available=True, fingerprint="route-after-mac-wifi-change", interface="test1", source_ipv4="192.168.56.3", route_class="direct", ) ) with pytest.raises(ApplicationConnectionBindingLost) as caught: service._validate_application_connection_binding(binding) # noqa: SLF001 assert caught.value.reason_code == "application-connection-binding-lost" def test_explicit_stop_dispatch_waits_for_transient_local_lifecycle_holder( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) binding = _seed_supervised_connection(service) monkeypatch.setattr(service, "_sample_host_path", _direct_host_path) monkeypatch.setattr( service._application_control_session, # noqa: SLF001 "snapshot", lambda: { "state": "scanning", "verified_control": _verified_control_for_binding(binding), }, ) assert service._k1_command_dispatch_gate.acquire(blocking=False) # noqa: SLF001 entered = threading.Event() completed = threading.Event() release_callbacks: list[Callable[[], None]] = [] failures: list[BaseException] = [] def acquire_stop_lease() -> None: entered.set() try: release_callbacks.append( service._acquire_application_dispatch_lease( # noqa: SLF001 binding, lambda: False, ) ) except BaseException as exc: # pragma: no branch - asserted below failures.append(exc) finally: completed.set() worker = threading.Thread(target=acquire_stop_lease) worker.start() assert entered.wait(1.0) assert completed.wait(0.1) is False service._k1_command_dispatch_gate.release() # noqa: SLF001 assert completed.wait(1.0) worker.join(timeout=1.0) assert failures == [] assert len(release_callbacks) == 1 release_callbacks[0]() assert service._k1_command_dispatch_gate.acquire(blocking=False) # noqa: SLF001 service._k1_command_dispatch_gate.release() # noqa: SLF001 def test_explicit_stop_dispatch_contention_expires_without_crossing_publish_lease( tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) binding = _seed_supervised_connection(service) assert service._k1_command_dispatch_gate.acquire(blocking=False) # noqa: SLF001 expired = threading.Event() completed = threading.Event() failures: list[BaseException] = [] def acquire_stop_lease() -> None: try: service._acquire_application_dispatch_lease( # noqa: SLF001 binding, expired.is_set, ) except BaseException as exc: # pragma: no branch - asserted below failures.append(exc) finally: completed.set() worker = threading.Thread(target=acquire_stop_lease) worker.start() assert completed.wait(0.1) is False expired.set() assert completed.wait(1.0) worker.join(timeout=1.0) service._k1_command_dispatch_gate.release() # noqa: SLF001 assert len(failures) == 1 assert isinstance(failures[0], ApplicationConnectionBindingLost) assert service._k1_command_dispatch_gate.acquire(blocking=False) # noqa: SLF001 service._k1_command_dispatch_gate.release() # noqa: SLF001 def test_application_command_guard_projects_new_remote_proof_before_admission( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) binding = _seed_supervised_connection(service) monkeypatch.setattr(service, "_sample_host_path", _direct_host_path) control_session_id = "test-control-test-ble-transport" monkeypatch.setattr( service._application_control_session, # noqa: SLF001 "snapshot", lambda: { "state": "connection-ready", "verified_control": _verified_control_for_binding( binding, control_session_id=control_session_id, control_proof_revision=2, control_proof_source="mqtt-heartbeat", ), }, ) service._validate_application_connection_binding(binding) # noqa: SLF001 supervisor = service._connection_supervisor # noqa: SLF001 assert supervisor.snapshot().authority.control_allowed is True assert supervisor._control_proof_revision == 2 # noqa: SLF001 assert supervisor._control_proof_source == "mqtt-heartbeat" # noqa: SLF001 def test_control_session_recovers_changed_bridge_address_without_wifi_write( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _seed_supervised_connection( service, target_ipv4="10.255.254.54", with_control=False, ) service._device_session_id = "old-session" # noqa: SLF001 service._compatibility_attestation = ATTESTATION.model_dump(mode="json") # noqa: SLF001 opened_hosts: list[str] = [] status_calls: list[dict[str, object]] = [] class FakeOpenControlSession: def __init__(self) -> None: self.state = "idle" self.verified_control: dict[str, object] | None = None def snapshot(self) -> dict[str, object]: return { "state": self.state, "can_confirm_standby": False, "verified_control": self.verified_control, } def open( self, *, host: str, connection_binding: ApplicationConnectionBinding, **_: object, ) -> dict[str, object]: opened_hosts.append(host) self.state = "connection-ready" self.verified_control = _verified_control_for_binding(connection_binding) return self.snapshot() async def fake_status_read(*_: object, **kwargs: object) -> dict[str, Any]: status_calls.append(kwargs) return _wifi_status_read("10.255.254.77") service._application_control_session = FakeOpenControlSession() # type: ignore[assignment] # noqa: SLF001 monkeypatch.setattr(facade_module, "read_wifi_status_once", fake_status_read) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr(facade_module, "_host_route_class", lambda _target: "direct-or-routed") monkeypatch.setattr( facade_module, "_control_endpoint_reachable", lambda target: target == "10.255.254.77", ) monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) async def scenario() -> dict[str, Any]: service.bind_runtime_event_loop() return await asyncio.to_thread( service.open_application_control_session, OpenApplicationControlSessionRequest( operator_present=True, owner_controlled_device=True, lixelgo_closed=True, battery_storage_confirmed=True, expected_physical_state_confirmed=True, timezone_name="Europe/Moscow", ), ) state = asyncio.run(scenario()) assert status_calls == [{"timeout_seconds": 20.0, "rediscover": True}] assert opened_hosts == ["10.255.254.77"] assert state["k1_ip"] == "10.255.254.77" assert state["device_session"]["device_session_id"] != "old-session" assert state["connection_verification"]["status"] == "reachable" assert state["connection_verification"]["write_performed"] is False open_operation = next( operation for operation in state["operations"] if operation["action"] == "application-control.session.open" ) assert open_operation["result"]["recovery_performed"] is True assert open_operation["result"]["address_changed"] is True assert open_operation["result"]["device_write_performed"] is False def test_control_session_prestart_failure_is_journaled_and_marks_lease_offline( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _seed_supervised_connection( service, target_ipv4="10.255.254.54", endpoint_reachable=False, with_control=False, ) service._device_session_id = "known-session" # noqa: SLF001 service._compatibility_attestation = ATTESTATION.model_dump(mode="json") # noqa: SLF001 async def failed_status_read(*_: object, **__: object) -> dict[str, Any]: raise TimeoutError("synthetic BLE recovery timeout") monkeypatch.setattr(facade_module, "read_wifi_status_once", failed_status_read) monkeypatch.setattr(facade_module, "_control_endpoint_reachable", lambda _target: False) monkeypatch.setattr(facade_module, "_host_route_class", lambda _target: "direct-or-routed") with pytest.raises( facade_module.ConnectionLeaseUnavailable, match="повторное чтение состояния", ): service.open_application_control_session( OpenApplicationControlSessionRequest( operator_present=True, owner_controlled_device=True, lixelgo_closed=True, battery_storage_confirmed=True, expected_physical_state_confirmed=True, timezone_name="Europe/Moscow", ) ) state = service.state() assert state["application_control_session"]["state"] == "idle" assert state["device_session"]["connectivity"] == "offline" assert state["connection_verification"]["lease_state"] == "configured-unverified" open_operation = next( operation for operation in state["operations"] if operation["action"] == "application-control.session.open" ) assert open_operation["status"] == "failed" assert open_operation["error"] == { "category": "connection", "code": "connection_lease_ble_recovery_failed", "retryable": False, "safe_to_retry": True, "side_effect_status": "none", } def test_bridge_route_mismatch_persists_read_only_recovery_before_rejecting_control( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _seed_supervised_connection( service, target_ipv4="192.168.68.50", host_path=_tunnel_host_path("192.168.68.50"), endpoint_reachable=False, endpoint_reason="connection_lease_host_route_mismatch", with_control=False, ) service._device_session_id = "known-session" # noqa: SLF001 service._compatibility_attestation = ATTESTATION.model_dump(mode="json") # noqa: SLF001 monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr(facade_module, "_control_endpoint_reachable", lambda _target: False) monkeypatch.setattr(facade_module, "_host_route_class", lambda _target: "tunnel") service._read_wifi_status_on_runtime_loop = ( # type: ignore[method-assign] # noqa: SLF001 lambda *_args, **_kwargs: _wifi_status_read("192.168.68.77") ) with pytest.raises( facade_module.ConnectionLeaseUnavailable, match="другой локальной сети", ): service.open_application_control_session( OpenApplicationControlSessionRequest( operator_present=True, owner_controlled_device=True, lixelgo_closed=True, battery_storage_confirmed=True, expected_physical_state_confirmed=True, timezone_name="Europe/Moscow", ) ) state = service.state() assert state["k1_ip"] == "192.168.68.77" assert state["semantic_topology_store"]["record"]["ipv4"] == "192.168.68.77" assert state["device_session"]["device_session_id"] != "known-session" assert state["connection_verification"]["lease_state"] == "configured-unverified" assert state["connection_verification"]["endpoint_validation"] == "host-route" assert state["connection_verification"]["host_route_class"] == "tunnel" assert state["application_control_session"]["state"] == "idle" def test_prepare_creates_provisional_device_session_and_profiled_acquisition( tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) state = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", duration_seconds=60, compatibility_attestation=ATTESTATION, ) ) assert runtime.start_calls == [] assert state["device_ref"]["identity_stability"] == "provisional" 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 def test_project_name_is_normalized_and_control_characters_are_rejected() -> None: request = _prepare_request( project_name=" K1 Lab ", host="192.168.1.20", compatibility_attestation=ATTESTATION, ) assert request.project_name == "K1 Lab" for invalid in (" ", "line\nbreak", "\ud800", "x" * 97): with pytest.raises(ValidationError): _prepare_request( project_name=invalid, host="192.168.1.20", compatibility_attestation=ATTESTATION, ) def test_acquisition_is_unbounded_by_default_and_accepts_ten_hour_hint() -> None: unbounded = _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ten_hours = _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", duration_seconds=10 * 60 * 60, compatibility_attestation=ATTESTATION, ) assert unbounded.duration_seconds is None assert ten_hours.duration_seconds == 36_000 def test_connection_modes_require_their_exact_topology_attestation() -> None: with pytest.raises(ValidationError, match="idempotency_key"): ConnectRequest( device_id="synthetic-device", ssid="synthetic-network", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, ) assert ( _connect_request( device_id="synthetic-device", connection_mode="quick-connect", compatibility_attestation=QUICK_CONNECT_ATTESTATION, ).connection_mode == "quick-connect" ) assert ( _connect_request( device_id="synthetic-device", ssid="synthetic-network", password=SecretStr(PRIMARY_TEST_CREDENTIAL), connection_mode="direct-connect", compatibility_attestation=DIRECT_CONNECT_ATTESTATION, ).connection_mode == "direct-connect" ) bridge = _connect_request( device_id="synthetic-device", ssid="synthetic-network", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, ) assert bridge.allow_host_wifi_switch is False assert ( _connect_request( device_id="synthetic-device", ssid="synthetic-network", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, allow_host_wifi_switch=True, ).allow_host_wifi_switch is True ) with pytest.raises(ValidationError, match="valid boolean"): _connect_request( device_id="synthetic-device", ssid="synthetic-network", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, allow_host_wifi_switch="yes", ) with pytest.raises(ValidationError, match="only for Bridge"): _connect_request( device_id="synthetic-device", connection_mode="quick-connect", compatibility_attestation=QUICK_CONNECT_ATTESTATION, allow_host_wifi_switch=True, ) with pytest.raises(ValidationError): _connect_request( device_id="synthetic-device", connection_mode="quick-connect", compatibility_attestation=ATTESTATION, ) with pytest.raises(ValidationError, match="host Wi-Fi profile"): _connect_request( device_id="synthetic-device", ssid="synthetic-network", password=SecretStr(PRIMARY_TEST_CREDENTIAL), connection_mode="quick-connect", compatibility_attestation=QUICK_CONNECT_ATTESTATION, ) with pytest.raises(ValidationError, match="32 UTF-8 bytes"): _connect_request( device_id="synthetic-device", ssid="🛰️" * 9, password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, ) with pytest.raises(ValidationError, match="64 UTF-8 bytes"): _connect_request( device_id="synthetic-device", ssid="synthetic-network", password=SecretStr("🔒" * 17), compatibility_attestation=ATTESTATION, ) def test_only_physically_accepted_mount_and_gnss_values_are_admitted() -> None: with pytest.raises(ValidationError): _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", mount_type="uav", # type: ignore[arg-type] compatibility_attestation=ATTESTATION, ) with pytest.raises(ValidationError): _prepare_request( 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( tmp_path: Path, ) -> None: loader = FakeApplicationAuthorityLoader() service = XgridsK1CompatibilityService( tmp_path, application_authority_loader=loader, ) runtime = FakeVisualizationRuntime() service.runtime = runtime # type: ignore[assignment] service._selected_device_id = "test-ble-transport" # noqa: SLF001 service._k1_ip = "192.168.1.20" # noqa: SLF001 service._compatibility_attestation = { # noqa: SLF001 "firmware_version": "3.0.2", "topology": "direct-lan", "verification": "live-device-info", "basis": "selected-profile-live-device-info-required", "observed_at": "2026-07-18T00:00:00Z", } state = service.arm_application_control_shadow( ShadowApplicationControlArmRequest( operator_confirmed=True, lease_seconds=60.0, timezone_name="Europe/Moscow", ) ) execution = state["application_control_execution"] assert loader.calls == 1 assert execution["state"] == "armed-shadow-only" assert execution["lease"]["authority_cached"] is True assert execution["can_emit_requests"] is False assert execution["live_transport_installed"] is False assert execution["publisher"]["vendor_writes_enabled"] is False assert execution["publisher"]["transport_calls"] == 0 assert PRIVATE_APPLICATION_AUTHORITY not in str(state) disarmed = service.disarm_application_control_shadow() assert disarmed["application_control_execution"]["state"] == "disarmed" assert disarmed["application_control_execution"]["lease"] is None def test_shadow_arm_requires_idle_connected_profile_selected_device_before_keychain_read( tmp_path: Path, ) -> None: loader = FakeApplicationAuthorityLoader() service = XgridsK1CompatibilityService( tmp_path, application_authority_loader=loader, ) service.runtime = FakeVisualizationRuntime() # type: ignore[assignment] with pytest.raises(RuntimeError, match="подключите K1"): service.arm_application_control_shadow( ShadowApplicationControlArmRequest( operator_confirmed=True, timezone_name="Europe/Moscow", ) ) assert loader.calls == 0 def test_shadow_arm_contract_requires_explicit_operator_confirmation() -> None: with pytest.raises(ValidationError): ShadowApplicationControlArmRequest.model_validate({"timezone_name": "Europe/Moscow"}) def test_prepare_acquisition_revokes_existing_shadow_authority_lease(tmp_path: Path) -> None: loader = FakeApplicationAuthorityLoader() service = XgridsK1CompatibilityService( tmp_path, application_authority_loader=loader, ) service.runtime = FakeVisualizationRuntime() # type: ignore[assignment] service._selected_device_id = "test-ble-transport" # noqa: SLF001 service._k1_ip = "192.168.1.20" # noqa: SLF001 service._compatibility_attestation = ATTESTATION.model_dump(mode="json") # noqa: SLF001 service.arm_application_control_shadow( ShadowApplicationControlArmRequest( operator_confirmed=True, timezone_name="Europe/Moscow", ) ) prepared = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", duration_seconds=60, compatibility_attestation=ATTESTATION, ) ) assert prepared["application_control_execution"]["state"] == "disarmed" assert prepared["application_control_execution"]["lease"] is None def test_operator_manual_start_is_confirmed_only_by_real_point_data(tmp_path: Path) -> None: service, runtime = service_with_fake_runtime(tmp_path) prepared = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", duration_seconds=60, compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] starting = service.start_acquisition(_start_request(acquisition_id=acquisition_id)) assert starting["acquisition"]["state"] == "starting" assert starting["last_operation"]["status"] == "running" runtime.mark_ready() awaiting = service.state() assert awaiting["acquisition"]["state"] == "awaiting_external_start" assert awaiting["last_operation"]["status"] == "operator_action_required" assert len(runtime.start_calls) == 1 assert runtime.start_calls[0][3] == PROJECT_NAME runtime.pcl_frames = 1 acquiring = service.state() assert acquiring["acquisition"]["state"] == "acquiring" assert acquiring["last_operation"]["status"] == "succeeded" assert acquiring["last_operation"]["result"]["confirmation"] == "point-frame" @pytest.mark.parametrize("proof_first", [False, True]) def test_plugin_commanded_acquisition_keeps_start_and_stop_as_explicit_actions( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, proof_first: bool, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) control = FakeInteractiveControlSession() service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 binding = _seed_supervised_connection(service) service._compatibility_attestation = ATTESTATION.model_dump(mode="json") # noqa: SLF001 prepared = service.prepare_acquisition( _prepare_request( project_name="TEST001", host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] assert prepared["acquisition"]["control_mode"] == "plugin-commanded" assert control.state == "project-ready" assert runtime.start_calls == [] with pytest.raises(ValueError, match="подтверждения присутствия"): service.start_acquisition(_start_request(acquisition_id=acquisition_id)) assert control.start_projects == [] pre_pcl_state = service.start_acquisition( _start_request( acquisition_id=acquisition_id, physical_acceptance=PHYSICAL_ACCEPTANCE, ) ) pre_pcl_camera_streams = [ stream for stream in pre_pcl_state["sensor_catalog"]["streams"] if stream.get("semantic_channel_id") == "camera.preview.live" ] assert pre_pcl_state["camera_preview"]["active_source_id"] is None assert pre_pcl_state["camera_preview"]["delivery"] is None assert pre_pcl_state["camera_preview"]["activation_admission"]["state"] == ( "waiting-for-first-authoritative-pcl" ) assert all(stream["activation"]["selected"] is False for stream in pre_pcl_camera_streams) assert all(stream["activation"]["controllable"] is False for stream in pre_pcl_camera_streams) assert all(stream["delivery"] is None for stream in pre_pcl_camera_streams) pre_pcl_camera = service.camera_preview.snapshot() assert pre_pcl_camera["active_source_id"] is None assert pre_pcl_camera["delivery"] is None assert pre_pcl_camera["recording"]["active"] is False assert pre_pcl_camera["recording"]["producer_alive"] is False assert control.start_projects == ["TEST001"] assert control.stop_calls == 0 assert control.start_projects == ["TEST001"] start_operation_id = service._acquisition_start_operation_id # noqa: SLF001 assert isinstance(start_operation_id, str) monkeypatch.setattr( service, "_active_acquisition_checkpoint_start_operation_id", lambda **_kwargs: start_operation_id, ) physical_proof = _exact_start_physical_proof( operation_id=start_operation_id, acquisition_id=acquisition_id, binding=binding, resolved=True, ) runtime.mark_ready() if proof_first: monkeypatch.setattr( service._physical_command_coordinator, # noqa: SLF001 "snapshot", lambda: physical_proof, ) proof_without_frame = service.state() assert proof_without_frame["acquisition"]["state"] == ("awaiting_external_start") assert proof_without_frame["last_operation"]["status"] == "running" else: runtime.pcl_frames = 1 frame_before_canonical_start = service.state() assert frame_before_canonical_start["acquisition"]["state"] == ("awaiting_external_start") assert frame_before_canonical_start["last_operation"]["status"] == "running" monkeypatch.setattr( service._physical_command_coordinator, # noqa: SLF001 "snapshot", lambda: physical_proof, ) runtime.pcl_frames = 1 acquiring = service.state() assert acquiring["acquisition"]["state"] == "acquiring" assert acquiring["last_operation"]["status"] == "succeeded" assert acquiring["last_operation"]["stage_code"] == ("canonical-start-and-first-point-frame") assert acquiring["last_operation"]["result"]["confirmation"] == ( "canonical-start-and-point-frame" ) stopping = service.stop_acquisition( _stop_request( acquisition_id=acquisition_id, mode="graceful", physical_acceptance=PHYSICAL_ACCEPTANCE, ) ) assert control.stop_calls == 1 assert stopping["acquisition"]["state"] == "awaiting_external_stop" assert stopping["last_operation"]["status"] == "running" control.state = "completed" # This legacy mapping fixture does not let the fake request_stop replace # the START projection with a typed durable STOP head. Bypass only its # terminal checkpoint seam; dedicated integration tests cover real v5 # STOP proof -> checkpoint CEASED ordering. monkeypatch.setattr( service, "_cease_active_acquisition_checkpoint_from_physical_head", lambda **_kwargs: True, ) # The production worker has also resolved the durable STOP ledger before # publishing `completed`; this mapping-only fake still returns the old # START document. Preserve this test's pre-checkpoint intent by omitting # that stale mapping at the reducer boundary. original_reconcile_acquisition = service._reconcile_acquisition # noqa: SLF001 def reconcile_legacy_completed( runtime_snapshot: Mapping[str, Any], camera_snapshot: Mapping[str, Any], control_snapshot: Mapping[str, Any], **kwargs: Any, ) -> None: kwargs["physical_command_proof"] = None original_reconcile_acquisition( runtime_snapshot, camera_snapshot, control_snapshot, **kwargs, ) monkeypatch.setattr(service, "_reconcile_acquisition", reconcile_legacy_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 assert completed["live_perception_shadow"]["active"] is False assert completed["message"] == ( "Приём и запись завершены. K1 остановлен и готов к новому запуску." ) def _activate_real_checkpoint_for_prepared_stop_fixture( service: XgridsK1CompatibilityService, *, project_name: str, ) -> None: """Back the specialized retained-receiver fixture with the real v5 CAS.""" store = service._active_acquisition_checkpoint # noqa: SLF001 acquisition = service._acquisition # noqa: SLF001 out_dir = service._acquisition_out_dir # noqa: SLF001 record = service._physical_command_ledger.snapshot().record # noqa: SLF001 assert store is not None assert acquisition is not None assert out_dir is not None assert record is not None and record.last_status is not None binding = ActiveAcquisitionRecoveryTransportBinding( runtime_instance_id=service._snapshot_runtime_id, # noqa: SLF001 intent_id=record.connection.intent_id, transport_ref=record.connection.transport_ref, connection_mode=record.connection.connection_mode, target_ipv4=record.connection.target_ipv4, target_port=record.connection.target_port, host_path_epoch=record.connection.host_path_epoch, control_session_id=record.connection.control_session_id, producer_generation=record.connection.producer_generation, logical_device_id=acquisition.device_id, compatibility_profile_id=record.compatibility_profile_id, vendor_device_id_sha256=record.identity.vendor_device_id_sha256, device_serial_sha256=record.identity.device_serial_sha256, ) prepared = store.prepare( transition_id=f"test-retained-prepare:{record.operation_id}", predecessor_revision=0, acquisition_id=acquisition.acquisition_id, original_start_operation_id=record.operation_id, start_payload_sha256=record.payload_sha256, identity=ActiveAcquisitionRecoveryIdentity( logical_device_id=acquisition.device_id, vendor_device_id_sha256=record.identity.vendor_device_id_sha256, device_serial_sha256=record.identity.device_serial_sha256, ), connection=ActiveAcquisitionRecoveryConnection( transport_ref=record.connection.transport_ref, connection_mode=record.connection.connection_mode, target_ipv4=record.connection.target_ipv4, target_port=record.connection.target_port, ), compatibility_profile_id=record.compatibility_profile_id, project_name=project_name, project_name_wire_sha256=active_acquisition_project_name_sha256( project_name ), original_evidence_session_id=out_dir.name, duration_seconds=acquisition.duration_seconds, requested_streams=acquisition.requested_streams, evidence_policy=acquisition.evidence_policy, mount_type="handheld", gnss_mode="none", prepared_binding=binding, ) status_proof = service._checkpoint_status_proof( # noqa: SLF001 status=record.last_status, binding=binding, evidence_session_id=out_dir.name, ) store.activate( transition_id=f"test-retained-activate:{record.operation_id}", expected_revision=prepared.revision, expected_acquisition_id=prepared.acquisition_id, expected_start_operation_id=prepared.original_start_operation_id, status_proof=status_proof, physical_proof=service._checkpoint_physical_proof( # noqa: SLF001 record=record, binding=binding, checkpoint=prepared, ), ) def _install_real_prepared_stop_dispatch_fixture( service: XgridsK1CompatibilityService, runtime: FakeVisualizationRuntime, *, confirm_first_pcl: bool = True, ) -> SimpleNamespace: """Install one fully confirmed START and a STOP that only durably PREPAREs.""" control = FakeInteractiveControlSession() service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 binding = _seed_supervised_connection(service, transport_ref="k1-stop-dispatch-race") prepared = service.prepare_acquisition( _prepare_request( project_name="STOP_RACE", host=binding.target_ipv4, compatibility_attestation=ATTESTATION, ) ) acquisition_id = str(prepared["acquisition"]["acquisition_id"]) service.start_acquisition( _start_request( acquisition_id=acquisition_id, physical_acceptance=PHYSICAL_ACCEPTANCE, ) ) start_operation_id = service._acquisition_start_operation_id # noqa: SLF001 assert isinstance(start_operation_id, str) identity = PhysicalCommandIdentity( vendor_device_id_sha256="a" * 64, device_serial_sha256="b" * 64, ) connection = PhysicalCommandConnectionBinding( intent_id=binding.intent_id, transport_ref=binding.transport_ref, connection_mode=binding.connection_mode, target_ipv4=binding.target_ipv4, target_port=binding.target_port, host_path_epoch=binding.host_path_epoch, control_session_id="fake-control-session", producer_generation=1, ) def status(session_state: str, observed_at_utc: str) -> PhysicalCommandStatusEvidence: scanning = session_state == "scanning" return PhysicalCommandStatusEvidence( source="live-control-session", vendor_device_id_sha256=identity.vendor_device_id_sha256, device_serial_sha256=identity.device_serial_sha256, control_session_id=connection.control_session_id, host_path_epoch=connection.host_path_epoch, producer_generation=connection.producer_generation, session_state=session_state, # type: ignore[arg-type] session_state_code=302 if scanning else 300, project_bound=scanning, project_id_sha256="c" * 64 if scanning else None, init_ready=scanning, status_message_sha256=hashlib.sha256(observed_at_utc.encode()).hexdigest(), mqtt_retained=False, observed_at_utc=observed_at_utc, ) ledger = service._physical_command_ledger # noqa: SLF001 ledger.prepare( operation_id=start_operation_id, parent_operation_id=None, acquisition_id=acquisition_id, action="start", identity=identity, connection=connection, compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, payload_sha256="1" * 64, baseline_status=status("ready", "2026-08-12T08:00:00.000Z"), ) ledger.mark_dispatching(start_operation_id) ledger.mark_observing(start_operation_id, publish_call_returned=True, packet_id=71) ledger.mark_qos2_completed(start_operation_id, packet_id=71) ledger.record_application_response( start_operation_id, PhysicalCommandApplicationResponse( operation_id=start_operation_id, action="start", control_session_id=connection.control_session_id, host_path_epoch=connection.host_path_epoch, producer_generation=connection.producer_generation, result_code=PHYSICAL_COMMAND_APPLICATION_SUCCESS_CODE, success=True, payload_sha256="2" * 64, observed_at_utc="2026-08-12T08:00:01.000Z", ), ) ledger.record_status_observation( start_operation_id, status("scanning", "2026-08-12T08:00:02.000Z"), ) ledger.resolve(start_operation_id, resolution="start-active-observed") coordinator = service._physical_command_coordinator # noqa: SLF001 coordinator.application_response( ApplicationMqttResponseEvidence( operation_key="bootstrap:stop-race:DeviceInfoRequest", response_topic="lixel/application/response/device_info", payload_sha256="3" * 64, modeling_action=None, result_code=None, success=None, observed_at_utc="2026-08-12T08:00:03.000Z", ) ) coordinator.bind_control_session( PhysicalCommandRuntimeBinding( vendor_device_id_sha256=identity.vendor_device_id_sha256, device_serial_sha256=identity.device_serial_sha256, compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, intent_id=connection.intent_id, transport_ref=connection.transport_ref, connection_mode=connection.connection_mode, target_ipv4=connection.target_ipv4, target_port=connection.target_port, host_path_epoch=connection.host_path_epoch, control_session_id=connection.control_session_id, producer_generation=connection.producer_generation, ) ) coordinator.device_status( ApplicationMqttDeviceStatusEvidence( vendor_device_id_sha256=identity.vendor_device_id_sha256, device_serial_sha256=identity.device_serial_sha256, session_state="scanning", session_state_code=MODELING_STATE_BASE + 302, project_bound=True, project_id_sha256="c" * 64, init_ready=True, status_message_sha256="4" * 64, mqtt_retained=False, observed_at_utc="2026-08-12T08:00:04.000Z", ) ) _activate_real_checkpoint_for_prepared_stop_fixture( service, project_name="STOP_RACE", ) runtime.mark_ready() runtime.pcl_frames = 1 if confirm_first_pcl else 0 assert service.state()["acquisition"]["state"] == ( "acquiring" if confirm_first_pcl else "awaiting_external_start" ) payload = b"exact-stop-dispatch-race" envelope = OneShotPublishEnvelope( operation_key="modeling:stop", topic="lixel/application/request/modeling", payload=payload, payload_sha256=hashlib.sha256(payload).hexdigest(), payload_bytes=len(payload), qos=2, retain=False, ) original_request_stop = control.request_stop prepare_calls: list[str] = [] def request_stop_after_durable_prepare(**kwargs: object) -> dict[str, object]: command_context = kwargs["command_context"] coordinator.prepare(command_context, action="stop", envelope=envelope) # type: ignore[arg-type] prepare_calls.append(str(command_context.operation_id)) # type: ignore[attr-defined] result = original_request_stop(**kwargs) # type: ignore[arg-type] control.state = "stop-requested" return result control.request_stop = request_stop_after_durable_prepare # type: ignore[method-assign] stop_operation_id = "op-00000000-0000-4000-8000-000000001401" request = _stop_request( acquisition_id=acquisition_id, operation_id=stop_operation_id, idempotency_key="prepared-stop-dispatch-race", mode="graceful", physical_acceptance=PHYSICAL_ACCEPTANCE, ) return SimpleNamespace( service=service, runtime=runtime, control=control, binding=binding, coordinator=coordinator, ledger=ledger, identity=identity, connection=connection, status=status, envelope=envelope, request=request, start_operation_id=start_operation_id, stop_operation_id=stop_operation_id, prepare_calls=prepare_calls, ) def _observe_stop_race_route_loss(service: XgridsK1CompatibilityService) -> None: service._connection_supervisor.observe_host_path( # noqa: SLF001 HostPathProbeResult( available=False, fingerprint=None, interface=None, source_ipv4=None, route_class="unavailable", reason_code="router-link-lost", ) ) def _settle_real_prepared_stop_before_publish( fixture: SimpleNamespace, ) -> facade_module._PreparedStopRecoveryOwner: """Drive the real S0 row to truthful NONE while retaining its receiver.""" fixture.control.state = "failed" fixture.control.state_revision += 1 fixture.control.failure = { "reason_code": "application-connection-binding-lost", "modeling_command_attempted": False, "safe_to_retry": False, } fixture.service.state() owner = fixture.service._prepared_stop_recovery_owner # noqa: SLF001 assert isinstance(owner, facade_module._PreparedStopRecoveryOwner) operation = fixture.service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert operation.stage_code == "physical-stop-classified-not-dispatched" assert operation.error is not None assert operation.error["side_effect_status"] == "none" return owner def _classify_real_prepared_stop( fixture: SimpleNamespace, owner: facade_module._PreparedStopRecoveryOwner, *, session_state: str, reconciliation_id: str, ) -> dict[str, object]: """Install a fresh inspection binding and classify S0 with real coordinator audit.""" scanning = session_state == "scanning" runtime_binding = PhysicalCommandRuntimeBinding( vendor_device_id_sha256="a" * 64, device_serial_sha256="b" * 64, compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, intent_id=fixture.binding.intent_id, transport_ref=fixture.binding.transport_ref, connection_mode=fixture.binding.connection_mode, target_ipv4=fixture.binding.target_ipv4, target_port=fixture.binding.target_port, host_path_epoch=fixture.binding.host_path_epoch + 1, control_session_id=f"fresh-{reconciliation_id}", producer_generation=2, ) fixture.coordinator.prepare_read_only_bootstrap() fixture.coordinator.application_response( ApplicationMqttResponseEvidence( operation_key=f"bootstrap:{reconciliation_id}:DeviceInfoRequest", response_topic="lixel/application/response/device_info", payload_sha256="f" * 64, modeling_action=None, result_code=None, success=None, observed_at_utc="2026-08-12T08:00:59.000Z", ) ) fixture.coordinator.bind_control_session(runtime_binding) fixture.coordinator.device_status( ApplicationMqttDeviceStatusEvidence( vendor_device_id_sha256=runtime_binding.vendor_device_id_sha256, device_serial_sha256=runtime_binding.device_serial_sha256, session_state=session_state, # type: ignore[arg-type] session_state_code=MODELING_STATE_BASE + (302 if scanning else 300), project_bound=scanning, project_id_sha256="c" * 64 if scanning else None, init_ready=scanning, status_message_sha256="e" * 64, mqtt_retained=False, observed_at_utc="2026-08-12T08:01:00.000Z", ) ) return dict( fixture.service._classify_retained_prepared_stop_owned( # noqa: SLF001 owner=owner, reconciliation_id=reconciliation_id, reconcile=lambda: fixture.coordinator.reconcile_unresolved( reconciliation_id=reconciliation_id, ), ) ) def _resolve_real_stop_ready(fixture: SimpleNamespace) -> None: """Advance the fixture's exact S0 to canonical durable READY without polling.""" fixture.ledger.mark_dispatching(fixture.stop_operation_id) fixture.ledger.mark_observing( fixture.stop_operation_id, publish_call_returned=True, packet_id=72, ) fixture.ledger.mark_qos2_completed(fixture.stop_operation_id, packet_id=72) fixture.ledger.record_application_response( fixture.stop_operation_id, PhysicalCommandApplicationResponse( operation_id=fixture.stop_operation_id, action="stop", control_session_id=fixture.connection.control_session_id, host_path_epoch=fixture.connection.host_path_epoch, producer_generation=fixture.connection.producer_generation, result_code=PHYSICAL_COMMAND_APPLICATION_SUCCESS_CODE, success=True, payload_sha256="5" * 64, observed_at_utc="2026-08-12T08:00:05.000Z", ), ) fixture.ledger.record_status_observation( fixture.stop_operation_id, fixture.status("ready", "2026-08-12T08:00:06.000Z"), ) fixture.ledger.resolve( fixture.stop_operation_id, resolution="stop-standby-observed", ) def test_prepared_stop_and_dispatch_gate_fence_route_loss_without_duplicate_publish( tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture(service, runtime) stopping = service.stop_acquisition(fixture.request) prepared_record = fixture.ledger.snapshot().record assert prepared_record is not None assert prepared_record.operation_id == fixture.stop_operation_id assert prepared_record.stage == "prepared" assert service._prepared_stop_dispatch_lineage_is_current() is True # noqa: SLF001 assert stopping["selected_device_id"] == fixture.binding.transport_ref # A route-negative state reduction lands after durable PREPARE but before # the asynchronous worker owns the command-dispatch gate. It must not # tear down the only topology that can execute this already accepted STOP. for _ in range(3): _observe_stop_race_route_loss(service) state = service.state() assert state["selected_device_id"] == fixture.binding.transport_ref assert fixture.prepare_calls == [fixture.stop_operation_id] repeated = service.stop_acquisition(fixture.request) assert repeated["selected_device_id"] == fixture.binding.transport_ref assert fixture.prepare_calls == [fixture.stop_operation_id] dispatch = ApplicationMqttPublishEvidence( operation_key="modeling:stop", topic=fixture.envelope.topic, payload_sha256=fixture.envelope.payload_sha256, qos=2, retain=False, packet_id=None, ) published: list[str] = [] assert service._k1_command_dispatch_gate.acquire(blocking=False) # noqa: SLF001 try: fixture.coordinator.publish_dispatching(dispatch) dispatching = fixture.ledger.snapshot().record assert dispatching is not None and dispatching.stage == "dispatching" # This is the exact mark_dispatching -> client.publish interleaving. # The reducer sees confirmed loss but cannot cross the transport gate. mid_dispatch = service.state() assert mid_dispatch["selected_device_id"] == fixture.binding.transport_ref published.append(fixture.envelope.payload_sha256) finally: service._k1_command_dispatch_gate.release() # noqa: SLF001 assert published == [fixture.envelope.payload_sha256] assert fixture.prepare_calls == [fixture.stop_operation_id] # Once the dispatch fence is released, the same genuine route loss uses # the normal fail-closed reducer; PREPARED lineage no longer applies. retired = service.state() assert retired["selected_device_id"] is None assert retired["device_session"] is None @pytest.mark.parametrize("terminal_reason", ["control-failed", "deadline"]) def test_prepared_stop_barrier_expires_and_real_loss_retires_fail_closed( tmp_path: Path, terminal_reason: str, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture(service, runtime) service.stop_acquisition(fixture.request) if terminal_reason == "control-failed": fixture.control.state = "failed" fixture.control.state_revision += 1 fixture.control.failure = { "reason_code": "mqtt_network_loop_failed", "modeling_command_attempted": False, "safe_to_retry": False, } else: operation = service._operations.get(fixture.stop_operation_id) # noqa: SLF001 operation.deadline_at = datetime.now(UTC) - timedelta(seconds=1) for _ in range(3): _observe_stop_race_route_loss(service) assert service._prepared_stop_dispatch_lineage_is_current() is False # noqa: SLF001 retired = service.state() if terminal_reason == "control-failed": # A terminal pre-publish worker is no longer merely an expired dispatch # barrier: it is exact NONE proof and retains the receiver/topology for # the automatic read-only SCANNING/READY classification path. assert retired["selected_device_id"] == fixture.binding.transport_ref operation = service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert operation.stage_code == "physical-stop-classified-not-dispatched" assert operation.error is not None assert operation.error["side_effect_status"] == "none" assert service._prepared_stop_recovery_owner is not None # noqa: SLF001 else: # A hung nonterminal worker whose bounded operation deadline elapsed has # no terminal NONE proof. Genuine route loss therefore retires normally. assert retired["selected_device_id"] is None assert fixture.ledger.snapshot().record is not None assert fixture.ledger.snapshot().record.stage == "prepared" # type: ignore[union-attr] assert fixture.prepare_calls == [fixture.stop_operation_id] def test_prepared_stop_pending_worker_outranks_runtime_error_then_settles_none( tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture(service, runtime) service.stop_acquisition(fixture.request) runtime.phase = "error" # Local producer symptoms cannot terminalize an accepted STOP while the # exact durable command is still PREPARED and its worker is nonterminal. pending = service.state() operation = service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert pending["acquisition"]["state"] == "awaiting_external_stop" assert operation.status == "running" assert operation.error is None assert fixture.ledger.snapshot().record is not None assert fixture.ledger.snapshot().record.stage == "prepared" # type: ignore[union-attr] # The same row plus a terminal pre-publish worker is exact NONE proof. fixture.control.state = "failed" fixture.control.state_revision += 1 fixture.control.failure = { "reason_code": "application-connection-binding-lost", "modeling_command_attempted": False, "safe_to_retry": False, } settled = service.state() operation = service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert operation.status == "failed" assert operation.stage_code == "physical-stop-classified-not-dispatched" assert operation.error is not None assert operation.error["side_effect_status"] == "none" assert operation.error["physical_command_sent"] is False assert settled["selected_device_id"] is None def test_expired_stop_dispatch_admission_resolves_durable_no_dispatch( tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture(service, runtime) service.stop_acquisition(fixture.request) assert len(fixture.control.stop_dispatch_deadlines) == 1 deadline_reached = fixture.control.stop_dispatch_deadlines[0] assert deadline_reached is not None operation = service._operations.get(fixture.stop_operation_id) # noqa: SLF001 operation.deadline_at = datetime.now(UTC) - timedelta(seconds=1) assert deadline_reached() is True fixture.control.state = "failed" fixture.control.state_revision += 1 fixture.control.failure = { "reason_code": "physical-command-dispatch-deadline-expired", "modeling_command_attempted": True, "stop_command_attempted": False, "stop_publish_attempts": 0, "diagnostic_evidence_unavailable": [], "safe_to_retry": True, } fixture.control.outcome_unknown = False fixture.control.transport_publish_attempts = 8 settled = service.state() record = fixture.ledger.snapshot().record assert record is not None assert record.stage == "resolved" assert record.resolution == "not-dispatched" assert record.resolved_unclassified_stop_recovery_required is True assert fixture.coordinator.snapshot()["active_operation_id"] is None operation = service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert operation.stage_code == "physical-stop-classified-not-dispatched" assert operation.error is not None assert operation.error["side_effect_status"] == "none" assert operation.error["physical_command_sent"] is False assert operation.error["automatic_replay_allowed"] is False assert service.camera_preview.snapshot()["recording"]["source_end_expected"] is False assert service._prepared_stop_recovery_owner is not None # noqa: SLF001 assert settled["physical_command"]["record"]["resolution"] == "not-dispatched" def test_abort_rejects_exact_unresolved_stop_before_any_local_cleanup( tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture(service, runtime) service.stop_acquisition(fixture.request) before_operations = tuple(service._operations.snapshot()) # noqa: SLF001 with pytest.raises( facade_module.LocalAcquisitionLifecycleError, match="исход PREPARED/DISPATCHING STOP", ) as raised: service.abort_acquisition( _abort_request(acquisition_id=fixture.request.acquisition_id) ) assert raised.value.reason_code == "acquisition-abort-physical-stop-unresolved" assert tuple(service._operations.snapshot()) == before_operations # noqa: SLF001 operation = service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert operation.status == "running" assert operation.error is None record = fixture.ledger.snapshot().record assert record is not None and record.stage == "prepared" assert service._acquisition is not None # noqa: SLF001 assert service._acquisition.state == "awaiting_external_stop" # noqa: SLF001 assert service._acquisition_stop_operation_id == fixture.stop_operation_id # noqa: SLF001 assert runtime.stop_calls == 0 def test_capture_only_rejects_live_prepared_stop_before_operation_or_local_cleanup( tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture(service, runtime) service.stop_acquisition(fixture.request) acquisition = service._acquisition # noqa: SLF001 assert acquisition is not None before_operations = tuple(service._operations.snapshot()) # noqa: SLF001 before_acquisition = ( acquisition.state, acquisition.state_revision, acquisition.message_code, acquisition.result, ) with pytest.raises( facade_module.LocalAcquisitionLifecycleError, match="ещё владеет PREPARED STOP", ) as raised: service.stop_acquisition( _stop_request( acquisition_id=acquisition.acquisition_id, operation_id="op-00000000-0000-4000-8000-000000001450", mode="capture-only", ) ) assert raised.value.reason_code == "acquisition-stop-worker-retirement-pending" assert tuple(service._operations.snapshot()) == before_operations # noqa: SLF001 assert fixture.control.state == "stop-requested" record = fixture.ledger.snapshot().record assert record is not None and record.stage == "prepared" assert fixture.prepare_calls == [fixture.stop_operation_id] assert ( acquisition.state, acquisition.state_revision, acquisition.message_code, acquisition.result, ) == before_acquisition assert service._acquisition_stop_operation_id == fixture.stop_operation_id # noqa: SLF001 assert runtime.stop_calls == 0 def test_capture_only_defers_terminal_prepared_stop_while_dispatch_gate_is_busy( tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture(service, runtime) service.stop_acquisition(fixture.request) fixture.control.state = "failed" fixture.control.failure = { "reason_code": "application-connection-binding-lost", "modeling_command_attempted": False, "safe_to_retry": False, } before_operations = tuple(service._operations.snapshot()) # noqa: SLF001 assert service._k1_command_dispatch_gate.acquire(blocking=False) # noqa: SLF001 try: with pytest.raises( facade_module.LocalAcquisitionLifecycleError, match="publish-переходом STOP", ) as raised: service.stop_acquisition( _stop_request( acquisition_id=fixture.request.acquisition_id, operation_id="op-00000000-0000-4000-8000-000000001451", mode="capture-only", ) ) finally: service._k1_command_dispatch_gate.release() # noqa: SLF001 assert raised.value.reason_code == "acquisition-stop-dispatch-retirement-pending" assert tuple(service._operations.snapshot()) == before_operations # noqa: SLF001 record = fixture.ledger.snapshot().record assert record is not None and record.stage == "prepared" operation = service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert operation.status == "running" assert operation.error is None assert fixture.prepare_calls == [fixture.stop_operation_id] assert runtime.stop_calls == 0 def test_capture_only_settles_terminal_prepared_stop_none_before_local_cleanup( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture(service, runtime) service.stop_acquisition(fixture.request) fixture.control.state = "failed" fixture.control.failure = { "reason_code": "application-connection-binding-lost", "modeling_command_attempted": False, "safe_to_retry": False, } monkeypatch.setattr(service, "_seal_acquisition_capture_clock", lambda: None) completed = service.stop_acquisition( _stop_request( acquisition_id=fixture.request.acquisition_id, operation_id="op-00000000-0000-4000-8000-000000001452", mode="capture-only", ) ) original_stop = service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert original_stop.status == "failed" assert original_stop.stage_code == "physical-stop-classified-not-dispatched" assert original_stop.error is not None assert original_stop.error["side_effect_status"] == "none" assert original_stop.error["physical_command_sent"] is False local_stop = completed["last_operation"] assert local_stop["operation_id"] == "op-00000000-0000-4000-8000-000000001452" assert local_stop["status"] == "succeeded" assert completed["acquisition"]["state"] == "completed" assert completed["acquisition"]["result"]["device_stop"] == "not-sent" record = fixture.ledger.snapshot().record assert record is not None and record.stage == "prepared" assert fixture.prepare_calls == [fixture.stop_operation_id] assert fixture.control.stop_calls == 1 assert runtime.stop_calls == 1 def test_capture_only_cleanup_failure_preserves_s0_and_confirmed_start_truth( tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture( service, runtime, confirm_first_pcl=False, ) service.stop_acquisition(fixture.request) fixture.control.state = "failed" fixture.control.failure = { "reason_code": "application-connection-binding-lost", "modeling_command_attempted": False, "safe_to_retry": False, } runtime.stop_error = RuntimeError("synthetic capture-only cleanup timeout") with pytest.raises(RuntimeError, match="synthetic capture-only cleanup timeout"): service.stop_acquisition( _stop_request( acquisition_id=fixture.request.acquisition_id, operation_id="op-00000000-0000-4000-8000-000000001457", mode="capture-only", ) ) start = service._operations.get(fixture.start_operation_id) # noqa: SLF001 original_stop = service._operations.get(fixture.stop_operation_id) # noqa: SLF001 local_stop = service._operations.get( # noqa: SLF001 "op-00000000-0000-4000-8000-000000001457" ) assert start.status == "interrupted" assert start.stage_code == "physical-start-active-local-retirement-before-point" assert start.error is not None and start.error["side_effect_status"] == "succeeded" assert original_stop.stage_code == "physical-stop-classified-not-dispatched" assert original_stop.error is not None assert original_stop.error["side_effect_status"] == "none" assert local_stop.status == "failed" assert service._acquisition_stop_operation_id == fixture.stop_operation_id # noqa: SLF001 record = fixture.ledger.snapshot().record assert record is not None and record.stage == "prepared" assert service._acquisition_session_lease is not None # noqa: SLF001 @pytest.mark.parametrize("stage", ["dispatching", "observing"]) def test_capture_only_preserves_postpublish_stop_unknown_before_local_cleanup( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, stage: str, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture(service, runtime) service.stop_acquisition(fixture.request) dispatch = ApplicationMqttPublishEvidence( operation_key="modeling:stop", topic=fixture.envelope.topic, payload_sha256=fixture.envelope.payload_sha256, qos=2, retain=False, packet_id=None, ) fixture.coordinator.publish_dispatching(dispatch) if stage == "observing": fixture.ledger.mark_observing( fixture.stop_operation_id, publish_call_returned=False, packet_id=None, ) monkeypatch.setattr(service, "_seal_acquisition_capture_clock", lambda: None) completed = service.stop_acquisition( _stop_request( acquisition_id=fixture.request.acquisition_id, operation_id=( "op-00000000-0000-4000-8000-000000001453" if stage == "dispatching" else "op-00000000-0000-4000-8000-000000001454" ), mode="capture-only", ) ) original_stop = service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert original_stop.status == "failed" assert original_stop.stage_code == "physical-stop-outcome-unknown-local-retirement" assert original_stop.error is not None assert original_stop.error["side_effect_status"] == "unknown" assert original_stop.error["automatic_replay_allowed"] is False assert completed["last_operation"]["status"] == "succeeded" assert completed["acquisition"]["result"]["device_stop"] == ( "physical-outcome-unknown" ) record = fixture.ledger.snapshot().record assert record is not None and record.stage == stage assert fixture.prepare_calls == [fixture.stop_operation_id] assert fixture.control.stop_calls == 1 assert runtime.stop_calls == 1 @pytest.mark.parametrize("action", ["capture-only", "abort", "force", "reset", "close"]) def test_resolved_ready_preducer_dominates_destructive_action_and_pending_start( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, action: str, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture( service, runtime, confirm_first_pcl=False, ) service.stop_acquisition(fixture.request) _resolve_real_stop_ready(fixture) monkeypatch.setattr(service, "_seal_acquisition_capture_clock", lambda: None) if action == "close": monkeypatch.setattr(service.camera_preview, "close", lambda: None) monkeypatch.setattr(runtime, "close", runtime.stop) before_record = fixture.ledger.snapshot().record before_prepare_calls = list(fixture.prepare_calls) before_operation_ids = { item["operation_id"] for item in service._operations.snapshot() # noqa: SLF001 } if action == "capture-only": result = service.stop_acquisition( _stop_request( acquisition_id=fixture.request.acquisition_id, operation_id="op-00000000-0000-4000-8000-000000001455", mode="capture-only", ) ) assert result["acquisition"]["state"] == "completed" elif action == "abort": result = service.abort_acquisition( _abort_request( acquisition_id=fixture.request.acquisition_id, operation_id="op-00000000-0000-4000-8000-000000001456", ) ) assert result["acquisition"]["state"] == "completed" elif action == "force": with service._acquisition_lifecycle_gate: # noqa: SLF001 assert service._force_finish_active_acquisition_locally( # noqa: SLF001 reason_code="test-resolved-ready-dominance", require_recovery=False, ) elif action == "reset": service.select_connection_mode( DesiredConnectionModeRequest( connection_mode="quick-connect", expected_revision=service._desired_connection_mode_revision, # noqa: SLF001 reset_scenario=True, reset_id="resolved-ready-preducer-reset-0001", ) ) else: service.close() start = service._operations.get(fixture.start_operation_id) # noqa: SLF001 stop = service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert start.status == "interrupted" assert start.stage_code == "physical-start-active-but-no-point-before-standby" assert start.error is not None assert start.error["side_effect_status"] == "succeeded" assert start.error["automatic_replay_allowed"] is False assert stop.status == "succeeded" assert stop.stage_code == "device-standby-confirmed" assert service._acquisition is not None # noqa: SLF001 assert service._acquisition.result is not None # noqa: SLF001 assert service._acquisition.result["device_state"] == "ready" # noqa: SLF001 assert service._acquisition.result["device_stop"] == "protocol-confirmed" # noqa: SLF001 assert fixture.ledger.snapshot().record == before_record assert fixture.prepare_calls == before_prepare_calls assert fixture.control.stop_calls == 1 assert runtime.stop_calls == 1 after_operation_ids = { item["operation_id"] for item in service._operations.snapshot() # noqa: SLF001 } assert after_operation_ids == before_operation_ids def test_local_force_finish_fences_prepared_stop_then_settles_none_before_cleanup( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture(service, runtime) service.stop_acquisition(fixture.request) monkeypatch.setattr(service, "_seal_acquisition_capture_clock", lambda: None) with service._acquisition_lifecycle_gate: # noqa: SLF001 assert service._force_finish_active_acquisition_locally( # noqa: SLF001 reason_code="test-local-retirement", require_recovery=False, ) operation = service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert operation.status == "failed" assert operation.stage_code == "physical-stop-classified-not-dispatched" assert operation.error is not None assert operation.error["side_effect_status"] == "none" assert operation.error["physical_command_sent"] is False record = fixture.ledger.snapshot().record assert record is not None and record.stage == "prepared" assert service._acquisition is not None # noqa: SLF001 assert service._acquisition.state == "interrupted" # noqa: SLF001 assert service._acquisition.result is not None # noqa: SLF001 assert service._acquisition.result["device_stop"] == "not-sent" # noqa: SLF001 assert service._acquisition_stop_operation_id == fixture.stop_operation_id # noqa: SLF001 assert runtime.stop_calls == 1 def test_local_force_finish_preserves_confirmed_start_truth_before_first_point( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture( service, runtime, confirm_first_pcl=False, ) service.stop_acquisition(fixture.request) start_before = service._operations.get(fixture.start_operation_id) # noqa: SLF001 assert start_before.status == "running" monkeypatch.setattr(service, "_seal_acquisition_capture_clock", lambda: None) with service._acquisition_lifecycle_gate: # noqa: SLF001 assert service._force_finish_active_acquisition_locally( # noqa: SLF001 reason_code="test-local-retirement", require_recovery=False, ) start = service._operations.get(fixture.start_operation_id) # noqa: SLF001 assert start.status == "interrupted" assert start.stage_code == "physical-start-active-local-retirement-before-point" assert start.error is not None assert start.error["side_effect_status"] == "succeeded" assert start.error["automatic_replay_allowed"] is False stop = service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert stop.stage_code == "physical-stop-classified-not-dispatched" assert stop.error is not None and stop.error["side_effect_status"] == "none" def test_local_force_finish_preserves_dispatching_stop_as_outcome_unknown( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture(service, runtime) service.stop_acquisition(fixture.request) dispatch = ApplicationMqttPublishEvidence( operation_key="modeling:stop", topic=fixture.envelope.topic, payload_sha256=fixture.envelope.payload_sha256, qos=2, retain=False, packet_id=None, ) assert service._k1_command_dispatch_gate.acquire(blocking=False) # noqa: SLF001 try: fixture.coordinator.publish_dispatching(dispatch) finally: service._k1_command_dispatch_gate.release() # noqa: SLF001 monkeypatch.setattr(service, "_seal_acquisition_capture_clock", lambda: None) with service._acquisition_lifecycle_gate: # noqa: SLF001 assert service._force_finish_active_acquisition_locally( # noqa: SLF001 reason_code="test-local-retirement", require_recovery=False, ) operation = service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert operation.status == "failed" assert operation.stage_code == "physical-stop-outcome-unknown-local-retirement" assert operation.error is not None assert operation.error["side_effect_status"] == "unknown" assert operation.error["automatic_replay_allowed"] is False record = fixture.ledger.snapshot().record assert record is not None and record.stage == "dispatching" assert service._acquisition is not None # noqa: SLF001 assert service._acquisition.state == "interrupted" # noqa: SLF001 assert service._acquisition.result is not None # noqa: SLF001 assert service._acquisition.result["device_stop"] == "physical-outcome-unknown" # noqa: SLF001 assert "physical_command_sent" not in service._acquisition.result # noqa: SLF001 assert service._acquisition_stop_operation_id == fixture.stop_operation_id # noqa: SLF001 def test_local_force_finish_defers_without_mutation_while_dispatch_gate_is_owned( tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture(service, runtime) service.stop_acquisition(fixture.request) acquisition = service._acquisition # noqa: SLF001 assert acquisition is not None before_revision = acquisition.state_revision before_recovery_generation = service._active_stream_recovery_generation # noqa: SLF001 assert service._k1_command_dispatch_gate.acquire(blocking=False) # noqa: SLF001 try: with service._acquisition_lifecycle_gate, pytest.raises( # noqa: SLF001 facade_module.LocalAcquisitionLifecycleError, match="publish-переходом STOP", ) as raised: service._force_finish_active_acquisition_locally( # noqa: SLF001 reason_code="test-local-retirement", require_recovery=False, ) finally: service._k1_command_dispatch_gate.release() # noqa: SLF001 assert raised.value.reason_code == "acquisition-stop-dispatch-retirement-pending" operation = service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert operation.status == "running" assert operation.error is None record = fixture.ledger.snapshot().record assert record is not None and record.stage == "prepared" assert service._acquisition is acquisition # noqa: SLF001 assert acquisition.state == "awaiting_external_stop" assert acquisition.state_revision == before_revision assert service._acquisition_stop_operation_id == fixture.stop_operation_id # noqa: SLF001 assert ( # noqa: SLF001 service._active_stream_recovery_generation == before_recovery_generation ) assert fixture.control.state == "stop-requested" assert runtime.stop_calls == 0 def test_scenario_reset_fences_prepared_stop_before_local_cleanup_and_durable_retirement( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture(service, runtime) service.stop_acquisition(fixture.request) monkeypatch.setattr(service, "_seal_acquisition_capture_clock", lambda: None) reset = service.select_connection_mode( DesiredConnectionModeRequest( connection_mode="quick-connect", expected_revision=service.state()["desired_connection_mode_revision"], reset_scenario=True, reset_id="prepared-stop-reset-0001", ) ) operation = service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert operation.status == "failed" assert operation.stage_code == "physical-stop-classified-not-dispatched" assert operation.error is not None assert operation.error["side_effect_status"] == "none" record = fixture.ledger.snapshot().record assert record is not None assert record.operation_id == fixture.stop_operation_id assert record.stage == "resolved" assert record.resolution == "not-dispatched" assert reset["connection_scenario_reset"]["physical_disposition"] == "not-dispatched" assert reset["connection_scenario_reset"]["device_command_performed"] is False assert reset["acquisition"]["state"] == "interrupted" assert service._acquisition_stop_operation_id is None # noqa: SLF001 assert runtime.stop_calls == 1 def test_scenario_reset_dispatch_gate_defer_preserves_owner_then_exact_retry_converges( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture(service, runtime) service.stop_acquisition(fixture.request) monkeypatch.setattr(service, "_seal_acquisition_capture_clock", lambda: None) request = DesiredConnectionModeRequest( connection_mode="quick-connect", expected_revision=service.state()["desired_connection_mode_revision"], reset_scenario=True, reset_id="prepared-stop-reset-retry-0001", ) assert service._k1_command_dispatch_gate.acquire(blocking=False) # noqa: SLF001 try: with pytest.raises( facade_module.LocalAcquisitionLifecycleError, match="publish-переходом STOP", ) as raised: service.select_connection_mode(request) finally: service._k1_command_dispatch_gate.release() # noqa: SLF001 assert raised.value.reason_code == "acquisition-stop-dispatch-retirement-pending" operation = service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert operation.status == "running" assert operation.error is None record = fixture.ledger.snapshot().record assert record is not None and record.stage == "prepared" assert service._acquisition is not None # noqa: SLF001 assert service._acquisition.state == "awaiting_external_stop" # noqa: SLF001 assert service._acquisition_stop_operation_id == fixture.stop_operation_id # noqa: SLF001 assert runtime.stop_calls == 0 retried = service.select_connection_mode(request) operation = service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert operation.stage_code == "physical-stop-classified-not-dispatched" assert operation.error is not None assert operation.error["side_effect_status"] == "none" record = fixture.ledger.snapshot().record assert record is not None and record.resolution == "not-dispatched" assert retried["connection_scenario_reset"]["physical_disposition"] == "not-dispatched" def test_scenario_reset_retires_dispatching_stop_as_outcome_unknown_never_cancelled( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture(service, runtime) service.stop_acquisition(fixture.request) dispatch = ApplicationMqttPublishEvidence( operation_key="modeling:stop", topic=fixture.envelope.topic, payload_sha256=fixture.envelope.payload_sha256, qos=2, retain=False, packet_id=None, ) assert service._k1_command_dispatch_gate.acquire(blocking=False) # noqa: SLF001 try: fixture.coordinator.publish_dispatching(dispatch) finally: service._k1_command_dispatch_gate.release() # noqa: SLF001 monkeypatch.setattr(service, "_seal_acquisition_capture_clock", lambda: None) reset = service.select_connection_mode( DesiredConnectionModeRequest( connection_mode="quick-connect", expected_revision=service.state()["desired_connection_mode_revision"], reset_scenario=True, reset_id="dispatching-stop-reset-0001", ) ) operation = service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert operation.status == "failed" assert operation.stage_code == "physical-stop-outcome-unknown-local-retirement" assert operation.error is not None assert operation.error["side_effect_status"] == "unknown" assert operation.error["automatic_replay_allowed"] is False record = fixture.ledger.snapshot().record assert record is not None assert record.stage == "resolved" assert record.resolution == "operator-retired-outcome-unknown" assert reset["connection_scenario_reset"]["physical_disposition"] == ( "operator-retired-outcome-unknown" ) assert service._acquisition_stop_operation_id is None # noqa: SLF001 @pytest.mark.parametrize( ("session_state", "expected_message", "expected_physical_state"), [ ( "scanning", "acquisition.recovery.scanning_adoption_pending", "active", ), ( "ready", "acquisition.recovery.device_standby_observed", "standby", ), ], ) def test_retained_prepared_stop_classification_reserves_local_owner_from_durable_audit( tmp_path: Path, session_state: str, expected_message: str, expected_physical_state: str, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture(service, runtime) service.stop_acquisition(fixture.request) owner = _settle_real_prepared_stop_before_publish(fixture) original_acquisition = owner.acquisition original_lease = owner.session_lease original_out_dir = owner.out_dir reconciled = _classify_real_prepared_stop( fixture, owner, session_state=session_state, reconciliation_id=f"test-{session_state}-retained", ) physical = fixture.coordinator.snapshot() assert reconciled["operation_id"] == fixture.stop_operation_id assert reconciled["stage"] == "resolved" assert reconciled["resolution"] == "not-dispatched" assert physical["reconciled_physical_state"] == expected_physical_state assert service._acquisition is original_acquisition # noqa: SLF001 assert service._acquisition_session_lease is original_lease # noqa: SLF001 assert service._acquisition_out_dir == original_out_dir # noqa: SLF001 assert service._acquisition.message_code == expected_message # noqa: SLF001 assert runtime.stop_calls == 0 assert fixture.control.stop_calls == 1 stop_operation = service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert stop_operation.stage_code == "physical-stop-classified-not-dispatched" assert stop_operation.error is not None assert stop_operation.error["side_effect_status"] == "none" @pytest.mark.parametrize("session_state", ["ready", "scanning"]) def test_resolved_unclassified_stop_compatibility_classifies_without_new_command( tmp_path: Path, session_state: str, ) -> None: """A startup-resolved legacy STOP still takes the read-only classifier.""" service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture(service, runtime) service.stop_acquisition(fixture.request) _settle_real_prepared_stop_before_publish(fixture) fixture.ledger.resolve( fixture.stop_operation_id, resolution="not-dispatched", ) fixture.coordinator = LedgerPhysicalCommandCoordinator(fixture.ledger) service._physical_command_coordinator = fixture.coordinator # noqa: SLF001 compatibility = fixture.coordinator.snapshot() compatibility_record = compatibility["record"] assert isinstance(compatibility_record, dict) compatibility_revision = compatibility_record["revision"] assert compatibility["status"] == "resolved" assert compatibility["requires_reconciliation"] is True assert compatibility["resolved_unclassified_stop_recovery_required"] is True assert compatibility["reconciliation_ready"] is False before_prepare_calls = list(fixture.prepare_calls) before_control_stop_calls = fixture.control.stop_calls reconciliation_id = f"test-resolved-unclassified-{session_state}" scanning = session_state == "scanning" runtime_binding = PhysicalCommandRuntimeBinding( vendor_device_id_sha256="a" * 64, device_serial_sha256="b" * 64, compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, intent_id=fixture.binding.intent_id, transport_ref=fixture.binding.transport_ref, connection_mode=fixture.binding.connection_mode, target_ipv4=fixture.binding.target_ipv4, target_port=fixture.binding.target_port, host_path_epoch=fixture.binding.host_path_epoch + 1, control_session_id=f"fresh-{reconciliation_id}", producer_generation=2, ) fixture.coordinator.prepare_read_only_bootstrap() fixture.coordinator.application_response( ApplicationMqttResponseEvidence( operation_key=f"bootstrap:{reconciliation_id}:DeviceInfoRequest", response_topic="lixel/application/response/device_info", payload_sha256="f" * 64, modeling_action=None, result_code=None, success=None, observed_at_utc="2026-08-12T08:10:59.000Z", ) ) fixture.coordinator.bind_control_session(runtime_binding) fixture.coordinator.device_status( ApplicationMqttDeviceStatusEvidence( vendor_device_id_sha256=runtime_binding.vendor_device_id_sha256, device_serial_sha256=runtime_binding.device_serial_sha256, session_state=session_state, # type: ignore[arg-type] session_state_code=MODELING_STATE_BASE + (302 if scanning else 300), project_bound=scanning, project_id_sha256="c" * 64 if scanning else None, init_ready=scanning, status_message_sha256="e" * 64, mqtt_retained=False, observed_at_utc="2026-08-12T08:11:00.000Z", ) ) reconciled = fixture.coordinator.reconcile_unresolved( reconciliation_id=reconciliation_id, ) latest = reconciled["reconciliations"][-1] original_attempt = latest["original_attempt"] assert reconciled["revision"] == compatibility_revision + 1 assert reconciled["operation_id"] == fixture.stop_operation_id assert reconciled["stage"] == "resolved" assert reconciled["resolution"] == "not-dispatched" assert latest["kind"] == "prepared-stop-classification" assert latest["resolution"] == ( "physical-active-observed" if session_state == "scanning" else "physical-standby-observed" ) assert original_attempt["stage"] == "resolved" assert original_attempt["resolution"] == "not-dispatched" assert original_attempt["publish_call_returned"] is None assert original_attempt["packet_id"] is None assert original_attempt["qos2_completed"] is False physical = fixture.coordinator.snapshot() matcher = ( service._matching_classified_prepared_stop_active # noqa: SLF001 if scanning else service._matching_classified_prepared_stop_standby # noqa: SLF001 ) assert matcher( physical, acquisition_id=reconciled["acquisition_id"], stop_operation_id=fixture.stop_operation_id, start_operation_id=fixture.start_operation_id, verified_control=latest["verified_binding"]["connection"], ) assert fixture.prepare_calls == before_prepare_calls assert fixture.control.stop_calls == before_control_stop_calls assert runtime.stop_calls == 0 def test_retained_prepared_stop_commit_and_local_reservation_are_one_lifecycle_transaction( tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture(service, runtime) service.stop_acquisition(fixture.request) owner = _settle_real_prepared_stop_before_publish(fixture) fixture.coordinator.prepare_read_only_bootstrap() fixture.coordinator.application_response( ApplicationMqttResponseEvidence( operation_key="bootstrap:test-atomic:DeviceInfoRequest", response_topic="lixel/application/response/device_info", payload_sha256="f" * 64, modeling_action=None, result_code=None, success=None, observed_at_utc="2026-08-12T08:01:59.000Z", ) ) binding = PhysicalCommandRuntimeBinding( vendor_device_id_sha256="a" * 64, device_serial_sha256="b" * 64, compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, intent_id=fixture.binding.intent_id, transport_ref=fixture.binding.transport_ref, connection_mode=fixture.binding.connection_mode, target_ipv4=fixture.binding.target_ipv4, target_port=fixture.binding.target_port, host_path_epoch=fixture.binding.host_path_epoch + 1, control_session_id="fresh-atomic-classification", producer_generation=2, ) fixture.coordinator.bind_control_session(binding) fixture.coordinator.device_status( ApplicationMqttDeviceStatusEvidence( vendor_device_id_sha256="a" * 64, device_serial_sha256="b" * 64, session_state="scanning", session_state_code=MODELING_STATE_BASE + 302, project_bound=True, project_id_sha256="c" * 64, init_ready=True, status_message_sha256="e" * 64, mqtt_retained=False, observed_at_utc="2026-08-12T08:02:00.000Z", ) ) committed = threading.Event() allow_reservation = threading.Event() state_finished = threading.Event() errors: list[BaseException] = [] def reconcile_after_pause() -> dict[str, object]: record = fixture.coordinator.reconcile_unresolved( reconciliation_id="test-atomic-classification", ) committed.set() assert allow_reservation.wait(timeout=5) return record def classify() -> None: try: service._classify_retained_prepared_stop_owned( # noqa: SLF001 owner=owner, reconciliation_id="test-atomic-classification", reconcile=reconcile_after_pause, ) except BaseException as exc: # pragma: no cover - assertion surface errors.append(exc) def poll_state() -> None: try: service.state() except BaseException as exc: # pragma: no cover - assertion surface errors.append(exc) finally: state_finished.set() classify_thread = threading.Thread(target=classify) classify_thread.start() assert committed.wait(timeout=5) poll_thread = threading.Thread(target=poll_state) poll_thread.start() assert state_finished.wait(timeout=0.05) is False allow_reservation.set() classify_thread.join(timeout=5) poll_thread.join(timeout=5) assert not errors assert state_finished.is_set() assert service._acquisition is owner.acquisition # noqa: SLF001 assert service._acquisition_session_lease is owner.session_lease # noqa: SLF001 assert service._acquisition.message_code == ( # noqa: SLF001 "acquisition.recovery.scanning_adoption_pending" ) def test_exact_old_stop_retry_is_idempotent_during_scanning_adoption_pending( tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture(service, runtime) service.stop_acquisition(fixture.request) owner = _settle_real_prepared_stop_before_publish(fixture) _classify_real_prepared_stop( fixture, owner, session_state="scanning", reconciliation_id="test-old-s0-retry-pending", ) before_record = fixture.ledger.snapshot().record before_operations = tuple(service._operations.snapshot()) # noqa: SLF001 before_control_calls = fixture.control.stop_calls before_prepare_calls = list(fixture.prepare_calls) repeated = service.stop_acquisition(fixture.request) assert repeated["acquisition"]["message_code"] == ( "acquisition.recovery.scanning_adoption_pending" ) assert fixture.ledger.snapshot().record == before_record assert tuple(service._operations.snapshot()) == before_operations # noqa: SLF001 assert fixture.control.stop_calls == before_control_calls assert fixture.prepare_calls == before_prepare_calls assert service._prepared_stop_recovery_owner is owner # noqa: SLF001 assert runtime.stop_calls == 0 @pytest.mark.parametrize( "action", ["abort", "capture-only", "force", "reset", "close"], ) def test_ready_local_projection_pending_rejects_destructive_action_without_mutation( tmp_path: Path, action: str, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture(service, runtime) service.stop_acquisition(fixture.request) owner = _settle_real_prepared_stop_before_publish(fixture) _classify_real_prepared_stop( fixture, owner, session_state="ready", reconciliation_id=f"test-ready-pending-{action}", ) acquisition = service._acquisition # noqa: SLF001 assert acquisition is owner.acquisition before_record = fixture.ledger.snapshot().record before_operations = tuple(service._operations.snapshot()) # noqa: SLF001 before_state = ( acquisition.state, acquisition.state_revision, acquisition.message_code, acquisition.result, ) before_stop_pointer = service._acquisition_stop_operation_id # noqa: SLF001 before_start_pointer = service._acquisition_start_operation_id # noqa: SLF001 before_control_calls = fixture.control.stop_calls before_prepare_calls = list(fixture.prepare_calls) with pytest.raises(facade_module.LocalAcquisitionLifecycleError) as raised: if action == "abort": service.abort_acquisition( _abort_request(acquisition_id=acquisition.acquisition_id) ) elif action == "capture-only": service.stop_acquisition( _stop_request( acquisition_id=acquisition.acquisition_id, operation_id=f"op-ready-pending-capture-{action}", mode="capture-only", ) ) elif action == "force": service.force_finish_acquisition_locally( _force_finish_request( acquisition_id=acquisition.acquisition_id, expected_state_revision=acquisition.state_revision, expected_recovery_generation=( service._active_stream_recovery_generation # noqa: SLF001 ), ) ) elif action == "reset": service.select_connection_mode( DesiredConnectionModeRequest( connection_mode="quick-connect", expected_revision=service._desired_connection_mode_revision, # noqa: SLF001 reset_scenario=True, reset_id="ready-pending-reset-0001", ) ) else: service.close() assert raised.value.reason_code == "acquisition-prepared-stop-adoption-pending" assert fixture.ledger.snapshot().record == before_record assert tuple(service._operations.snapshot()) == before_operations # noqa: SLF001 assert ( acquisition.state, acquisition.state_revision, acquisition.message_code, acquisition.result, ) == before_state assert service._acquisition_stop_operation_id == before_stop_pointer # noqa: SLF001 assert service._acquisition_start_operation_id == before_start_pointer # noqa: SLF001 assert service._prepared_stop_recovery_owner is owner # noqa: SLF001 assert fixture.control.stop_calls == before_control_calls assert fixture.prepare_calls == before_prepare_calls assert runtime.stop_calls == 0 assert service._connection_scenario_reset_pending is None # noqa: SLF001 assert service._service_close_requested.is_set() is False # noqa: SLF001 def test_classified_scanning_adopts_same_receiver_and_allows_one_fresh_stop( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture(service, runtime) service.stop_acquisition(fixture.request) owner = _settle_real_prepared_stop_before_publish(fixture) reconciled = _classify_real_prepared_stop( fixture, owner, session_state="scanning", reconciliation_id="test-scanning-in-place", ) latest = reconciled["reconciliations"][-1] verified_binding = latest["verified_binding"]["connection"] fixture.control.state = "scanning" fixture.control.state_revision += 1 fixture.control.failure = None fixture.control.verified_control = { **dict(verified_binding), "logical_device_id": "known-k1", "compatibility_profile_id": XGRIDS_K1_COMPATIBILITY_PROFILE_ID, } old_device_session_id = owner.acquisition.device_session_id service._device_session_id = "fresh-in-place-device-session" # noqa: SLF001 runtime_start_calls = list(runtime.start_calls) service._adopt_classified_prepared_stop_scanning_in_place( # noqa: SLF001 owner=owner, reconciliation_id="test-scanning-in-place", reconciled_record=reconciled, ) assert service._acquisition is owner.acquisition # noqa: SLF001 assert service._acquisition_session_lease is owner.session_lease # noqa: SLF001 assert service._acquisition_out_dir == owner.out_dir # noqa: SLF001 assert service._acquisition.device_session_id != old_device_session_id # noqa: SLF001 assert service._acquisition.device_session_id == ( # noqa: SLF001 "fresh-in-place-device-session" ) assert service._acquisition.state == "acquiring" # noqa: SLF001 assert service._acquisition_stop_operation_id is None # noqa: SLF001 assert runtime.start_calls == runtime_start_calls # Hold the durable gap closure exactly where its fsync may block. A public # STOP must publish priority without waiting for lifecycle ownership; once # the store resumes, that priority prevents this already-published PCL from # granting camera authority and the fresh STOP owns the next durable edge. store = service._active_acquisition_checkpoint # noqa: SLF001 assert store is not None original_rebind_active = store.rebind_active rebind_entered = threading.Event() release_rebind = threading.Event() def blocked_rebind_active(**kwargs: Any) -> Any: rebind_entered.set() assert release_rebind.wait(timeout=2.0) return original_rebind_active(**kwargs) monkeypatch.setattr(store, "rebind_active", blocked_rebind_active) camera_calls: list[str] = [] def forbidden_camera_start(*_: object, **__: object) -> dict[str, object]: camera_calls.append("camera-start") return service.camera_preview.snapshot() monkeypatch.setattr( service.camera_preview, "activate_recording_producer", forbidden_camera_start, ) monkeypatch.setattr( service.camera_preview, "retry_recording_producer", forbidden_camera_start, ) frame = DecodedPointCloudView( context=ConsumerFrameContext( sequence=1, captured_at_epoch_ns=1, received_monotonic_ns=1, processing_started_monotonic_ns=1, encoded_size_bytes=16, live=True, ), frame_id="map", positions_xyz=((0.0, 0.0, 0.0),), ) runtime.phase = "live" runtime.source_mode = "live" runtime.source_ready = True runtime.pcl_frames = 1 publish_errors: list[BaseException] = [] def publish_first_pcl() -> None: try: service._observe_published_runtime_envelope( # noqa: SLF001 frame, runtime.producer_generation, ) except BaseException as exc: # pragma: no cover - asserted below publish_errors.append(exc) fresh_stop_id = "op-00000000-0000-4000-8000-000000001402" fresh_request = _stop_request( acquisition_id=owner.lineage.acquisition_id, operation_id=fresh_stop_id, idempotency_key="classified-scanning-fresh-stop", mode="graceful", physical_acceptance=PHYSICAL_ACCEPTANCE, expected_control_session_generation=fixture.control.session_generation, expected_control_state_revision=fixture.control.state_revision, ) stop_results: list[dict[str, Any]] = [] stop_errors: list[BaseException] = [] def request_fresh_stop() -> None: try: stop_results.append(service.stop_acquisition(fresh_request)) except BaseException as exc: # pragma: no cover - asserted below stop_errors.append(exc) publish_thread = threading.Thread(target=publish_first_pcl) stop_thread = threading.Thread(target=request_fresh_stop) publish_thread.start() try: assert rebind_entered.wait(timeout=2.0) stop_thread.start() deadline = time.monotonic() + 2.0 while time.monotonic() < deadline: with service._lock: # noqa: SLF001 if service._camera_stop_priority_counts.get( # noqa: SLF001 owner.lineage.acquisition_id, 0, ): break time.sleep(0.005) with service._lock: # noqa: SLF001 assert service._camera_stop_priority_counts.get( # noqa: SLF001 owner.lineage.acquisition_id, 0, ) == 1 assert stop_thread.is_alive() finally: release_rebind.set() publish_thread.join(timeout=2.0) if stop_thread.ident is not None: stop_thread.join(timeout=2.0) assert publish_thread.is_alive() is False assert stop_thread.is_alive() is False assert publish_errors == [] assert stop_errors == [] assert len(stop_results) == 1 fresh = stop_results[0] assert camera_calls == [] with service._lock: # noqa: SLF001 assert service._classified_stop_rebind_pending is None # noqa: SLF001 assert service._classified_stop_rebind_inflight is None # noqa: SLF001 record = fixture.ledger.snapshot().record assert record is not None assert record.operation_id == fresh_stop_id assert record.parent_operation_id == fixture.stop_operation_id assert record.stage == "prepared" assert fresh["acquisition"]["state"] == "awaiting_external_stop" assert fixture.prepare_calls == [fixture.stop_operation_id, fresh_stop_id] assert runtime.start_calls == runtime_start_calls def test_blocked_checkpoint_fsync_starts_stop_deadline_and_expires_before_prepare( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture(service, runtime) service.stop_acquisition(fixture.request) owner = _settle_real_prepared_stop_before_publish(fixture) reconciled = _classify_real_prepared_stop( fixture, owner, session_state="scanning", reconciliation_id="test-scanning-stop-deadline-fsync", ) verified_binding = reconciled["reconciliations"][-1]["verified_binding"]["connection"] fixture.control.state = "scanning" fixture.control.state_revision += 1 fixture.control.failure = None fixture.control.verified_control = { **dict(verified_binding), "logical_device_id": "known-k1", "compatibility_profile_id": XGRIDS_K1_COMPATIBILITY_PROFILE_ID, } service._device_session_id = "fresh-stop-deadline-session" # noqa: SLF001 service._adopt_classified_prepared_stop_scanning_in_place( # noqa: SLF001 owner=owner, reconciliation_id="test-scanning-stop-deadline-fsync", reconciled_record=reconciled, ) store = service._active_acquisition_checkpoint # noqa: SLF001 assert store is not None original_rebind_active = store.rebind_active rebind_entered = threading.Event() release_rebind = threading.Event() def blocked_rebind_active(**kwargs: Any) -> Any: rebind_entered.set() assert release_rebind.wait(timeout=3.0) return original_rebind_active(**kwargs) monkeypatch.setattr(store, "rebind_active", blocked_rebind_active) frame = DecodedPointCloudView( context=ConsumerFrameContext( sequence=1, captured_at_epoch_ns=1, received_monotonic_ns=1, processing_started_monotonic_ns=1, encoded_size_bytes=16, live=True, ), frame_id="map", positions_xyz=((0.0, 0.0, 0.0),), ) runtime.phase = "live" runtime.source_mode = "live" runtime.source_ready = True runtime.pcl_frames = 1 publish_thread = threading.Thread( target=service._observe_published_runtime_envelope, # noqa: SLF001 kwargs={"envelope": frame, "producer_generation": runtime.producer_generation}, daemon=True, ) publish_thread.start() assert rebind_entered.wait(timeout=2.0) stop_id = "op-00000000-0000-4000-8000-000000001403" request = _stop_request( acquisition_id=owner.lineage.acquisition_id, operation_id=stop_id, idempotency_key="classified-scanning-fsync-expired-stop", mode="graceful", deadline_seconds=1.0, physical_acceptance=PHYSICAL_ACCEPTANCE, expected_control_session_generation=fixture.control.session_generation, expected_control_state_revision=fixture.control.state_revision, ) stop_errors: list[BaseException] = [] def request_stop() -> None: try: service.stop_acquisition(request) except BaseException as exc: # pragma: no cover - asserted below stop_errors.append(exc) stop_thread = threading.Thread(target=request_stop, daemon=True) stop_thread.start() try: priority_deadline = time.monotonic() + 0.5 while time.monotonic() < priority_deadline: operation = next( ( item for item in service._operations.snapshot() # noqa: SLF001 if item["operation_id"] == stop_id ), None, ) with service._lock: # noqa: SLF001 priority = service._camera_stop_priority_counts.get( # noqa: SLF001 owner.lineage.acquisition_id, 0, ) if operation is not None and priority == 1: break time.sleep(0.005) assert operation is not None assert operation["status"] == "accepted" assert priority == 1 assert fixture.prepare_calls == [fixture.stop_operation_id] assert stop_thread.is_alive() deadline = time.monotonic() + 2.0 while time.monotonic() < deadline and not service._operations.deadline_reached( # noqa: SLF001 stop_id ): time.sleep(0.01) assert service._operations.deadline_reached(stop_id) is True # noqa: SLF001 finally: release_rebind.set() publish_thread.join(timeout=3.0) stop_thread.join(timeout=3.0) assert publish_thread.is_alive() is False assert stop_thread.is_alive() is False assert len(stop_errors) == 1 assert getattr(stop_errors[0], "reason_code", None) == ( "physical-command-dispatch-deadline-expired" ) operation = service._operations.get(stop_id) # noqa: SLF001 assert operation.status == "failed" assert operation.stage_code == ( "physical-stop-dispatch-deadline-expired-before-prepare" ) assert operation.error is not None assert operation.error["code"] == "physical-command-dispatch-deadline-expired" assert operation.error["side_effect_status"] == "none" assert operation.error["physical_command_sent"] is False assert operation.error["automatic_replay_allowed"] is False assert fixture.prepare_calls == [fixture.stop_operation_id] record = fixture.ledger.snapshot().record assert record is not None assert record.operation_id == fixture.stop_operation_id assert record.action == "stop" assert record.stage == "resolved" assert fixture.control.stop_calls == 1 def test_stop_deadline_after_durable_prepare_retains_exact_no_dispatch_owner( tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture(service, runtime) original_request_stop = fixture.control.request_stop def expire_after_durable_prepare(**kwargs: object) -> dict[str, object]: command_context = kwargs["command_context"] fixture.coordinator.prepare( command_context, action="stop", envelope=fixture.envelope, ) fixture.prepare_calls.append(str(command_context.operation_id)) fixture.coordinator.resolve_prepared_not_dispatched("stop") raise ApplicationMqttTransportError( "synthetic deadline after STOP PREPARE fsync", reason_code="physical-command-dispatch-deadline-expired", ) fixture.control.request_stop = expire_after_durable_prepare try: with pytest.raises( ApplicationMqttTransportError, match="synthetic deadline after STOP PREPARE fsync", ): service.stop_acquisition(fixture.request) finally: fixture.control.request_stop = original_request_stop record = fixture.ledger.snapshot().record assert record is not None assert record.operation_id == fixture.stop_operation_id assert record.action == "stop" assert record.stage == "resolved" assert record.resolution == "not-dispatched" assert record.publish_call_returned is None assert record.packet_id is None assert record.qos2_completed is False operation = service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert operation.status == "failed" assert operation.stage_code == "physical-stop-classified-not-dispatched" assert operation.error is not None assert operation.error["side_effect_status"] == "none" assert operation.error["physical_command_sent"] is False assert operation.error["automatic_replay_allowed"] is False assert fixture.prepare_calls == [fixture.stop_operation_id] with service._lock: # noqa: SLF001 acquisition = service._acquisition # noqa: SLF001 owner = service._prepared_stop_recovery_owner # noqa: SLF001 assert service._acquisition_stop_operation_id == fixture.stop_operation_id # noqa: SLF001 assert acquisition is not None assert acquisition.state == "awaiting_external_stop" assert owner is not None assert owner.acquisition is acquisition assert owner.lineage.stop_operation_id == fixture.stop_operation_id assert service.camera_preview.snapshot()["recording"]["source_end_expected"] is False # Exact retries observe the terminal journal identity and never prepare or # publish another physical STOP, even after the original control socket is # no longer admissible for a new command. fixture.control.state = "failed" fixture.control.state_revision += 1 fixture.control.failure = { "reason_code": "mqtt_network_loop_failed", "modeling_command_attempted": False, "safe_to_retry": False, } fixture.control.verified_control = None retried = service.stop_acquisition(fixture.request) assert retried["contract_version"] == "missioncore.device-plugin-state/v1alpha2" assert retried["selected_device_id"] == fixture.binding.transport_ref assert retried["acquisition"]["acquisition_id"] == fixture.request.acquisition_id assert retried["acquisition"]["state"] in { "awaiting_external_stop", "interrupted", } assert retried["last_operation"]["operation_id"] == fixture.stop_operation_id assert retried["last_operation"]["status"] == "failed" assert fixture.prepare_calls == [fixture.stop_operation_id] with pytest.raises(ValueError, match="different request"): service.stop_acquisition( fixture.request.model_copy( update={ "idempotency_key": fixture.request.idempotency_key, "expected_control_state_revision": ( fixture.request.expected_control_state_revision + 1 ), } ) ) assert fixture.prepare_calls == [fixture.stop_operation_id] def test_corrupt_physical_snapshot_never_terminalizes_preadmitted_stop_as_none( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture(service, runtime) original_snapshot = fixture.ledger.snapshot original_owned = service._stop_acquisition_owned # noqa: SLF001 entered_owned = threading.Event() def reject_before_prepare( request: StopAcquisitionRequest, preadmitted_stop: object | None = None, ) -> dict[str, Any]: assert preadmitted_stop is not None entered_owned.set() raise facade_module.LocalAcquisitionLifecycleError( "synthetic admission rejection before physical PREPARE", reason_code="synthetic-before-prepare", ) monkeypatch.setattr(service, "_stop_acquisition_owned", reject_before_prepare) monkeypatch.setattr( fixture.ledger, "snapshot", lambda: PhysicalCommandLedgerSnapshot( status="corrupt", record=None, reason_code="physical-command-ledger-corrupt", ), ) fresh_request = fixture.request.model_copy( update={ "operation_id": "op-00000000-0000-4000-8000-000000001404", "idempotency_key": "corrupt-ledger-preadmitted-stop", } ) try: with pytest.raises( facade_module.LocalAcquisitionLifecycleError, match="synthetic admission rejection", ): service.stop_acquisition(fresh_request) finally: monkeypatch.setattr(fixture.ledger, "snapshot", original_snapshot) monkeypatch.setattr(service, "_stop_acquisition_owned", original_owned) assert entered_owned.is_set() operation = service._operations.get(fresh_request.operation_id) # noqa: SLF001 assert operation.status == "accepted" assert operation.error is None assert fixture.prepare_calls == [] assert original_snapshot().record is not None assert original_snapshot().record.operation_id == fixture.start_operation_id # type: ignore[union-attr] def test_classified_ready_finishes_same_receiver_and_pins_fresh_start_binding( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture(service, runtime) service.stop_acquisition(fixture.request) owner = _settle_real_prepared_stop_before_publish(fixture) _classify_real_prepared_stop( fixture, owner, session_state="ready", reconciliation_id="test-ready-in-place", ) monkeypatch.setattr(service, "_seal_acquisition_capture_clock", lambda: None) finished = service.state() stop_operation = service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert finished["acquisition"]["state"] == "interrupted" assert finished["acquisition"]["result"]["read_only_recovery"] is True assert finished["acquisition"]["result"]["device_stop"] == "not-sent" assert finished["acquisition"]["cleanup_pending"] is False assert stop_operation.stage_code == "physical-stop-classified-not-dispatched" assert stop_operation.error is not None assert stop_operation.error["side_effect_status"] == "none" assert service._acquisition_session_lease is None # noqa: SLF001 assert service._prepared_stop_recovery_owner is None # noqa: SLF001 assert runtime.stop_calls == 1 physical = fixture.coordinator.snapshot() assert facade_module._physical_command_prepared_stop_ready_successor_pending( # noqa: SLF001 physical ) with pytest.raises( facade_module.NetworkProvisioningConflict, ) as mutation: service._require_physical_command_network_mutation_allowed() # noqa: SLF001 assert mutation.value.reason_code == "physical-command-reconciliation-required" policy = facade_module._connection_policy_projection( # noqa: SLF001 supervisor=service._connection_supervisor.snapshot(), # noqa: SLF001 ledger=service._network_mutation_ledger.snapshot(), # noqa: SLF001 fresh_devices=[], provisioning_active=False, acquisition_active=False, acquisition_cleanup_pending=False, acquisition_state="interrupted", runtime_active=False, application_control_session=fixture.control.snapshot(), physical_command=physical, ble_runtime={ "poisoned": False, "cleanup_pending": False, "active_operation_kind": None, }, lifecycle_process_lease_holders=(), network_provisioning_idempotency={}, network_provisioning_idempotency_available=True, semantic_topology_store={"status": "available"}, device_identity_pin_store={"status": "available"}, current_device_recovery=None, desired_connection_mode=service._desired_connection_mode, # noqa: SLF001 active_connection_mode=service._connection_mode, # noqa: SLF001 ) assert "physical-command-reconciliation-required" not in policy["actions"][ "start-acquisition" ]["reason_codes"] # The classified READY binding remains pinned during an ordinary # continuation, but an explicit clean-scenario reset must abandon that # future START ownership. After the separately requested fresh Scan, the # exact UUID is an ordinary one-click provisioning target again. reset = service.select_connection_mode( DesiredConnectionModeRequest( connection_mode="bridge", expected_revision=finished["desired_connection_mode_revision"], reset_scenario=True, reset_id="classified-ready-clean-network-reset-0001", ) ) assert reset["connection_scenario_reset"]["physical_disposition"] == ( "operator-retired-outcome-unknown" ) reset_record = fixture.ledger.snapshot().record assert reset_record is not None assert reset_record.resolution == "operator-retired-outcome-unknown" assert reset_record.original_command_outcome == "not-dispatched" assert fixture.prepare_calls == [fixture.stop_operation_id] with service._lock: # noqa: SLF001 service._ble_discovery_generation += 1 # noqa: SLF001 generation = service._ble_discovery_generation # noqa: SLF001 service._scenario_reset_successful_scan_generation = generation # noqa: SLF001 assert service._connection_scenario_reset is not None # noqa: SLF001 service._scenario_reset_successful_scan_reset_id = ( # noqa: SLF001 service._connection_scenario_reset["reset_id"] ) service._connection_scenario_reset["active"] = False # noqa: SLF001 service._connection_scenario_reset[ # noqa: SLF001 "settled_by_discovery_generation" ] = generation _set_scanned_k1(service, device_id=fixture.binding.transport_ref) scanned = service.state() assert scanned["connection_policy"]["facts"][ "eligible_fresh_transport_refs" ] == [fixture.binding.transport_ref] assert scanned["connection_policy"]["actions"]["provision-fresh-device"][ "allowed" ] is True assert scanned["connection_policy"]["actions"]["start-acquisition"][ "allowed" ] is False writes = _install_successful_fast_ack_bridge_write(monkeypatch) monkeypatch.setattr( service, "_schedule_control_bootstrap_continuation", lambda **_kwargs: None, ) applied = asyncio.run( service.connect( _connect_request( device_id=fixture.binding.transport_ref, ssid="classified-ready-clean-network", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, operation_id="op-00000000-0000-4000-8000-000000001405", expected_mode_revision=scanned[ "desired_connection_mode_revision" ], expected_discovery_generation=generation, expected_reconfiguration_revision=scanned[ "connection_reconfiguration" ]["revision"], ) ) ) assert writes == ["network-write"] assert applied["connection_attempt"]["phase"] == "network_applied" reopened = fixture.ledger.snapshot().record assert reopened is not None assert reopened.original_command_outcome == "not-dispatched" assert reopened.reopened_physical_state_requires_reconciliation is True assert len(reopened.operator_reconciliation_reopens) == 1 assert reopened.operator_reconciliation_reopens[-1].reason == ( "reset-network-intent-read-only-settlement" ) assert fixture.prepare_calls == [fixture.stop_operation_id] def test_classified_ready_before_first_pcl_interrupts_pending_start_without_new_edge( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture( service, runtime, confirm_first_pcl=False, ) start_before = service._operations.get(fixture.start_operation_id) # noqa: SLF001 assert start_before.status == "running" assert service._acquisition_start_operation_id == fixture.start_operation_id # noqa: SLF001 service.stop_acquisition(fixture.request) owner = _settle_real_prepared_stop_before_publish(fixture) _classify_real_prepared_stop( fixture, owner, session_state="ready", reconciliation_id="test-ready-before-first-pcl", ) monkeypatch.setattr(service, "_seal_acquisition_capture_clock", lambda: None) finished = service.state() start = service._operations.get(fixture.start_operation_id) # noqa: SLF001 stop = service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert finished["acquisition"]["state"] == "interrupted" assert finished["acquisition"]["result"]["device_stop"] == "not-sent" assert start.status == "interrupted" assert start.stage_code == "physical-start-active-but-no-point-before-standby" assert start.error is not None assert start.error["side_effect_status"] == "succeeded" assert start.error["automatic_replay_allowed"] is False assert service._acquisition_start_operation_id is None # noqa: SLF001 assert stop.stage_code == "physical-stop-classified-not-dispatched" assert stop.error is not None assert stop.error["side_effect_status"] == "none" assert fixture.prepare_calls == [fixture.stop_operation_id] assert fixture.control.stop_calls == 1 assert runtime.stop_calls == 1 @pytest.mark.parametrize("action", ["abort", "force", "reset", "close"]) def test_resolved_ready_dominates_later_local_action_without_rewriting_s0_or_pending_start( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, action: str, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture( service, runtime, confirm_first_pcl=False, ) service.stop_acquisition(fixture.request) owner = _settle_real_prepared_stop_before_publish(fixture) _classify_real_prepared_stop( fixture, owner, session_state="ready", reconciliation_id=f"test-ready-dominates-{action}", ) monkeypatch.setattr(service, "_seal_acquisition_capture_clock", lambda: None) completed = service.state() acquisition = service._acquisition # noqa: SLF001 assert acquisition is not None assert completed["acquisition"]["state"] == "interrupted" assert completed["acquisition"]["result"]["device_stop"] == "not-sent" before_record = fixture.ledger.snapshot().record before_acquisition = ( acquisition.state, acquisition.state_revision, acquisition.message_code, dict(acquisition.result or {}), ) before_operations = { item["operation_id"]: item for item in service._operations.snapshot() # noqa: SLF001 if item["operation_id"] in {fixture.start_operation_id, fixture.stop_operation_id} } before_prepare_calls = list(fixture.prepare_calls) before_control_stop_calls = fixture.control.stop_calls if action == "abort": result = service.abort_acquisition( _abort_request(acquisition_id=acquisition.acquisition_id) ) assert result["acquisition"]["state"] == "interrupted" elif action == "force": result = service.force_finish_acquisition_locally( _force_finish_request( acquisition_id=acquisition.acquisition_id, expected_state_revision=acquisition.state_revision, expected_recovery_generation=( service._active_stream_recovery_generation # noqa: SLF001 ), ) ) assert result["acquisition"]["state"] == "interrupted" elif action == "reset": result = service.select_connection_mode( DesiredConnectionModeRequest( connection_mode="quick-connect", expected_revision=service._desired_connection_mode_revision, # noqa: SLF001 reset_scenario=True, reset_id="resolved-ready-reset-0001", ) ) assert result["acquisition"]["state"] == "interrupted" else: service.close() after_operations = { item["operation_id"]: item for item in service._operations.snapshot() # noqa: SLF001 if item["operation_id"] in {fixture.start_operation_id, fixture.stop_operation_id} } after_record = fixture.ledger.snapshot().record if action == "reset": assert before_record is not None assert after_record is not None assert after_record.revision == before_record.revision + 1 assert after_record.resolution == "operator-retired-outcome-unknown" assert after_record.original_command_outcome == "not-dispatched" assert after_record.reconciliations == before_record.reconciliations assert after_record.operator_retirements[-1].reason == ( "connection-scenario-reset-by-operator" ) assert after_record.operator_retirements[-1].original_attempt.operation_id == ( before_record.operation_id ) assert after_record.operator_retirements[-1].original_attempt.revision == ( before_record.revision ) else: assert after_record == before_record assert ( acquisition.state, acquisition.state_revision, acquisition.message_code, dict(acquisition.result or {}), ) == before_acquisition assert after_operations == before_operations assert before_operations[fixture.start_operation_id]["status"] == "interrupted" assert before_operations[fixture.start_operation_id]["stage_code"] == ( "physical-start-active-but-no-point-before-standby" ) assert before_operations[fixture.stop_operation_id]["stage_code"] == ( "physical-stop-classified-not-dispatched" ) assert before_operations[fixture.stop_operation_id]["error"]["side_effect_status"] == "none" assert fixture.prepare_calls == before_prepare_calls assert fixture.control.stop_calls == before_control_stop_calls @pytest.mark.parametrize("camera_outcome", ["healthy", "dead", "clean-ended"]) def test_classified_scanning_cancels_stop_eof_and_preserves_or_rearms_camera_epoch( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, camera_outcome: str, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture(service, runtime) service.stop_acquisition(fixture.request) owner = _settle_real_prepared_stop_before_publish(fixture) reconciled = _classify_real_prepared_stop( fixture, owner, session_state="scanning", reconciliation_id=f"test-scanning-camera-{camera_outcome}", ) verified_binding = reconciled["reconciliations"][-1]["verified_binding"]["connection"] fixture.control.state = "scanning" fixture.control.state_revision += 1 fixture.control.failure = None fixture.control.verified_control = { **dict(verified_binding), "logical_device_id": "known-k1", "compatibility_profile_id": XGRIDS_K1_COMPATIBILITY_PROFILE_ID, } service._device_session_id = f"fresh-camera-{camera_outcome}-session" # noqa: SLF001 # `_classify_real_prepared_stop` installs the fresh durable/control proof # directly. Production Verify also publishes that same rotated route and # DeviceInfo generation to the connection supervisor; mirror that portion # here so the real camera activation admission remains exercised. fresh_path = HostPathProbeResult( available=True, fingerprint=f"test-route:classified-camera:{camera_outcome}", interface="test0", source_ipv4="192.168.1.2", route_class="direct", kernel_route_fingerprint=(f"test-route:classified-camera:{camera_outcome}"), ) fresh_host_epoch = service._connection_supervisor.observe_host_path( # noqa: SLF001 fresh_path ) assert fresh_host_epoch == verified_binding["host_path_epoch"] fresh_target = EndpointTarget( str(verified_binding["target_ipv4"]), int(verified_binding["target_port"]), ) assert service._connection_supervisor.observe_endpoint( # noqa: SLF001 target=fresh_target, intent_id=str(verified_binding["intent_id"]), host_path_epoch=fresh_host_epoch, reachable=True, ) assert service._connection_supervisor.observe_control_evidence( # noqa: SLF001 VerifiedControlEvidence( intent_id=str(verified_binding["intent_id"]), transport_ref=str(verified_binding["transport_ref"]), host_path_epoch=fresh_host_epoch, target=fresh_target, connection_mode=verified_binding["connection_mode"], # type: ignore[arg-type] logical_device_id="known-k1", compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, control_session_id=str(verified_binding["control_session_id"]), ) ) owner.out_dir.mkdir(parents=True, exist_ok=True) initial_epoch = 5 if camera_outcome == "healthy" else None camera_state: dict[str, object] = { "phase": ( "streaming" if camera_outcome == "healthy" else "error" if camera_outcome == "dead" else "idle" ), "generation": None if camera_outcome == "clean-ended" else 5, "active_source_id": ( None if camera_outcome == "clean-ended" else facade_module.DEFAULT_ACQUISITION_CAMERA_SOURCE ), # These are the real gateway shapes after producer detachment. The # acquisition recording root stays active while both ended variants # expose no active producer epoch. The dead case is the bounded # pre-first-media decode failure which production admits for a fresh # epoch; a generic source EOF must first finish its archive seal. "recording": { "active": True, "session": owner.out_dir.name, "active_epoch": initial_epoch, "producer_alive": camera_outcome == "healthy", "source_end_expected": False, "committed_media_segment_count": 0, }, "error": ( {"code": "invalid-fmp4", "message": "synthetic dead producer"} if camera_outcome == "dead" else None ), } cancel_calls: list[str] = [] select_calls: list[tuple[str, str]] = [] start_recording_calls: list[Path] = [] retry_calls: list[tuple[str, str, int, str]] = [] def snapshot_camera() -> dict[str, object]: return { **camera_state, "recording": dict(camera_state["recording"]), # type: ignore[arg-type] } def cancel_expected_source_end() -> dict[str, object]: cancel_calls.append("cancel") return snapshot_camera() def select_camera(source_id: str, target: str) -> dict[str, object]: select_calls.append((source_id, target)) assert camera_outcome == "clean-ended" recording = camera_state["recording"] assert isinstance(recording, dict) camera_state.update( { "phase": "connecting", "generation": 6, "active_source_id": source_id, "error": None, } ) # A real select auto-spawns because the clean-ended gateway retained # this acquisition's recording root. recording.update({"active_epoch": 6, "producer_alive": True}) return snapshot_camera() def start_recording(session_dir: Path) -> dict[str, object]: start_recording_calls.append(session_dir) assert session_dir == owner.out_dir return snapshot_camera() def retry_recording( source_id: str, target: str, *, expected_generation: int, expected_recording_session: str, pre_retry_fence: Callable[[Callable[[], bool]], bool], commit_fence: Callable[[Callable[[], bool]], bool] | None = None, committed_before_start: Callable[[dict[str, object]], None] | None = None, ) -> dict[str, object]: retry_calls.append( (source_id, target, expected_generation, expected_recording_session) ) assert camera_outcome == "dead" assert expected_generation == 5 assert expected_recording_session == owner.out_dir.name assert pre_retry_fence(lambda: True) is True recording = camera_state["recording"] assert isinstance(recording, dict) recording.update({"active_epoch": 6, "producer_alive": True}) camera_state.update( { "phase": "streaming", "generation": 6, "active_source_id": source_id, "error": None, } ) assert commit_fence is not None assert committed_before_start is not None assert commit_fence( lambda: committed_before_start(snapshot_camera()) is None ) is True return snapshot_camera() def activate_recording( source_id: str, target: str, session_dir: Path, *, commit_fence: Callable[[Callable[[], bool]], bool], committed_before_start: Callable[[dict[str, object]], None] | None = None, ) -> dict[str, object]: select_camera(source_id, target) start_recording(session_dir) assert committed_before_start is not None assert commit_fence( lambda: committed_before_start(snapshot_camera()) is None ) is True return snapshot_camera() monkeypatch.setattr(service.camera_preview, "snapshot", snapshot_camera) monkeypatch.setattr( service.camera_preview, "cancel_expected_source_end", cancel_expected_source_end, ) monkeypatch.setattr(service.camera_preview, "select", select_camera) monkeypatch.setattr(service.camera_preview, "start_recording", start_recording) monkeypatch.setattr( service.camera_preview, "activate_recording_producer", activate_recording, ) monkeypatch.setattr( service.camera_preview, "retry_recording_producer", retry_recording, ) activation_lineage = ( owner.lineage.acquisition_id, owner.out_dir.name, owner.runtime_producer_generation, ) with service._lock: # noqa: SLF001 service._camera_activation_lineage = activation_lineage # noqa: SLF001 service._adopt_classified_prepared_stop_scanning_in_place( # noqa: SLF001 owner=owner, reconciliation_id=f"test-scanning-camera-{camera_outcome}", reconciled_record=reconciled, ) assert cancel_calls == ["cancel"] assert snapshot_camera()["recording"]["source_end_expected"] is False # type: ignore[index] assert select_calls == [] assert start_recording_calls == [] assert retry_calls == [] with service._lock: # noqa: SLF001 if camera_outcome == "healthy": assert service._camera_activation_lineage == activation_lineage # noqa: SLF001 assert service._camera_activation_retry_lineage is None # noqa: SLF001 else: assert service._camera_activation_lineage is None # noqa: SLF001 assert service._camera_activation_retry_lineage == activation_lineage # noqa: SLF001 assert snapshot_camera()["recording"]["active_epoch"] == initial_epoch # type: ignore[index] checkpoint_store = service._active_acquisition_checkpoint # noqa: SLF001 assert checkpoint_store is not None pending_before_pcl = service._classified_stop_rebind_pending # noqa: SLF001 assert pending_before_pcl is not None gap_snapshot = checkpoint_store.snapshot() assert gap_snapshot.status == "active" assert gap_snapshot.checkpoint is not None assert gap_snapshot.checkpoint.last_gap_started_at_utc is not None assert gap_snapshot.checkpoint.last_gap_recovered_at_utc is None original_lease = service._acquisition_session_lease # noqa: SLF001 original_out_dir = service._acquisition_out_dir # noqa: SLF001 frame = DecodedPointCloudView( context=ConsumerFrameContext( sequence=1, captured_at_epoch_ns=1, received_monotonic_ns=1, processing_started_monotonic_ns=1, encoded_size_bytes=16, live=True, ), frame_id="map", positions_xyz=((0.0, 0.0, 0.0),), ) runtime.phase = "live" runtime.source_mode = "live" runtime.source_ready = True runtime.pcl_frames = 1 stale_frame = DecodedPointCloudView( context=ConsumerFrameContext( sequence=2, captured_at_epoch_ns=1, received_monotonic_ns=1, processing_started_monotonic_ns=1, encoded_size_bytes=16, live=False, ), frame_id="map", positions_xyz=((0.0, 0.0, 0.0),), ) empty_frame = DecodedPointCloudView( context=ConsumerFrameContext( sequence=1, captured_at_epoch_ns=1, received_monotonic_ns=1, processing_started_monotonic_ns=1, encoded_size_bytes=0, live=True, ), frame_id="map", positions_xyz=(), ) service._observe_published_runtime_envelope( # noqa: SLF001 stale_frame, runtime.producer_generation, ) service._observe_published_runtime_envelope( # noqa: SLF001 empty_frame, runtime.producer_generation, ) service._observe_published_runtime_envelope( # noqa: SLF001 frame, runtime.producer_generation + 1, ) with service._camera_restart_commit_gate, service._lock: # noqa: SLF001 service._camera_stop_priority_counts[ # noqa: SLF001 owner.lineage.acquisition_id ] = 1 try: assert service._promote_classified_stop_rebind_from_pcl( # noqa: SLF001 envelope=frame, producer_generation=runtime.producer_generation, ) is False finally: with service._camera_restart_commit_gate, service._lock: # noqa: SLF001 service._camera_stop_priority_counts.pop( # noqa: SLF001 owner.lineage.acquisition_id, None, ) assert service._classified_stop_rebind_pending == pending_before_pcl # noqa: SLF001 assert service._classified_stop_rebind_inflight is None # noqa: SLF001 assert checkpoint_store.snapshot().checkpoint == gap_snapshot.checkpoint assert select_calls == [] assert start_recording_calls == [] assert retry_calls == [] rebind_calls: list[str] = [] original_rebind_active = checkpoint_store.rebind_active def observe_rebind_active(**kwargs: Any) -> Any: rebind_calls.append(str(kwargs["transition_id"])) committed = original_rebind_active(**kwargs) if camera_outcome == "dead": raise OSError("synthetic lost response after durable rebind") return committed monkeypatch.setattr( checkpoint_store, "rebind_active", observe_rebind_active, ) service._observe_published_runtime_envelope( # noqa: SLF001 frame, runtime.producer_generation, ) committed_snapshot = checkpoint_store.snapshot() assert committed_snapshot.status == "active" assert committed_snapshot.checkpoint is not None assert committed_snapshot.checkpoint.revision == ( gap_snapshot.checkpoint.revision + 1 ) assert committed_snapshot.checkpoint.last_gap_recovered_at_utc is not None assert rebind_calls == [pending_before_pcl.transition_id] assert service._classified_stop_rebind_pending is None # noqa: SLF001 assert service._classified_stop_rebind_inflight is None # noqa: SLF001 assert service._acquisition_session_lease is original_lease # noqa: SLF001 assert service._acquisition_out_dir == original_out_dir # noqa: SLF001 deadline = time.monotonic() + 2.0 while ( camera_outcome != "healthy" and not (select_calls or retry_calls) and time.monotonic() < deadline ): time.sleep(0.01) service._observe_published_runtime_envelope( # noqa: SLF001 frame, runtime.producer_generation, ) time.sleep(0.05) assert checkpoint_store.snapshot().checkpoint == committed_snapshot.checkpoint assert rebind_calls == [pending_before_pcl.transition_id] assert len(select_calls) + len(retry_calls) <= 1 if camera_outcome == "healthy": assert select_calls == [] assert start_recording_calls == [] assert retry_calls == [] assert snapshot_camera()["recording"]["active_epoch"] == initial_epoch # type: ignore[index] elif camera_outcome == "clean-ended": assert select_calls == [ ( facade_module.DEFAULT_ACQUISITION_CAMERA_SOURCE, owner.lineage.target_ipv4, ) ] assert start_recording_calls == [owner.out_dir] assert retry_calls == [] assert snapshot_camera()["recording"]["active_epoch"] == 6 # type: ignore[index] else: assert select_calls == [] assert start_recording_calls == [] assert retry_calls == [ ( facade_module.DEFAULT_ACQUISITION_CAMERA_SOURCE, owner.lineage.target_ipv4, 5, owner.out_dir.name, ) ] assert snapshot_camera()["recording"]["active_epoch"] == 6 # type: ignore[index] def test_classified_ready_cleanup_failure_retains_owner_then_retries_locally( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture(service, runtime) service.stop_acquisition(fixture.request) owner = _settle_real_prepared_stop_before_publish(fixture) _classify_real_prepared_stop( fixture, owner, session_state="ready", reconciliation_id="test-ready-cleanup-retry", ) monkeypatch.setattr(service, "_seal_acquisition_capture_clock", lambda: None) original_stop_current = service.camera_preview.stop_current failure_pending = True def fail_once_stop_current() -> dict[str, object]: nonlocal failure_pending if failure_pending: failure_pending = False raise RuntimeError("synthetic camera current cleanup failure") return original_stop_current() monkeypatch.setattr(service.camera_preview, "stop_current", fail_once_stop_current) with pytest.raises(RuntimeError, match="synthetic camera current cleanup failure"): service.state() failed = service._acquisition # noqa: SLF001 assert failed is not None assert failed.state == "failed" assert failed.result is not None assert failed.result["device_stop"] == "not-sent" assert failed.result["local_cleanup_retry_pending"] is True assert service._acquisition_session_lease is owner.session_lease # noqa: SLF001 assert service._prepared_stop_recovery_owner is owner # noqa: SLF001 assert runtime.stop_calls == 0 retried = service.state() assert retried["acquisition"]["state"] == "failed" assert retried["acquisition"]["cleanup_pending"] is False assert retried["acquisition"]["result"]["device_stop"] == "not-sent" assert retried["acquisition"]["result"]["receiver_stopped"] is True assert "local_cleanup_retry_pending" not in retried["acquisition"]["result"] assert retried["acquisition"]["message_code"] == ( "acquisition.recovery.local_cleanup_completed" ) assert failed.result is not None assert failed.result["receiver_stopped"] is True assert "local_cleanup_retry_pending" not in failed.result assert service._acquisition_session_lease is None # noqa: SLF001 assert service._prepared_stop_recovery_owner is None # noqa: SLF001 assert runtime.stop_calls == 1 record = fixture.ledger.snapshot().record assert record is not None assert record.operation_id == fixture.stop_operation_id assert record.resolution == "not-dispatched" assert fixture.control.stop_calls == 1 @pytest.mark.parametrize( ("failure_stage", "expected_message_code"), [ ( "camera-process-lease", "acquisition.recovery.camera_fence_release_failed", ), ("runtime", "acquisition.recovery.runtime_cleanup_failed"), ("capture-clock", "acquisition.recovery.capture_clock_failed"), ( "perception-ingress", "acquisition.recovery.perception_ingress_cleanup_failed", ), ( "evidence-lease", "acquisition.recovery.evidence_lease_release_failed", ), ], ) def test_classified_ready_staged_cleanup_failure_retains_exact_owner_for_local_retry( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, failure_stage: str, expected_message_code: str, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture(service, runtime) service.stop_acquisition(fixture.request) owner = _settle_real_prepared_stop_before_publish(fixture) _classify_real_prepared_stop( fixture, owner, session_state="ready", reconciliation_id=f"test-ready-{failure_stage}", ) activation_lineage = ( owner.lineage.acquisition_id, owner.out_dir.name, owner.runtime_producer_generation, ) with service._lock: # noqa: SLF001 service._live_perception_camera_binding = ( # noqa: SLF001 owner.out_dir.name, facade_module.DEFAULT_ACQUISITION_CAMERA_SOURCE, 1, ) service._camera_activation_lineage = activation_lineage # noqa: SLF001 service._camera_activation_retry_lineage = activation_lineage # noqa: SLF001 failure_pending = True process_lease = None if failure_stage == "camera-process-lease": assert service._ensure_camera_preview_process_lease() is True # noqa: SLF001 process_lease = service._application_control_process_lease # noqa: SLF001 assert process_lease is not None original_release = type(process_lease).release def fail_once_process_release(candidate: object) -> object: nonlocal failure_pending if candidate is process_lease and failure_pending: failure_pending = False raise RuntimeError("synthetic camera process lease release failure") return original_release(candidate) # type: ignore[arg-type] monkeypatch.setattr(type(process_lease), "release", fail_once_process_release) elif failure_stage == "runtime": runtime.stop_error = RuntimeError("synthetic recovery runtime stop failure") elif failure_stage == "capture-clock": original_seal = service._seal_acquisition_capture_clock # noqa: SLF001 def fail_once_clock() -> None: nonlocal failure_pending if failure_pending: failure_pending = False raise RuntimeError("synthetic recovery capture clock failure") original_seal() monkeypatch.setattr(service, "_seal_acquisition_capture_clock", fail_once_clock) elif failure_stage == "perception-ingress": original_end_session = service.live_perception_ingress.end_session def fail_once_ingress(session_id: str) -> None: nonlocal failure_pending if failure_pending: failure_pending = False raise RuntimeError("synthetic recovery ingress cleanup failure") original_end_session(session_id) monkeypatch.setattr( service.live_perception_ingress, "end_session", fail_once_ingress, ) elif failure_stage == "evidence-lease": original_release_evidence = service._release_acquisition_session_lease # noqa: SLF001 def fail_once_evidence_release() -> None: nonlocal failure_pending if failure_pending: failure_pending = False raise RuntimeError("synthetic recovery evidence lease release failure") original_release_evidence() monkeypatch.setattr( service, "_release_acquisition_session_lease", fail_once_evidence_release, ) else: # pragma: no cover - exhaustive test table raise AssertionError(failure_stage) with pytest.raises(RuntimeError, match="synthetic"): service.state() failed = service._acquisition # noqa: SLF001 assert failed is owner.acquisition assert failed.state == "failed" assert failed.message_code == expected_message_code assert failed.result is not None assert failed.result["device_stop"] == "not-sent" assert failed.result["local_cleanup_retry_pending"] is True assert failed.result["local_cleanup_stage"] == failure_stage assert failed.result["local_cleanup_error_code"] == "RuntimeError" assert service._acquisition_session_lease is owner.session_lease # noqa: SLF001 assert service._prepared_stop_recovery_owner is owner # noqa: SLF001 if failure_stage == "camera-process-lease": assert runtime.stop_calls == 0 assert service._application_control_process_lease is process_lease # noqa: SLF001 assert service._application_control_process_lease_holders == { # noqa: SLF001 "camera" } runtime.stop_error = None retried = service.state() assert retried["acquisition"]["state"] == "failed" assert retried["acquisition"]["cleanup_pending"] is False assert retried["acquisition"]["result"]["device_stop"] == "not-sent" assert retried["acquisition"]["result"]["receiver_stopped"] is True assert "local_cleanup_retry_pending" not in retried["acquisition"]["result"] assert "local_cleanup_stage" not in retried["acquisition"]["result"] assert retried["acquisition"]["message_code"] == ( "acquisition.recovery.local_cleanup_completed" ) assert service._acquisition_session_lease is None # noqa: SLF001 assert service._prepared_stop_recovery_owner is None # noqa: SLF001 assert service._application_control_process_lease_holders == set() # noqa: SLF001 assert service._application_control_process_lease is None # noqa: SLF001 assert service._live_perception_camera_binding is None # noqa: SLF001 assert service._camera_activation_lineage is None # noqa: SLF001 assert service._camera_activation_retry_lineage is None # noqa: SLF001 assert fixture.control.stop_calls == 1 record = fixture.ledger.snapshot().record assert record is not None assert record.operation_id == fixture.stop_operation_id assert record.resolution == "not-dispatched" def test_classified_ready_ambiguous_process_fence_release_requires_restart( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture(service, runtime) service.stop_acquisition(fixture.request) owner = _settle_real_prepared_stop_before_publish(fixture) _classify_real_prepared_stop( fixture, owner, session_state="ready", reconciliation_id="test-ready-ambiguous-process-fence", ) assert service._ensure_camera_preview_process_lease() is True # noqa: SLF001 process_lease = service._application_control_process_lease # noqa: SLF001 assert process_lease is not None descriptor = process_lease._descriptor # noqa: SLF001 original_flock = fcntl.flock original_close = os.close unlock_calls = 0 close_calls = 0 def fail_unlock(candidate: int, operation: int) -> None: nonlocal unlock_calls if candidate == descriptor and operation == fcntl.LOCK_UN: unlock_calls += 1 raise OSError(5, "synthetic unlock failure") original_flock(candidate, operation) def fail_close(candidate: int) -> None: nonlocal close_calls if candidate == descriptor: close_calls += 1 raise OSError(5, "synthetic close failure") original_close(candidate) monkeypatch.setattr(fcntl, "flock", fail_unlock) monkeypatch.setattr(os, "close", fail_close) try: with pytest.raises( facade_module.ApplicationControlProcessLeaseReleaseAmbiguous ): service.state() failed = service._acquisition # noqa: SLF001 assert failed is owner.acquisition assert failed.state == "failed" assert failed.result is not None assert failed.result["local_cleanup_retry_pending"] is True assert failed.result["local_cleanup_stage"] == "camera-process-lease" assert service._acquisition_session_lease is owner.session_lease # noqa: SLF001 assert service._prepared_stop_recovery_owner is owner # noqa: SLF001 assert runtime.stop_calls == 0 assert (unlock_calls, close_calls) == (1, 1) quarantined = service.state() assert quarantined["acquisition"]["cleanup_pending"] is True assert quarantined["acquisition"]["result"][ "local_cleanup_retry_pending" ] is True assert quarantined["k1_lifecycle_process_lease"] == { "held_by_current_service": False, "holders": [], "process_lease_quarantined": True, "reason_code": ( "application-control-process-lease-release-ambiguous" ), "restart_required": True, } assert quarantined["connection_policy"]["allowed_actions"] == [] assert quarantined["connection_policy"]["recommended_action"] == ( "restart-mission-core" ) assert (unlock_calls, close_calls) == (1, 1) assert runtime.stop_calls == 0 with pytest.raises( facade_module.ApplicationControlProcessLeaseUnavailable ): service._ensure_camera_preview_process_lease() # noqa: SLF001 finally: monkeypatch.setattr(fcntl, "flock", original_flock) monkeypatch.setattr(os, "close", original_close) original_flock(descriptor, fcntl.LOCK_UN) original_close(descriptor) def test_repeated_classified_stop_chain_preserves_pending_start_until_first_pcl( tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture( service, runtime, confirm_first_pcl=False, ) start_operation = service._operations.get(fixture.start_operation_id) # noqa: SLF001 assert start_operation.status == "running" assert service._acquisition_start_operation_id == fixture.start_operation_id # noqa: SLF001 service.stop_acquisition(fixture.request) owner0 = _settle_real_prepared_stop_before_publish(fixture) reconciled0 = _classify_real_prepared_stop( fixture, owner0, session_state="scanning", reconciliation_id="test-chain-s0", ) binding0 = reconciled0["reconciliations"][-1]["verified_binding"]["connection"] fixture.control.state = "scanning" fixture.control.state_revision += 1 fixture.control.failure = None fixture.control.verified_control = { **dict(binding0), "logical_device_id": "known-k1", "compatibility_profile_id": XGRIDS_K1_COMPATIBILITY_PROFILE_ID, } service._device_session_id = "fresh-chain-s0-session" # noqa: SLF001 service._adopt_classified_prepared_stop_scanning_in_place( # noqa: SLF001 owner=owner0, reconciliation_id="test-chain-s0", reconciled_record=reconciled0, ) assert service._acquisition.state == "awaiting_external_start" # noqa: SLF001 assert service._acquisition_start_operation_id == fixture.start_operation_id # noqa: SLF001 stop1_id = "op-00000000-0000-4000-8000-000000001403" service.stop_acquisition( _stop_request( acquisition_id=owner0.lineage.acquisition_id, operation_id=stop1_id, idempotency_key="classified-chain-s1", mode="graceful", physical_acceptance=PHYSICAL_ACCEPTANCE, expected_control_session_generation=fixture.control.session_generation, expected_control_state_revision=fixture.control.state_revision, ) ) fixture.control.state = "failed" fixture.control.state_revision += 1 fixture.control.failure = { "reason_code": "application-connection-binding-lost", "modeling_command_attempted": False, "safe_to_retry": False, } service.state() owner1 = service._prepared_stop_recovery_owner # noqa: SLF001 assert isinstance(owner1, facade_module._PreparedStopRecoveryOwner) assert owner1.lineage.stop_operation_id == stop1_id assert owner1.lineage.parent_physical_operation_id == fixture.stop_operation_id assert owner1.start_operation_id == fixture.start_operation_id reconciled1 = _classify_real_prepared_stop( fixture, owner1, session_state="scanning", reconciliation_id="test-chain-s1", ) binding1 = reconciled1["reconciliations"][-1]["verified_binding"]["connection"] fixture.control.state = "scanning" fixture.control.state_revision += 1 fixture.control.failure = None fixture.control.verified_control = { **dict(binding1), "logical_device_id": "known-k1", "compatibility_profile_id": XGRIDS_K1_COMPATIBILITY_PROFILE_ID, } with service._lock: # noqa: SLF001 service._selected_device_id = fixture.binding.transport_ref # noqa: SLF001 service._connection_mode = fixture.binding.connection_mode # noqa: SLF001 service._k1_ip = fixture.binding.target_ipv4 # noqa: SLF001 service._device_session_id = "fresh-chain-s1-session" # noqa: SLF001 service._adopt_classified_prepared_stop_scanning_in_place( # noqa: SLF001 owner=owner1, reconciliation_id="test-chain-s1", reconciled_record=reconciled1, ) assert service._matching_start_active_confirmed( # noqa: SLF001 fixture.coordinator.snapshot(), acquisition_id=owner1.lineage.acquisition_id, start_operation_id=fixture.start_operation_id, verified_control=fixture.control.verified_control, ) repeated_s0 = service.stop_acquisition(fixture.request) current_after_old_retry = fixture.ledger.snapshot().record assert current_after_old_retry is not None assert current_after_old_retry.operation_id == stop1_id assert current_after_old_retry.stage == "resolved" assert repeated_s0["acquisition"]["state"] == "awaiting_external_start" assert fixture.prepare_calls == [fixture.stop_operation_id, stop1_id] runtime.phase = "live" runtime.source_ready = True runtime.recovery_state = "recovered" runtime.pcl_frames = 1 first_pcl = service.state() start_operation = service._operations.get(fixture.start_operation_id) # noqa: SLF001 assert first_pcl["acquisition"]["state"] == "acquiring" assert start_operation.status == "succeeded" assert start_operation.stage_code == "canonical-start-and-first-point-frame" assert service._acquisition_start_operation_id is None # noqa: SLF001 with service._lock: # noqa: SLF001 service._active_stream_recovery_lineage = None # noqa: SLF001 service._active_stream_recovery_state = "inactive" # noqa: SLF001 runtime.phase = "reconnecting" runtime.source_ready = False runtime.recovery_state = "reconnecting" second_disconnect = service._admit_active_stream_recovery_lineage( # noqa: SLF001 runtime=runtime.snapshot(), ) assert second_disconnect is not None assert second_disconnect.physical_operation_id == stop1_id assert second_disconnect.start_operation_id == fixture.start_operation_id runtime.phase = "live" runtime.source_ready = True runtime.recovery_state = "recovered" current_physical = fixture.coordinator.snapshot() current_record = current_physical["record"] assert isinstance(current_record, dict) assert service._physical_active_parent_proof( # noqa: SLF001 current_physical, acquisition_id=owner1.lineage.acquisition_id, parent_operation_id=str(current_record["operation_id"]), verified_control=fixture.control.verified_control, ) is not None stop2_id = "op-00000000-0000-4000-8000-000000001404" captured_stop2 = service._capture_prepared_stop_dispatch_lineage( # noqa: SLF001 operation_id=stop2_id, acquisition=owner1.acquisition, ) assert captured_stop2 is not None service.stop_acquisition( _stop_request( acquisition_id=owner1.lineage.acquisition_id, operation_id=stop2_id, idempotency_key="classified-chain-s2", mode="graceful", physical_acceptance=PHYSICAL_ACCEPTANCE, expected_control_session_generation=fixture.control.session_generation, expected_control_state_revision=fixture.control.state_revision, ) ) current = fixture.ledger.snapshot().record assert current is not None assert current.operation_id == stop2_id assert current.parent_operation_id == stop1_id assert current.stage == "prepared" def test_prepared_stop_gate_defer_preserves_terminal_truth_until_settlement_and_teardown( tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture(service, runtime) service.stop_acquisition(fixture.request) fixture.control.state = "failed" fixture.control.state_revision += 1 fixture.control.failure = { "reason_code": "mqtt_network_loop_failed", "modeling_command_attempted": False, "safe_to_retry": False, } # Simulate the transport owning its global dispatch fence. Both truthful # settlement and topology retirement defer; generic reducers must not # convert the still-PREPARED STOP to UNKNOWN in the meantime. assert service._k1_command_dispatch_gate.acquire(blocking=False) # noqa: SLF001 try: deferred = service.state() finally: service._k1_command_dispatch_gate.release() # noqa: SLF001 operation = service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert operation.status == "running" assert operation.error is None assert deferred["selected_device_id"] == fixture.binding.transport_ref assert deferred["application_control_session"]["state"] == "failed" # On the next poll, settlement happens before proven-loss retirement could # reset the failed control owner to idle. Exact NONE instead promotes the # retained receiver into read-only classification recovery, so teardown is # intentionally deferred rather than discarding the live evidence owner. settled = service.state() operation = service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert operation.status == "failed" assert operation.stage_code == "physical-stop-classified-not-dispatched" assert operation.error is not None assert operation.error["side_effect_status"] == "none" assert operation.error["physical_command_sent"] is False assert settled["selected_device_id"] == fixture.binding.transport_ref assert service._prepared_stop_recovery_owner is not None # noqa: SLF001 assert settled["application_control_session"]["state"] == "failed" def test_stop_without_exact_parent_proof_fails_before_durable_prepare( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture(service, runtime) parent = fixture.ledger.snapshot().record assert parent is not None original_snapshot = fixture.coordinator.snapshot def snapshot_without_parent_identity() -> dict[str, object]: snapshot = original_snapshot() record = snapshot.get("record") assert isinstance(record, dict) snapshot["record"] = {**record, "identity": None} return snapshot monkeypatch.setattr(fixture.coordinator, "snapshot", snapshot_without_parent_identity) with pytest.raises( facade_module.LocalAcquisitionLifecycleError, match="physical lineage", ) as raised: service.stop_acquisition(fixture.request) assert raised.value.reason_code == "physical-stop-parent-proof-unavailable" assert fixture.prepare_calls == [] assert fixture.control.stop_calls == 0 current = fixture.ledger.snapshot().record assert current is not None assert current.operation_id == parent.operation_id assert current.stage == "resolved" operation = service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert operation.status == "failed" assert operation.error is not None assert operation.error["side_effect_status"] == "none" @dataclass class _ActualWorkerStopTransportSnapshot: state: str publish_attempts: int def as_dict(self) -> dict[str, object]: return { "state": self.state, "publish_attempts": self.publish_attempts, "qos2_completions": 0, "correlated_responses": 1, "ignored_known_responses": 0, "late_known_responses": 0, "latest_device_session_state": "scanning", "latest_device_project_bound": True, "latest_device_init_ready": True, "automatic_retry": False, "automatic_reconnect": False, "control_proof_revision": 1, "control_proof_source": "correlated-application-response", "control_proof_fresh": True, "control_proof_age_seconds": 0.0, } class _ActualWorkerStopRaceTransport: """Fake MQTT client boundary driven by the real control-session worker.""" def __init__(self) -> None: self.state = "new" self.publish_attempts = 0 self.fake_client_publish_calls: list[str] = [] self.evidence_observer: object | None = None self.dispatch_guard: Callable[[], Callable[[], None] | None] | None = None self.before_transport_guard = threading.Event() self.release_transport_guard = threading.Event() self.after_mark_dispatching = threading.Event() self.release_fake_publish = threading.Event() def install_evidence_observer(self, observer: object) -> None: self.evidence_observer = observer def install_dispatch_guard( self, guard: Callable[[], Callable[[], None] | None], ) -> None: self.dispatch_guard = guard def open(self) -> _ActualWorkerStopTransportSnapshot: self.state = "ready" return self.snapshot() def close(self) -> None: self.state = "closed" def snapshot(self) -> _ActualWorkerStopTransportSnapshot: return _ActualWorkerStopTransportSnapshot(self.state, self.publish_attempts) def validate_control_proof(self, _binding: LiveDeviceControlBinding) -> None: return None def scan_initialization_complete(self, _binding: LiveDeviceControlBinding) -> bool: return True def exchange_batch_once( self, envelopes: Any, *, required_response_operation_keys: Any, ) -> dict[str, bytes]: envelope = tuple(envelopes)[0] assert envelope.operation_key == "modeling:stop" assert required_response_operation_keys == {"modeling:stop"} assert self.dispatch_guard is not None release = self.dispatch_guard() try: self.publish_attempts += 1 observer = self.evidence_observer assert observer is not None observer.publish_dispatching( ApplicationMqttPublishEvidence( operation_key="modeling:stop", topic=envelope.topic, payload_sha256=envelope.payload_sha256, qos=envelope.qos, retain=envelope.retain, packet_id=None, ) ) self.after_mark_dispatching.set() assert self.release_fake_publish.wait(3.0) self.fake_client_publish_calls.append(envelope.payload_sha256) raise RuntimeError("synthetic response omitted after fake client publish") finally: if release is not None: release() class _ActualWorkerStopRaceExecutor: def __init__(self, transport: _ActualWorkerStopRaceTransport) -> None: self.transport = transport self.binding = LiveDeviceControlBinding( vendor_device_id="actual-worker-device", device_serial="ACTUAL-WORKER-SERIAL", software_version="3.0.2", system_version="3.0.2", device_model="LixelKity K1", device_type="A4", is_activated=True, ) self.stage = "inspection" def run_read_only_inspection_stage(self, _orchestrator: object) -> LiveDeviceControlBinding: observer = self.transport.evidence_observer assert observer is not None observer.application_response( ApplicationMqttResponseEvidence( operation_key="bootstrap:1:DeviceInfoRequest", response_topic="lixel/application/response/device_info", payload_sha256="8" * 64, modeling_action=None, result_code=None, success=None, observed_at_utc="2026-08-12T09:00:00.000Z", ) ) return self.binding def wait_for_operator_checkpoint( self, _event: str, observed: Callable[[], bool], *, reconciled_active_observed: Callable[[], bool] | None = None, ) -> None: deadline = time.monotonic() + 3.0 while not observed(): if reconciled_active_observed is not None and reconciled_active_observed(): return None if time.monotonic() >= deadline: raise TimeoutError("actual worker checkpoint was not released") threading.Event().wait(0.005) return None def adopt_reconciled_scanning(self, **_: object) -> None: self.stage = "scanning" def maintain_active_until_stop_requested(self, observed: Callable[[], bool]) -> None: while not observed(): threading.Event().wait(0.005) self.stage = "stop-requested" def execute_canonical_stop( self, command: object, _permit: object, *, dispatch_guard: Callable[[], None] | None = None, dispatch_admission_deadline_reached: Callable[[], bool] | None = None, ) -> object: self.transport.before_transport_guard.set() assert self.transport.release_transport_guard.wait(3.0) if dispatch_guard is not None: dispatch_guard() assert dispatch_admission_deadline_reached is not None assert dispatch_admission_deadline_reached() is False envelope = OneShotPublishEnvelope.from_modeling_command(command) # type: ignore[arg-type] return self.transport.exchange_batch_once( [envelope], required_response_operation_keys={"modeling:stop"}, ) def maintain_post_stop_until_standby(self) -> None: raise RuntimeError("synthetic standby omitted") def snapshot(self) -> dict[str, object]: return { "dialogue_stage": self.stage, "start_attempted": True, "start_complete": True, "stop_attempted": self.transport.publish_attempts > 0, "stop_complete": False, "automatic_retry": False, } def _wait_control_state( session: InteractiveApplicationControlSession, expected: set[str], ) -> dict[str, object]: deadline = time.monotonic() + 3.0 while time.monotonic() < deadline: snapshot = session.snapshot() if str(snapshot.get("state")) in expected: return snapshot threading.Event().wait(0.005) raise AssertionError(f"control did not reach {expected}: {session.snapshot()}") def _install_actual_worker_recovered_stop_fixture( service: XgridsK1CompatibilityService, runtime: FakeVisualizationRuntime, monkeypatch: pytest.MonkeyPatch, ) -> SimpleNamespace: binding = _seed_supervised_connection( service, transport_ref="actual-worker-transport", logical_device_id="actual-worker-device", with_control=False, ) route_available = {"value": True} monkeypatch.setattr( service, "_sample_host_path", lambda _target, **_kwargs: ( _direct_host_path(binding.target_ipv4) if route_available["value"] else HostPathProbeResult( available=False, fingerprint=None, interface=None, source_ipv4=None, route_class="unavailable", reason_code="router-link-lost", ) ), ) identity = PhysicalCommandIdentity( vendor_device_id_sha256=hashlib.sha256(b"actual-worker-device").hexdigest(), device_serial_sha256=hashlib.sha256(b"ACTUAL-WORKER-SERIAL").hexdigest(), ) old_connection = PhysicalCommandConnectionBinding( intent_id="old-active-intent", transport_ref=binding.transport_ref, connection_mode=binding.connection_mode, target_ipv4=binding.target_ipv4, target_port=binding.target_port, host_path_epoch=binding.host_path_epoch, control_session_id="old-active-control", producer_generation=1, ) def physical_status(state: str, observed: str) -> PhysicalCommandStatusEvidence: scanning = state == "scanning" return PhysicalCommandStatusEvidence( source="live-control-session", vendor_device_id_sha256=identity.vendor_device_id_sha256, device_serial_sha256=identity.device_serial_sha256, control_session_id=old_connection.control_session_id, host_path_epoch=old_connection.host_path_epoch, producer_generation=old_connection.producer_generation, session_state=state, # type: ignore[arg-type] session_state_code=302 if scanning else 300, project_bound=scanning, project_id_sha256="a" * 64 if scanning else None, init_ready=scanning, status_message_sha256=hashlib.sha256(observed.encode()).hexdigest(), mqtt_retained=False, observed_at_utc=observed, ) ledger = service._physical_command_ledger # noqa: SLF001 start_operation_id = "op-00000000-0000-4000-8000-000000001420" acquisition_id = "acq-actual-worker-stop-race" ledger.prepare( operation_id=start_operation_id, parent_operation_id=None, acquisition_id=acquisition_id, action="start", identity=identity, connection=old_connection, compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, payload_sha256="1" * 64, baseline_status=physical_status("ready", "2026-08-12T09:00:01.000Z"), ) ledger.mark_dispatching(start_operation_id) ledger.mark_observing(start_operation_id, publish_call_returned=True, packet_id=81) ledger.mark_qos2_completed(start_operation_id, packet_id=81) ledger.record_application_response( start_operation_id, PhysicalCommandApplicationResponse( operation_id=start_operation_id, action="start", control_session_id=old_connection.control_session_id, host_path_epoch=old_connection.host_path_epoch, producer_generation=old_connection.producer_generation, result_code=PHYSICAL_COMMAND_APPLICATION_SUCCESS_CODE, success=True, payload_sha256="2" * 64, observed_at_utc="2026-08-12T09:00:02.000Z", ), ) ledger.record_status_observation( start_operation_id, physical_status("scanning", "2026-08-12T09:00:03.000Z"), ) ledger.resolve(start_operation_id, resolution="start-active-observed") transport = _ActualWorkerStopRaceTransport() monkeypatch.setattr( session_module, "PhysicalAcceptanceDialogueExecutor", _ActualWorkerStopRaceExecutor, ) coordinator = service._physical_command_coordinator # noqa: SLF001 control = InteractiveApplicationControlSession( FakeApplicationAuthorityLoader(), transport_factory=lambda _host: transport, # type: ignore[arg-type] connection_path_validator=service._validate_application_connection_path, # noqa: SLF001 connection_binding_validator=service._validate_application_connection_binding, # noqa: SLF001 connection_dispatch_lease=service._acquire_application_dispatch_lease, # noqa: SLF001 physical_command_coordinator=coordinator, ) service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 control.open( host=binding.target_ipv4, timezone_name="Europe/Moscow", connection_binding=binding, inspection_only=True, ) ready = _wait_control_state(control, {"connection-ready"}) verified = ready["verified_control"] assert isinstance(verified, dict) coordinator.device_status( ApplicationMqttDeviceStatusEvidence( vendor_device_id_sha256=identity.vendor_device_id_sha256, device_serial_sha256=identity.device_serial_sha256, session_state="scanning", session_state_code=MODELING_STATE_BASE + 302, project_bound=True, project_id_sha256="a" * 64, init_ready=True, status_message_sha256="3" * 64, mqtt_retained=False, observed_at_utc="2026-08-12T09:00:04.000Z", ) ) reconciliation_id = "actual-worker-rebind" reconciled = coordinator.reconcile_resolved_active(reconciliation_id=reconciliation_id) control.adopt_reconciled_scanning( reconciliation_id=reconciliation_id, expected_session_generation=ready["session_generation"], # type: ignore[arg-type] expected_state_revision=ready["state_revision"], # type: ignore[arg-type] ) scanning = _wait_control_state(control, {"scanning"}) service._reconcile_connection_supervisor(scanning, runtime.snapshot()) # noqa: SLF001 service._materialize_recovered_physical_stop_acquisition( # noqa: SLF001 reconciliation_id=reconciliation_id, reconciled_record=reconciled, ) stop_operation_id = "op-00000000-0000-4000-8000-000000001421" request = _stop_request( acquisition_id=acquisition_id, operation_id=stop_operation_id, idempotency_key="actual-worker-stop-race", mode="graceful", physical_acceptance=PHYSICAL_ACCEPTANCE, expected_control_session_generation=scanning["session_generation"], expected_control_state_revision=scanning["state_revision"], ) return SimpleNamespace( binding=binding, route_available=route_available, ledger=ledger, coordinator=coordinator, control=control, transport=transport, request=request, stop_operation_id=stop_operation_id, ) def test_capture_only_rejects_real_worker_queued_before_prepared_dispatch( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_actual_worker_recovered_stop_fixture( service, runtime, monkeypatch, ) service.stop_acquisition(fixture.request) assert fixture.transport.before_transport_guard.wait(3.0) before_operations = tuple(service._operations.snapshot()) # noqa: SLF001 before_acquisition = service._acquisition # noqa: SLF001 with pytest.raises( facade_module.LocalAcquisitionLifecycleError, match="ещё владеет PREPARED STOP", ) as raised: service.stop_acquisition( _stop_request( acquisition_id=fixture.request.acquisition_id, operation_id="op-00000000-0000-4000-8000-000000001458", mode="capture-only", ) ) assert raised.value.reason_code == "acquisition-stop-worker-retirement-pending" assert tuple(service._operations.snapshot()) == before_operations # noqa: SLF001 assert service._acquisition is before_acquisition # noqa: SLF001 assert fixture.transport.fake_client_publish_calls == [] assert fixture.transport.publish_attempts == 0 record = fixture.ledger.snapshot().record assert record is not None and record.stage == "prepared" operation = service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert operation.status == "running" assert operation.error is None assert runtime.stop_calls == 0 # Rejection performs no socket close or cancellation. The one accepted # canonical S0 worker remains the sole owner and may cross its original # publish edge exactly once after the test releases it. fixture.transport.release_transport_guard.set() assert fixture.transport.after_mark_dispatching.wait(3.0) fixture.transport.release_fake_publish.set() _wait_control_state(fixture.control, {"failed"}) assert len(fixture.transport.fake_client_publish_calls) == 1 assert fixture.transport.publish_attempts == 1 record = fixture.ledger.snapshot().record assert record is not None and record.stage in {"dispatching", "observing"} def test_actual_worker_stop_survives_both_loss_reducer_seams_and_publishes_once( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_actual_worker_recovered_stop_fixture( service, runtime, monkeypatch, ) service.stop_acquisition(fixture.request) assert fixture.transport.before_transport_guard.wait(3.0) supervisor = service._connection_supervisor.snapshot() # noqa: SLF001 assert supervisor.intent is not None and supervisor.device_network.target is not None for _ in range(3): assert service._connection_supervisor.observe_endpoint( # noqa: SLF001 target=supervisor.device_network.target, intent_id=supervisor.intent.intent_id, host_path_epoch=supervisor.host_path.epoch, reachable=False, reason_code="transient-control-port-negative", ) retained = service.state() assert retained["selected_device_id"] == fixture.binding.transport_ref assert fixture.transport.fake_client_publish_calls == [] # Restore the exact control-plane proof after the synthetic transient # endpoint negatives; the first seam tested only PREPARED lineage. service._reconcile_connection_supervisor( # noqa: SLF001 fixture.control.snapshot(), runtime.snapshot(), ) refreshed = fixture.control.snapshot() refreshed_verified = refreshed.get("verified_control") assert isinstance(refreshed_verified, dict) supervisor = service._connection_supervisor.snapshot() # noqa: SLF001 assert supervisor.intent is not None and supervisor.device_network.target is not None assert service._connection_supervisor.observe_endpoint( # noqa: SLF001 target=supervisor.device_network.target, intent_id=supervisor.intent.intent_id, host_path_epoch=supervisor.host_path.epoch, reachable=True, ) assert service._connection_supervisor.observe_control_evidence( # noqa: SLF001 VerifiedControlEvidence( intent_id=supervisor.intent.intent_id, transport_ref=fixture.binding.transport_ref, host_path_epoch=supervisor.host_path.epoch, target=supervisor.device_network.target, connection_mode=fixture.binding.connection_mode, logical_device_id="actual-worker-device", compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, control_session_id=str(refreshed_verified["control_session_id"]), control_proof_revision=2, control_proof_source="correlated-application-response", ) ) fixture.transport.release_transport_guard.set() assert fixture.transport.after_mark_dispatching.wait(3.0) # The real worker now owns the facade dispatch gate after mark_dispatching. # A true route loss cannot tear topology out from under fake client.publish. for _ in range(3): _observe_stop_race_route_loss(service) mid_publish = service.state() assert mid_publish["selected_device_id"] == fixture.binding.transport_ref assert fixture.transport.fake_client_publish_calls == [] fixture.transport.release_fake_publish.set() failed = _wait_control_state(fixture.control, {"failed"}) assert failed["state"] == "failed" assert len(fixture.transport.fake_client_publish_calls) == 1 assert fixture.transport.publish_attempts == 1 after_failure = service.state() physical_record = fixture.ledger.snapshot().record assert physical_record is not None assert physical_record.stage in {"dispatching", "observing"} operation = service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert operation.stage_code != "physical-stop-classified-not-dispatched" assert operation.error is None or operation.error.get("side_effect_status") != "none" assert after_failure["physical_command"]["record"]["stage"] in { "dispatching", "observing", } def test_actual_worker_real_route_loss_fails_before_publish_and_settles_none( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_actual_worker_recovered_stop_fixture( service, runtime, monkeypatch, ) service.stop_acquisition(fixture.request) assert fixture.transport.before_transport_guard.wait(3.0) fixture.route_available["value"] = False for _ in range(3): _observe_stop_race_route_loss(service) retained = service.state() assert retained["selected_device_id"] == fixture.binding.transport_ref fixture.transport.release_transport_guard.set() failed = _wait_control_state(fixture.control, {"failed"}) assert failed["failure"]["reason_code"] == "application-connection-binding-lost" # type: ignore[index] assert fixture.transport.fake_client_publish_calls == [] assert fixture.transport.publish_attempts == 0 settled = service.state() operation = service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert operation.status == "failed" assert operation.stage_code == "physical-stop-classified-not-dispatched" assert operation.error is not None assert operation.error["side_effect_status"] == "none" assert operation.error["physical_command_sent"] is False assert settled["selected_device_id"] is None @pytest.mark.parametrize( ("durable_start_resolved", "expected_side_effect_status"), [(False, "unknown"), (True, "succeeded")], ) @pytest.mark.parametrize("coincident_local_error", ["none", "camera", "runtime"]) def test_plugin_start_requires_composite_active_proof_and_fails_closed_on_control_fault( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, durable_start_resolved: bool, expected_side_effect_status: str, coincident_local_error: str, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) control = FakeInteractiveControlSession() service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 binding = _seed_supervised_connection(service) service._compatibility_attestation = ATTESTATION.model_dump(mode="json") # noqa: SLF001 prepared = service.prepare_acquisition( _prepare_request( project_name="START_GATE", host=binding.target_ipv4, compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] pre_pcl_state = service.start_acquisition( _start_request( acquisition_id=acquisition_id, physical_acceptance=PHYSICAL_ACCEPTANCE, ) ) pre_pcl_camera_streams = [ stream for stream in pre_pcl_state["sensor_catalog"]["streams"] if stream.get("semantic_channel_id") == "camera.preview.live" ] assert pre_pcl_state["camera_preview"]["active_source_id"] is None assert pre_pcl_state["camera_preview"]["delivery"] is None assert pre_pcl_state["camera_preview"]["activation_admission"]["state"] == ( "waiting-for-first-authoritative-pcl" ) assert all(stream["activation"]["selected"] is False for stream in pre_pcl_camera_streams) assert all(stream["activation"]["controllable"] is False for stream in pre_pcl_camera_streams) start_operation_id = service._acquisition_start_operation_id # noqa: SLF001 assert isinstance(start_operation_id, str) physical_proof = _exact_start_physical_proof( operation_id=start_operation_id, acquisition_id=acquisition_id, binding=binding, resolved=durable_start_resolved, ) monkeypatch.setattr( service._physical_command_coordinator, # noqa: SLF001 "snapshot", lambda: physical_proof, ) # The live stream can begin during SCAN_STARTING. Neither frames alone nor # even a durable edge observed after this browser reduction is enough while # the current canonical control owner is not SCANNING/can_stop. control.state = "initializing" runtime.mark_ready() runtime.pcl_frames = 30 initializing = service.state() assert initializing["acquisition"]["state"] == "awaiting_external_start" assert initializing["last_operation"]["status"] == "running" original_control_snapshot = control.snapshot def failed_control_snapshot() -> dict[str, object]: snapshot = original_control_snapshot() snapshot["outcome_unknown"] = True snapshot["failure"] = { "code": "ApplicationControlDeviceFault", "reason_code": "device_status_fault", "failed_phase": "initializing", "modeling_command_attempted": True, "safe_to_retry": False, } snapshot["transport"] = { "latest_system_error_code": 0x32040133, "latest_system_error_state": "algorithm_error", } return snapshot if coincident_local_error == "camera": original_camera_snapshot = service.camera_preview.snapshot def failed_camera_snapshot() -> dict[str, Any]: return { **original_camera_snapshot(), "phase": "error", "recording": {"active": True}, "error": {"code": "coincident-camera-fault"}, } monkeypatch.setattr(service.camera_preview, "snapshot", failed_camera_snapshot) elif coincident_local_error == "runtime": runtime.phase = "error" monkeypatch.setattr(control, "snapshot", failed_control_snapshot) control.state = "failed" failed = service.state() start_operation = next( operation for operation in failed["operations"] if operation["operation_id"] == start_operation_id ) assert failed["acquisition"]["state"] == "failed" assert failed["acquisition"]["cleanup_pending"] is True assert failed["source_mode"] == "live" assert start_operation["status"] == "failed" assert start_operation["stage_code"] == "device-start-outcome-unknown" assert start_operation["error"]["safe_to_retry"] is False assert start_operation["error"]["side_effect_status"] == (expected_side_effect_status) assert start_operation["error"]["automatic_replay_allowed"] is False assert runtime.stop_calls == 0 assert control.stop_calls == 0 runtime.pcl_frames += 1 still_failed = service.state() repeated_start_operation = next( operation for operation in still_failed["operations"] if operation["operation_id"] == start_operation_id ) assert still_failed["acquisition"]["state"] == "failed" assert still_failed["acquisition"]["cleanup_pending"] is True assert still_failed["source_mode"] == "live" assert repeated_start_operation == start_operation assert runtime.stop_calls == 0 assert control.stop_calls == 0 locally_stopped = service.stop_acquisition( _stop_request(acquisition_id=acquisition_id, mode="capture-only") ) assert locally_stopped["source_mode"] == "idle" assert locally_stopped["acquisition"]["cleanup_pending"] is False assert locally_stopped["last_operation"]["result"]["device_stop"] == "unknown" assert runtime.stop_calls == 1 assert control.stop_calls == 0 @pytest.mark.parametrize( ("durable_start_resolved", "expected_side_effect_status"), [(False, "unknown"), (True, "succeeded")], ) @pytest.mark.parametrize("local_error", ["camera", "runtime"]) def test_plugin_start_local_failure_preserves_post_checkpoint_physical_outcome( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, durable_start_resolved: bool, expected_side_effect_status: str, local_error: str, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) control = FakeInteractiveControlSession() service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 binding = _seed_supervised_connection(service) service._compatibility_attestation = ATTESTATION.model_dump(mode="json") # noqa: SLF001 prepared = service.prepare_acquisition( _prepare_request( project_name="START_LOCAL_FAILURE", host=binding.target_ipv4, compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] pre_pcl_state = service.start_acquisition( _start_request( acquisition_id=acquisition_id, physical_acceptance=PHYSICAL_ACCEPTANCE, ) ) pre_pcl_camera_streams = [ stream for stream in pre_pcl_state["sensor_catalog"]["streams"] if stream.get("semantic_channel_id") == "camera.preview.live" ] assert pre_pcl_state["camera_preview"]["active_source_id"] is None assert pre_pcl_state["camera_preview"]["delivery"] is None assert pre_pcl_state["camera_preview"]["activation_admission"]["state"] == ( "waiting-for-first-authoritative-pcl" ) assert all(stream["activation"]["selected"] is False for stream in pre_pcl_camera_streams) assert all(stream["activation"]["controllable"] is False for stream in pre_pcl_camera_streams) start_operation_id = service._acquisition_start_operation_id # noqa: SLF001 assert isinstance(start_operation_id, str) physical_proof = _exact_start_physical_proof( operation_id=start_operation_id, acquisition_id=acquisition_id, binding=binding, resolved=durable_start_resolved, ) monkeypatch.setattr( service._physical_command_coordinator, # noqa: SLF001 "snapshot", lambda: physical_proof, ) runtime.mark_ready() awaiting = service.state() assert awaiting["acquisition"]["state"] == "awaiting_external_start" assert awaiting["last_operation"]["status"] == "running" if local_error == "camera": original_camera_snapshot = service.camera_preview.snapshot def failed_camera_snapshot() -> dict[str, Any]: return { **original_camera_snapshot(), "phase": "error", "recording": {"active": True}, "error": {"code": "camera-failed-before-local-start-acceptance"}, } monkeypatch.setattr(service.camera_preview, "snapshot", failed_camera_snapshot) else: runtime.phase = "error" failed = service.state() start_operation = next( operation for operation in failed["operations"] if operation["operation_id"] == start_operation_id ) assert failed["acquisition"]["state"] == "failed" assert failed["acquisition"]["cleanup_pending"] is False assert failed["source_mode"] == "idle" assert start_operation["status"] == "failed" assert start_operation["stage_code"] == "runtime-failed" assert start_operation["error"]["safe_to_retry"] is False assert start_operation["error"]["side_effect_status"] == (expected_side_effect_status) assert start_operation["error"]["automatic_replay_allowed"] is False assert runtime.stop_calls == 1 assert control.stop_calls == 0 @pytest.mark.parametrize("local_failure", ["none", "cleanup", "camera"]) def test_durable_stop_ready_auto_cleans_local_receiver_after_control_loss( tmp_path: Path, local_failure: str, monkeypatch: pytest.MonkeyPatch, ) -> None: """A resolved exact STOP survives Wi-Fi/control retirement as completion truth.""" service, runtime = service_with_fake_runtime(tmp_path) control = FakeInteractiveControlSession() service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 binding = _seed_supervised_connection( service, connection_mode="bridge", transport_ref="k1-stop-ready", ) control.verified_control = _verified_control_for_binding( binding, control_session_id="stop-ready-control", ) prepared = service.prepare_acquisition( _prepare_request( project_name="STOP_READY", host=binding.target_ipv4, compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] service.start_acquisition( _start_request( acquisition_id=acquisition_id, physical_acceptance=PHYSICAL_ACCEPTANCE, ) ) start_operation_id = service._acquisition_start_operation_id # noqa: SLF001 assert isinstance(start_operation_id, str) identity = PhysicalCommandIdentity( vendor_device_id_sha256="a" * 64, device_serial_sha256="b" * 64, ) physical_connection = PhysicalCommandConnectionBinding( intent_id=binding.intent_id, transport_ref=binding.transport_ref, connection_mode="bridge", target_ipv4=binding.target_ipv4, target_port=binding.target_port, host_path_epoch=binding.host_path_epoch, control_session_id="stop-ready-control", producer_generation=1, ) def status( session_state: str, *, observed_at_utc: str, ) -> PhysicalCommandStatusEvidence: scanning = session_state == "scanning" return PhysicalCommandStatusEvidence( source="live-control-session", vendor_device_id_sha256=identity.vendor_device_id_sha256, device_serial_sha256=identity.device_serial_sha256, control_session_id=physical_connection.control_session_id, host_path_epoch=physical_connection.host_path_epoch, producer_generation=physical_connection.producer_generation, session_state=session_state, # type: ignore[arg-type] session_state_code=302 if scanning else 300, project_bound=scanning, project_id_sha256="c" * 64 if scanning else None, init_ready=scanning, status_message_sha256=hashlib.sha256( f"{session_state}:{observed_at_utc}".encode() ).hexdigest(), mqtt_retained=False, observed_at_utc=observed_at_utc, ) ledger = service._physical_command_ledger # noqa: SLF001 ledger.prepare( operation_id=start_operation_id, parent_operation_id=None, acquisition_id=acquisition_id, action="start", identity=identity, connection=physical_connection, compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, payload_sha256="1" * 64, baseline_status=status( "ready", observed_at_utc="2026-08-10T08:01:30.000Z", ), ) ledger.mark_dispatching(start_operation_id) ledger.mark_observing( start_operation_id, publish_call_returned=True, packet_id=94, ) ledger.mark_qos2_completed(start_operation_id, packet_id=94) ledger.record_application_response( start_operation_id, PhysicalCommandApplicationResponse( operation_id=start_operation_id, action="start", control_session_id=physical_connection.control_session_id, host_path_epoch=physical_connection.host_path_epoch, producer_generation=physical_connection.producer_generation, result_code=PHYSICAL_COMMAND_APPLICATION_SUCCESS_CODE, success=True, payload_sha256="2" * 64, observed_at_utc="2026-08-10T08:01:31.000Z", ), ) ledger.record_status_observation( start_operation_id, status("scanning", observed_at_utc="2026-08-10T08:01:32.000Z"), ) ledger.resolve(start_operation_id, resolution="start-active-observed") runtime.mark_ready() runtime.pcl_frames = 1 assert service.state()["acquisition"]["state"] == "acquiring" # Match an acquisition that resumed through the exact read-only recovery # owner before the operator requested the one canonical STOP. active_start_record = ledger.snapshot().record assert active_start_record is not None recovery_lineage = facade_module._ActiveStreamRecoveryLineage( # noqa: SLF001 recovery_generation=service._active_stream_recovery_generation, # noqa: SLF001 snapshot_runtime_id=service._snapshot_runtime_id, # noqa: SLF001 acquisition_id=acquisition_id, device_id=service._device_id, # type: ignore[arg-type] # noqa: SLF001 device_session_id=service._device_session_id, # type: ignore[arg-type] # noqa: SLF001 evidence_session_id=service._acquisition_out_dir.name, # type: ignore[union-attr] # noqa: SLF001 runtime_producer_generation=runtime.producer_generation, start_operation_id=start_operation_id, physical_operation_id=start_operation_id, physical_revision=active_start_record.revision, intent_id=binding.intent_id, transport_ref=binding.transport_ref, connection_mode="bridge", target_ipv4=binding.target_ipv4, target_port=binding.target_port, ) with service._lock: # noqa: SLF001 service._active_stream_recovery_lineage = recovery_lineage # noqa: SLF001 service._active_stream_recovery_state = "recovered" # noqa: SLF001 service._active_stream_recovery_attempt = 7 # noqa: SLF001 runtime.recovery_state = "recovered" runtime.recovery_attempt = 7 stop_operation_id = "op-00000000-0000-4000-8000-000000001299" stop_request = _stop_request( acquisition_id=acquisition_id, operation_id=stop_operation_id, mode="graceful", physical_acceptance=PHYSICAL_ACCEPTANCE, ) stopping = service.stop_acquisition(stop_request) assert stopping["acquisition"]["state"] == "awaiting_external_stop" assert stopping["last_operation"]["status"] == "running" assert control.stop_calls == 1 assert runtime.source_mode == "live" # Wi-Fi/control disappears after the one STOP request. Model the exact # production ordering: state() begins with a pending local retirement, # turns the completed ephemeral control owner into idle, and only then # reduces the durable READY edge. control.state = "completed" service._pending_local_control_retirement = True # noqa: SLF001 ledger.prepare( operation_id=stop_operation_id, parent_operation_id=start_operation_id, acquisition_id=acquisition_id, action="stop", identity=identity, connection=physical_connection, compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, payload_sha256="d" * 64, baseline_status=status( "scanning", observed_at_utc="2026-08-10T08:01:40.000Z", ), ) ledger.mark_dispatching(stop_operation_id) ledger.mark_observing( stop_operation_id, publish_call_returned=True, packet_id=95, ) ledger.mark_qos2_completed(stop_operation_id, packet_id=95) ledger.record_application_response( stop_operation_id, PhysicalCommandApplicationResponse( operation_id=stop_operation_id, action="stop", control_session_id=physical_connection.control_session_id, host_path_epoch=physical_connection.host_path_epoch, producer_generation=physical_connection.producer_generation, result_code=PHYSICAL_COMMAND_APPLICATION_SUCCESS_CODE, success=True, payload_sha256="e" * 64, observed_at_utc="2026-08-10T08:01:41.000Z", ), ) ledger.record_status_observation( stop_operation_id, status("ready", observed_at_utc="2026-08-10T08:01:44.000Z"), ) ledger.resolve(stop_operation_id, resolution="stop-standby-observed") unintended_edges: list[str] = [] async def forbidden_device_edge(*_args: object, **_kwargs: object) -> object: unintended_edges.append("device-or-network-io") raise AssertionError("durable STOP READY reduction must be local-only") monkeypatch.setattr(facade_module, "scan", forbidden_device_edge) monkeypatch.setattr(facade_module, "read_wifi_status_once", forbidden_device_edge) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_device_edge) if local_failure == "cleanup": runtime.stop_error = RuntimeError("synthetic local cleanup failure after READY") elif local_failure == "camera": original_camera_snapshot = service.camera_preview.snapshot def failed_camera_snapshot() -> dict[str, Any]: snapshot = original_camera_snapshot() return { **snapshot, "phase": "error", "recording": {"active": True}, "error": {"code": "synthetic-camera-producer-failed"}, } monkeypatch.setattr(service.camera_preview, "snapshot", failed_camera_snapshot) completed = service.state() operation = next( item for item in completed["operations"] if item["operation_id"] == stop_operation_id ) assert completed["application_control_session"]["state"] == "idle" assert completed["physical_command"]["record"]["resolution"] == ("stop-standby-observed") if local_failure == "cleanup": assert completed["acquisition"]["state"] == "failed" assert completed["acquisition"]["cleanup_pending"] is True assert operation["status"] == "failed" assert operation["stage_code"] == "local-finalization-failed" assert operation["error"] == { "category": "stream", "code": "local-finalization-failed-after-device-standby", "retryable": True, "safe_to_retry": True, "side_effect_status": "succeeded", } assert completed["source_mode"] == "live" assert completed["connection_policy"]["actions"]["scan-ble"]["allowed"] is False # Local cleanup alone is retried by polling. The physical STOP remains # terminal and is never published again. runtime.stop_error = None completed = service.state() operation = next( item for item in completed["operations"] if item["operation_id"] == stop_operation_id ) assert completed["acquisition"]["state"] == "failed" assert completed["acquisition"]["cleanup_pending"] is False assert operation["status"] == "failed" assert operation["stage_code"] == "local-finalization-failed" assert runtime.stop_calls == 2 elif local_failure == "camera": assert completed["acquisition"]["state"] == "failed" assert completed["acquisition"]["cleanup_pending"] is False assert completed["acquisition"]["result"] == { "receiver_stopped": True, "device_state": "ready", "device_stop": "protocol-confirmed", "camera_failure_code": "synthetic-camera-producer-failed", } assert operation["status"] == "failed" assert operation["stage_code"] == "local-finalization-failed" assert operation["error"]["side_effect_status"] == "succeeded" assert runtime.stop_calls == 1 else: assert completed["acquisition"]["state"] == "completed" assert completed["acquisition"]["cleanup_pending"] is False assert completed["acquisition"]["result"] == { "receiver_stopped": True, "device_state": "ready", "device_stop": "protocol-confirmed", } assert operation["status"] == "succeeded" assert operation["stage_code"] == "device-standby-confirmed" assert runtime.stop_calls == 1 assert completed["source_mode"] == "idle" assert completed["live_perception_shadow"]["active"] is False assert completed["connection_policy"]["actions"]["scan-ble"]["allowed"] is True assert unintended_edges == [] assert control.stop_calls == 1 if local_failure != "cleanup": assert completed["connection_recovery"]["state"] == "inactive" assert completed["connection_recovery"]["automatic_read_only_rebind"] is False assert service._active_stream_recovery_lineage is None # noqa: SLF001 # Polling the same durable proof is a pure idempotent read: no second # local teardown and, critically, no second physical STOP. stop_call_count = runtime.stop_calls repeated = service.state() repeated_operation = next( item for item in repeated["operations"] if item["operation_id"] == stop_operation_id ) assert repeated_operation["status"] == operation["status"] assert repeated["acquisition"]["state"] == completed["acquisition"]["state"] assert repeated["connection_policy"]["actions"]["scan-ble"]["allowed"] is True assert unintended_edges == [] assert control.stop_calls == 1 assert runtime.stop_calls == stop_call_count # A process restart retains only the resolved durable edge. There is no # process-local receiver to recover and no physical action to replay. restarted, restarted_runtime = service_with_fake_runtime(tmp_path) restarted_state = restarted.state() assert restarted_state["physical_command"]["record"]["operation_id"] == (stop_operation_id) assert restarted_state["physical_command"]["record"]["resolution"] == ("stop-standby-observed") assert restarted_state["acquisition"] is None assert restarted_state["source_mode"] == "idle" assert restarted_state["connection_policy"]["actions"]["scan-ble"]["allowed"] is True assert restarted_runtime.stop_calls == 0 @pytest.mark.parametrize( "mismatch", [ "operation", "acquisition", "response-operation", "retained-ready", "bound-ready", "initialized-ready", "missing-qos2", ], ) def test_durable_stop_ready_rejects_nonmatching_or_noncanonical_proof( mismatch: str, ) -> None: stop_operation_id = "op-00000000-0000-4000-8000-000000001399" acquisition_id = "acquisition-stop-ready-proof" proof: dict[str, Any] = { "status": "resolved", "requires_reconciliation": False, "record": { "operation_id": stop_operation_id, "acquisition_id": acquisition_id, "action": "stop", "stage": "resolved", "resolution": "stop-standby-observed", "publish_call_returned": True, "qos2_completed": True, "packet_id": 91, "application_response": { "operation_id": stop_operation_id, "action": "stop", "success": True, }, "last_status": { "session_state": "ready", "project_bound": False, "init_ready": False, "mqtt_retained": False, }, }, } record = proof["record"] if mismatch == "operation": record["operation_id"] = "different-stop-operation" elif mismatch == "acquisition": record["acquisition_id"] = "different-acquisition" elif mismatch == "response-operation": record["application_response"]["operation_id"] = "different-stop-operation" elif mismatch == "retained-ready": record["last_status"]["mqtt_retained"] = True elif mismatch == "bound-ready": record["last_status"]["project_bound"] = True elif mismatch == "initialized-ready": record["last_status"]["init_ready"] = True elif mismatch == "missing-qos2": record["qos2_completed"] = False assert ( XgridsK1CompatibilityService._matching_stop_standby_confirmed( # noqa: SLF001 proof, acquisition_id=acquisition_id, stop_operation_id=stop_operation_id, ) is False ) @pytest.mark.parametrize( "mismatch", ["operation", "acquisition", "response-operation", "response-failed", "ready", "stopping"], ) def test_stop_timeout_matcher_rejects_wrong_lineage_or_terminal_status( mismatch: str, ) -> None: stop_operation_id = "op-00000000-0000-4000-8000-000000001489" acquisition_id = "acquisition-stop-timeout-proof" proof: dict[str, Any] = { "status": "unresolved", "requires_reconciliation": True, "record": { "operation_id": stop_operation_id, "acquisition_id": acquisition_id, "action": "stop", "stage": "observing", "resolution": None, # An exact application response may precede or outlive the local # QoS2 callback. Timeout cleanup is local-only in either case. "publish_call_returned": None, "qos2_completed": False, "packet_id": None, "application_response": { "operation_id": stop_operation_id, "action": "stop", "success": True, "observed_at_utc": "2026-08-10T08:10:02.000Z", }, "last_status": None, }, } record = proof["record"] if mismatch == "operation": record["operation_id"] = "different-stop-operation" elif mismatch == "acquisition": record["acquisition_id"] = "different-acquisition" elif mismatch == "response-operation": record["application_response"]["operation_id"] = "different-stop-operation" elif mismatch == "response-failed": record["application_response"]["success"] = False elif mismatch in {"ready", "stopping"}: record["last_status"] = { "session_state": "ready" if mismatch == "ready" else "scan_stopping" } assert ( XgridsK1CompatibilityService._matching_stop_response_without_terminal_status( # noqa: SLF001 proof, acquisition_id=acquisition_id, stop_operation_id=stop_operation_id, ) is False ) def test_stop_timeout_matcher_accepts_exact_response_without_qos2_callback() -> None: stop_operation_id = "op-00000000-0000-4000-8000-000000001488" acquisition_id = "acquisition-stop-timeout-no-qos" proof = { "status": "unresolved", "requires_reconciliation": True, "record": { "operation_id": stop_operation_id, "acquisition_id": acquisition_id, "action": "stop", "stage": "observing", "resolution": None, "publish_call_returned": None, "qos2_completed": False, "packet_id": None, "application_response": { "operation_id": stop_operation_id, "action": "stop", "success": True, "observed_at_utc": "2026-08-10T08:10:02.000Z", }, "last_status": None, }, } assert XgridsK1CompatibilityService._matching_stop_response_without_terminal_status( # noqa: SLF001 proof, acquisition_id=acquisition_id, stop_operation_id=stop_operation_id, ) def _stop_response_without_terminal_status_fixture( tmp_path: Path, *, qos2_completed: bool = True, ) -> SimpleNamespace: clock_value = [datetime(2026, 8, 10, 8, 10, tzinfo=UTC)] service, runtime = service_with_fake_runtime(tmp_path) service._operations = OperationJournal(clock=lambda: clock_value[0]) # noqa: SLF001 control = FakeInteractiveControlSession() service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 binding = _seed_supervised_connection( service, connection_mode="bridge", transport_ref="k1-stop-timeout", ) control.verified_control = _verified_control_for_binding( binding, control_session_id="stop-timeout-control", ) prepared = service.prepare_acquisition( _prepare_request( project_name="STOP_TIMEOUT", host=binding.target_ipv4, compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] service.start_acquisition( _start_request( acquisition_id=acquisition_id, physical_acceptance=PHYSICAL_ACCEPTANCE, ) ) start_operation_id = service._acquisition_start_operation_id # noqa: SLF001 assert isinstance(start_operation_id, str) identity = PhysicalCommandIdentity( vendor_device_id_sha256="4" * 64, device_serial_sha256="5" * 64, ) physical_connection = PhysicalCommandConnectionBinding( intent_id=binding.intent_id, transport_ref=binding.transport_ref, connection_mode="bridge", target_ipv4=binding.target_ipv4, target_port=binding.target_port, host_path_epoch=binding.host_path_epoch, control_session_id="stop-timeout-control", producer_generation=1, ) def status( session_state: str, *, observed_at_utc: str, ) -> PhysicalCommandStatusEvidence: scanning = session_state == "scanning" return PhysicalCommandStatusEvidence( source="live-control-session", vendor_device_id_sha256=identity.vendor_device_id_sha256, device_serial_sha256=identity.device_serial_sha256, control_session_id=physical_connection.control_session_id, host_path_epoch=physical_connection.host_path_epoch, producer_generation=physical_connection.producer_generation, session_state=session_state, # type: ignore[arg-type] session_state_code=302 if scanning else 300, project_bound=scanning, project_id_sha256="6" * 64 if scanning else None, init_ready=scanning, status_message_sha256=hashlib.sha256( f"{session_state}:{observed_at_utc}".encode() ).hexdigest(), mqtt_retained=False, observed_at_utc=observed_at_utc, ) ledger = service._physical_command_ledger # noqa: SLF001 ledger.prepare( operation_id=start_operation_id, parent_operation_id=None, acquisition_id=acquisition_id, action="start", identity=identity, connection=physical_connection, compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, payload_sha256="7" * 64, baseline_status=status( "ready", observed_at_utc="2026-08-10T08:09:55.000Z", ), ) ledger.mark_dispatching(start_operation_id) ledger.mark_observing( start_operation_id, publish_call_returned=True, packet_id=81, ) ledger.mark_qos2_completed(start_operation_id, packet_id=81) ledger.record_application_response( start_operation_id, PhysicalCommandApplicationResponse( operation_id=start_operation_id, action="start", control_session_id=physical_connection.control_session_id, host_path_epoch=physical_connection.host_path_epoch, producer_generation=physical_connection.producer_generation, result_code=PHYSICAL_COMMAND_APPLICATION_SUCCESS_CODE, success=True, payload_sha256="8" * 64, observed_at_utc="2026-08-10T08:09:56.000Z", ), ) ledger.record_status_observation( start_operation_id, status("scanning", observed_at_utc="2026-08-10T08:09:57.000Z"), ) ledger.resolve(start_operation_id, resolution="start-active-observed") runtime.mark_ready() runtime.pcl_frames = 1 assert service.state()["acquisition"]["state"] == "acquiring" stop_operation_id = "op-00000000-0000-4000-8000-000000001499" stop_request = _stop_request( acquisition_id=acquisition_id, operation_id=stop_operation_id, deadline_seconds=10.0, mode="graceful", physical_acceptance=PHYSICAL_ACCEPTANCE, ) stopping = service.stop_acquisition(stop_request) assert stopping["acquisition"]["state"] == "awaiting_external_stop" assert stopping["last_operation"]["status"] == "running" ledger.prepare( operation_id=stop_operation_id, parent_operation_id=start_operation_id, acquisition_id=acquisition_id, action="stop", identity=identity, connection=physical_connection, compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, payload_sha256="9" * 64, baseline_status=status( "scanning", observed_at_utc="2026-08-10T08:10:00.000Z", ), ) ledger.mark_dispatching(stop_operation_id) if qos2_completed: ledger.mark_observing( stop_operation_id, publish_call_returned=True, packet_id=82, ) ledger.mark_qos2_completed(stop_operation_id, packet_id=82) ledger.record_application_response( stop_operation_id, PhysicalCommandApplicationResponse( operation_id=stop_operation_id, action="stop", control_session_id=physical_connection.control_session_id, host_path_epoch=physical_connection.host_path_epoch, producer_generation=physical_connection.producer_generation, result_code=PHYSICAL_COMMAND_APPLICATION_SUCCESS_CODE, success=True, payload_sha256="a" * 64, observed_at_utc="2026-08-10T08:10:02.000Z", ), ) return SimpleNamespace( service=service, runtime=runtime, control=control, ledger=ledger, clock_value=clock_value, acquisition_id=acquisition_id, stop_operation_id=stop_operation_id, status=status, ) @pytest.mark.parametrize("qos2_completed", [True, False]) def test_stop_success_without_terminal_status_times_out_into_local_only_recovery( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, qos2_completed: bool, ) -> None: fixture = _stop_response_without_terminal_status_fixture( tmp_path, qos2_completed=qos2_completed, ) service = fixture.service runtime = fixture.runtime control = fixture.control operation = service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert operation.deadline_at is not None fixture.clock_value[0] = operation.deadline_at - timedelta(milliseconds=1) before_deadline = service.state() assert before_deadline["acquisition"]["state"] == "awaiting_external_stop" assert service._acquisition_session_lease is not None # noqa: SLF001 assert before_deadline["source_mode"] == "live" assert before_deadline["last_operation"]["status"] == "running" assert runtime.stop_calls == 0 assert control.stop_calls == 1 unintended_edges: list[str] = [] async def forbidden_device_edge(*_args: object, **_kwargs: object) -> object: unintended_edges.append("device-or-network-io") raise AssertionError("STOP timeout recovery must be local-only") monkeypatch.setattr(facade_module, "scan", forbidden_device_edge) monkeypatch.setattr(facade_module, "read_wifi_status_once", forbidden_device_edge) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_device_edge) fixture.clock_value[0] = operation.deadline_at timed_out = service.state() timeout_operation = next( item for item in timed_out["operations"] if item["operation_id"] == fixture.stop_operation_id ) assert timed_out["application_control_session"]["state"] == "idle" assert timed_out["acquisition"]["state"] == "failed" assert timed_out["acquisition"]["cleanup_pending"] is False assert timed_out["acquisition"]["message_code"] == ( "acquisition.stop.accepted_physical_outcome_unknown" ) assert timed_out["acquisition"]["result"] == { "receiver_stopped": True, "device_state": "unknown", "device_stop": "stop-accepted-physical-outcome-unknown", "automatic_replay_allowed": False, } assert timeout_operation["status"] == "timed_out" assert timeout_operation["stage_code"] == ("stop-accepted-physical-outcome-unknown") assert timeout_operation["error"] == { "category": "device", "code": "stop-accepted-physical-outcome-unknown", "retryable": False, "safe_to_retry": False, "side_effect_status": "unknown", "automatic_replay_allowed": False, } assert timed_out["physical_command"]["status"] == "unresolved" assert timed_out["physical_command"]["requires_reconciliation"] is True assert timed_out["physical_command"]["record"]["resolution"] is None assert timed_out["source_mode"] == "idle" assert timed_out["live_perception_shadow"]["active"] is False assert timed_out["connection_policy"]["actions"]["scan-ble"]["allowed"] is True for action in ("provision-fresh-device", "start-acquisition", "stop-acquisition"): assert timed_out["connection_policy"]["actions"][action]["allowed"] is False assert unintended_edges == [] assert runtime.stop_calls == 1 assert control.stop_calls == 1 repeated = service.state() assert repeated["acquisition"]["state"] == "failed" assert repeated["physical_command"]["status"] == "unresolved" assert repeated["connection_policy"]["actions"]["scan-ble"]["allowed"] is True assert unintended_edges == [] assert runtime.stop_calls == 1 assert control.stop_calls == 1 restarted, restarted_runtime = service_with_fake_runtime(tmp_path) restarted_state = restarted.state() assert restarted_state["physical_command"]["status"] == "unresolved" assert restarted_state["physical_command"]["record"]["operation_id"] == ( fixture.stop_operation_id ) assert restarted_state["acquisition"] is None assert restarted_state["connection_policy"]["actions"]["scan-ble"]["allowed"] is True for action in ("provision-fresh-device", "start-acquisition", "stop-acquisition"): assert restarted_state["connection_policy"]["actions"][action]["allowed"] is False assert restarted_runtime.stop_calls == 0 def test_stop_timeout_local_cleanup_failure_retries_only_local_resources( tmp_path: Path, ) -> None: fixture = _stop_response_without_terminal_status_fixture(tmp_path) operation = fixture.service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert operation.deadline_at is not None fixture.clock_value[0] = operation.deadline_at fixture.runtime.stop_error = RuntimeError("synthetic timeout cleanup failure") failed_cleanup = fixture.service.state() failed_operation = next( item for item in failed_cleanup["operations"] if item["operation_id"] == fixture.stop_operation_id ) assert failed_cleanup["acquisition"]["state"] == "failed" assert failed_cleanup["acquisition"]["cleanup_pending"] is True assert failed_cleanup["source_mode"] == "live" assert failed_operation["status"] == "failed" assert failed_operation["stage_code"] == ("local-cleanup-failed-after-stop-outcome-unknown") assert failed_operation["error"]["side_effect_status"] == "unknown" assert failed_operation["error"]["safe_to_retry"] is False assert failed_operation["error"]["automatic_replay_allowed"] is False assert fixture.control.stop_calls == 1 assert fixture.runtime.stop_calls == 1 fixture.runtime.stop_error = None recovered = fixture.service.state() assert recovered["acquisition"]["state"] == "failed" assert recovered["acquisition"]["cleanup_pending"] is False assert recovered["acquisition"]["result"]["receiver_stopped"] is True assert "local_cleanup_retry_pending" not in recovered["acquisition"]["result"] assert recovered["source_mode"] == "idle" assert recovered["physical_command"]["status"] == "unresolved" assert recovered["connection_policy"]["actions"]["scan-ble"]["allowed"] is True assert fixture.control.stop_calls == 1 assert fixture.runtime.stop_calls == 2 repeated = fixture.service.state() assert repeated["acquisition"]["cleanup_pending"] is False assert fixture.control.stop_calls == 1 assert fixture.runtime.stop_calls == 2 def test_stop_response_preserves_precise_unknown_outcome_through_predeadline_loss( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: fixture = _stop_response_without_terminal_status_fixture(tmp_path) operation = fixture.service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert operation.deadline_at is not None original_snapshot = fixture.control.snapshot def failed_control_snapshot() -> dict[str, object]: snapshot = original_snapshot() if fixture.control.state == "failed": snapshot["failure"] = { "reason_code": "mqtt_network_loop_failed", "safe_to_retry": False, "modeling_command_attempted": True, } return snapshot monkeypatch.setattr(fixture.control, "snapshot", failed_control_snapshot) fixture.control.state = "failed" fixture.runtime.phase = "error" fixture.clock_value[0] = operation.deadline_at - timedelta(milliseconds=1) before_deadline = fixture.service.state() stop_operation = next( item for item in before_deadline["operations"] if item["operation_id"] == fixture.stop_operation_id ) assert before_deadline["acquisition"]["state"] == "awaiting_external_stop" assert before_deadline["acquisition"]["message_code"] == ("acquisition.stop.device_stopping") assert stop_operation["status"] == "running" assert before_deadline["physical_command"]["status"] == "unresolved" assert fixture.runtime.stop_calls == 0 assert fixture.control.stop_calls == 1 fixture.clock_value[0] = operation.deadline_at timed_out = fixture.service.state() stop_operation = next( item for item in timed_out["operations"] if item["operation_id"] == fixture.stop_operation_id ) assert timed_out["acquisition"]["message_code"] == ( "acquisition.stop.accepted_physical_outcome_unknown" ) assert stop_operation["status"] == "timed_out" assert stop_operation["stage_code"] == "stop-accepted-physical-outcome-unknown" assert timed_out["source_mode"] == "idle" assert timed_out["physical_command"]["status"] == "unresolved" assert fixture.runtime.stop_calls == 1 assert fixture.control.stop_calls == 1 def test_stop_ready_resolution_wins_when_it_arrives_at_timeout_deadline( tmp_path: Path, ) -> None: fixture = _stop_response_without_terminal_status_fixture(tmp_path) operation = fixture.service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert operation.deadline_at is not None fixture.clock_value[0] = operation.deadline_at fixture.ledger.record_status_observation( fixture.stop_operation_id, fixture.status("ready", observed_at_utc="2026-08-10T08:10:10.000Z"), ) fixture.ledger.resolve( fixture.stop_operation_id, resolution="stop-standby-observed", ) fixture.control.state = "idle" fixture.control.verified_control = None completed = fixture.service.state() completed_operation = next( item for item in completed["operations"] if item["operation_id"] == fixture.stop_operation_id ) assert completed["acquisition"]["state"] == "completed" assert completed["acquisition"]["result"]["device_state"] == "ready" assert completed_operation["status"] == "succeeded" assert completed["physical_command"]["record"]["resolution"] == ("stop-standby-observed") assert fixture.control.stop_calls == 1 assert fixture.runtime.stop_calls == 1 def test_facade_wires_one_physical_command_coordinator_into_control_session( tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) assert ( service._application_control_session._physical_command_coordinator # noqa: SLF001 is service._physical_command_coordinator # noqa: SLF001 ) physical_snapshot = service.state()["physical_command"] assert physical_snapshot["automatic_replay_allowed"] is False assert physical_snapshot["status"] == "empty" @pytest.mark.parametrize( ("stage", "action", "expected_resolution"), [ ( "prepared", "start", [("op-00000000-0000-4000-8000-000000000111", "not-dispatched")], ), ("prepared", "stop", []), ("dispatching", "start", []), ("observing", "start", []), ], ) def test_facade_startup_auto_resolves_only_pre_dispatch_physical_attempt( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, stage: str, action: str, expected_resolution: list[tuple[str, str]], ) -> None: operation_id = "op-00000000-0000-4000-8000-000000000111" class StartupLedger: def __init__(self) -> None: self.resolutions: list[tuple[str, str]] = [] def snapshot(self) -> SimpleNamespace: return SimpleNamespace( status="unresolved", record=SimpleNamespace( operation_id=operation_id, stage=stage, action=action, ), ) def resolve(self, candidate: str, *, resolution: str) -> None: self.resolutions.append((candidate, resolution)) ledger = StartupLedger() monkeypatch.setattr(facade_module, "PhysicalCommandLedger", lambda _root: ledger) service = XgridsK1CompatibilityService( tmp_path, host_wifi_association_probe=FakeHostWifiAssociationProbe(), ) assert service._physical_command_ledger is ledger # noqa: SLF001 assert ledger.resolutions == expected_resolution def test_facade_physical_context_chains_stop_to_durable_start_after_transient_id_clears( tmp_path: Path, ) -> None: start_operation_id = "op-00000000-0000-4000-8000-000000000101" stop_operation_id = "op-00000000-0000-4000-8000-000000000102" service, runtime = service_with_fake_runtime(tmp_path) control = FakeInteractiveControlSession() service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 binding = _seed_supervised_connection(service) service._compatibility_attestation = ATTESTATION.model_dump(mode="json") # noqa: SLF001 class FacadeAdmissionLedger: def __init__(self) -> None: self.record: object | None = None self.admission_calls = 0 def require_no_unresolved_attempt(self) -> None: self.admission_calls += 1 def snapshot(self) -> SimpleNamespace: return SimpleNamespace(record=self.record) ledger = FacadeAdmissionLedger() service._physical_command_ledger = ledger # type: ignore[assignment] # noqa: SLF001 prepared = service.prepare_acquisition( _prepare_request( project_name="TEST001", host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] service.start_acquisition( _start_request( acquisition_id=acquisition_id, operation_id=start_operation_id, physical_acceptance=PHYSICAL_ACCEPTANCE, ) ) start_context = control.start_contexts[-1] assert start_context.operation_id == start_operation_id assert start_context.parent_operation_id is None assert start_context.acquisition_id == acquisition_id assert start_context.operator_confirmation_id is None assert start_context.operator_confirmed_at_utc is None ledger.record = SimpleNamespace(operation_id=start_context.operation_id) service._physical_command_coordinator = SimpleNamespace( # type: ignore[assignment] # noqa: SLF001 snapshot=lambda: _exact_start_physical_proof( operation_id=start_operation_id, acquisition_id=acquisition_id, binding=binding, resolved=True, ) ) runtime.mark_ready() runtime.pcl_frames = 1 service.state() assert service._acquisition_start_operation_id is None # noqa: SLF001 service.stop_acquisition( _stop_request( acquisition_id=acquisition_id, operation_id=stop_operation_id, mode="graceful", physical_acceptance=PHYSICAL_ACCEPTANCE, ) ) stop_context = control.stop_contexts[-1] assert stop_context.operation_id == stop_operation_id assert stop_context.parent_operation_id == start_operation_id assert stop_context.acquisition_id == acquisition_id assert stop_context.operator_confirmation_id is None assert stop_context.operator_confirmed_at_utc is None assert ledger.admission_calls == 2 def test_facade_blocks_unresolved_physical_start_before_local_receiver_side_effects( tmp_path: Path, ) -> None: operation_id = "op-00000000-0000-4000-8000-000000000103" service, runtime = service_with_fake_runtime(tmp_path) control = FakeInteractiveControlSession() service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 _seed_supervised_connection(service) service._compatibility_attestation = ATTESTATION.model_dump(mode="json") # noqa: SLF001 class BlockedPhysicalLedger: def require_no_unresolved_attempt(self) -> None: raise PhysicalCommandBlocked("ambiguous previous physical edge") service._physical_command_ledger = BlockedPhysicalLedger() # type: ignore[assignment] # noqa: SLF001 prepared = service.prepare_acquisition( _prepare_request( project_name="TEST001", host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) with pytest.raises(PhysicalCommandBlocked): service.start_acquisition( _start_request( acquisition_id=prepared["acquisition"]["acquisition_id"], operation_id=operation_id, physical_acceptance=PHYSICAL_ACCEPTANCE, ) ) assert runtime.start_calls == [] assert control.start_contexts == [] assert service._operations.get(operation_id).status == "failed" # noqa: SLF001 def test_plugin_commanded_prepare_rejects_stale_binding_before_creating_acquisition( tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) class StaleInteractiveControlSession(FakeInteractiveControlSession): def __init__(self) -> None: super().__init__() self.project_prompt_calls = 0 self.close_calls = 0 def validate_connection_binding(self) -> None: raise ApplicationConnectionBindingLost("test route changed") def open_project_prompt( self, *, expected_session_generation: int | None = None, expected_state_revision: int | None = None, ) -> dict[str, object]: self.project_prompt_calls += 1 return super().open_project_prompt( expected_session_generation=expected_session_generation, expected_state_revision=expected_state_revision, ) def close_prestart(self) -> dict[str, object]: self.close_calls += 1 return super().close_prestart() control = StaleInteractiveControlSession() service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 _seed_supervised_connection(service) service._compatibility_attestation = ATTESTATION.model_dump(mode="json") # noqa: SLF001 with pytest.raises(ApplicationConnectionBindingLost): service.prepare_acquisition( _prepare_request( project_name="TEST001", host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) assert service._acquisition is None # noqa: SLF001 assert control.project_prompt_calls == 0 assert control.close_calls == 1 assert control.state == "closed" def test_workspace_entry_rejects_stale_binding_before_releasing_checkpoint( tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) class StaleWorkspaceControlSession(FakeInteractiveControlSession): def __init__(self) -> None: super().__init__() self.state = "connection-ready" self.enter_calls = 0 self.close_calls = 0 def validate_connection_binding(self) -> None: raise ApplicationConnectionBindingLost("test route changed") def enter_workspace( self, *, expected_session_generation: int | None = None, expected_state_revision: int | None = None, ) -> dict[str, object]: # Production ``InteractiveApplicationControlSession`` owns this # command-bound guard internally. The facade must not duplicate # it ahead of the checkpoint. self.validate_connection_binding() del expected_session_generation, expected_state_revision self.enter_calls += 1 raise AssertionError("stale checkpoint must not be released") def close_prestart(self) -> dict[str, object]: self.close_calls += 1 return super().close_prestart() control = StaleWorkspaceControlSession() service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 _seed_supervised_connection(service) with pytest.raises(ApplicationConnectionBindingLost): service.enter_application_workspace( EnterApplicationWorkspaceRequest( operator_confirmed=True, expected_session_generation=1, expected_state_revision=1, ) ) assert control.enter_calls == 0 assert control.close_calls == 1 assert control.state == "closed" class _BindingValidatingControlSession(FakeInteractiveControlSession): """Test double with the production session's command-bound guards.""" def __init__( self, service: XgridsK1CompatibilityService, binding: ApplicationConnectionBinding, ) -> None: super().__init__(initial_state="idle") self._service = service self._binding = binding self.validation_calls = 0 def validate_connection_binding(self) -> None: self.validation_calls += 1 self._service._validate_application_connection_binding(self._binding) # noqa: SLF001 def enter_workspace( self, *, expected_session_generation: int | None = None, expected_state_revision: int | None = None, ) -> dict[str, object]: self.validate_connection_binding() return super().enter_workspace( expected_session_generation=expected_session_generation, expected_state_revision=expected_state_revision, ) def open_project_prompt( self, *, expected_session_generation: int | None = None, expected_state_revision: int | None = None, ) -> dict[str, object]: self.validate_connection_binding() return super().open_project_prompt( expected_session_generation=expected_session_generation, expected_state_revision=expected_state_revision, ) def request_start( self, *, project_name: str, confirmation: object, command_context: object, preparation_checkpoint_observer: object | None = None, expected_session_generation: int | None = None, expected_state_revision: int | None = None, ) -> dict[str, object]: self.validate_connection_binding() return super().request_start( project_name=project_name, confirmation=confirmation, command_context=command_context, preparation_checkpoint_observer=preparation_checkpoint_observer, expected_session_generation=expected_session_generation, expected_state_revision=expected_state_revision, ) def _install_binding_validating_ready_control( service: XgridsK1CompatibilityService, *, host_path: HostPathProbeResult | None = None, ) -> tuple[ _BindingValidatingControlSession, ApplicationConnectionBinding, dict[str, Any], ]: binding = _seed_supervised_connection( service, connection_mode="bridge", transport_ref="ttl-bound-k1", logical_device_id="ttl-bound-device", host_path=host_path, ) control = _BindingValidatingControlSession(service, binding) control.open(connection_binding=binding) control.verified_control = _verified_control_for_binding( binding, logical_device_id="ttl-bound-device", control_session_id="test-control-ttl-bound-k1", control_proof_revision=2, ) service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 service._reconcile_connection_supervisor( # noqa: SLF001 control.snapshot(), service.runtime.snapshot(), ) service._acquire_application_control_process_lease() # noqa: SLF001 state = service.state() assert state["application_control_session"]["state"] == "connection-ready" return control, binding, state def test_public_commanded_workflow_refreshes_stable_route_before_ttl_reduction( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) monotonic_now = [100.0] suspend_aware_now = [1_000.0] supervisor = service._connection_supervisor # noqa: SLF001 supervisor._monotonic_clock = lambda: monotonic_now[0] # noqa: SLF001 supervisor._suspend_aware_clock = lambda: suspend_aware_now[0] # noqa: SLF001 control, binding, ready = _install_binding_validating_ready_control(service) stable_path = _direct_host_path(binding.target_ipv4) monkeypatch.setattr(service, "_sample_host_path", lambda *_args, **_kwargs: stable_path) target = EndpointTarget(binding.target_ipv4, binding.target_port) def advance_past_fifteen_seconds_with_fresh_endpoint() -> None: monotonic_now[0] += 10.0 suspend_aware_now[0] += 10.0 assert supervisor.observe_endpoint( target=target, intent_id=binding.intent_id, host_path_epoch=binding.host_path_epoch, reachable=True, ) monotonic_now[0] += 5.01 suspend_aware_now[0] += 5.01 advance_past_fifteen_seconds_with_fresh_endpoint() polled = service.state() assert polled["application_control_session"]["state"] == "connection-ready" assert supervisor.snapshot().host_path.epoch == binding.host_path_epoch workspace = service.enter_application_workspace( EnterApplicationWorkspaceRequest( operator_confirmed=True, expected_session_generation=ready["application_control_session"]["session_generation"], expected_state_revision=ready["application_control_session"]["state_revision"], ) ) assert workspace["application_control_session"]["state"] == "workspace-ready" assert supervisor.snapshot().host_path.epoch == binding.host_path_epoch assert control.validation_calls == 1 # Retain a focused regression for the original 15-second reducer ordering # even though the production silence lease now tolerates two monitor # passes. Command-bound sampling must still precede stale reduction for # any reviewed TTL configuration. supervisor._observation_ttl_seconds = 15.0 # noqa: SLF001 advance_past_fifteen_seconds_with_fresh_endpoint() prepared = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host=binding.target_ipv4, compatibility_attestation=ATTESTATION, expected_control_session_generation=workspace["application_control_session"][ "session_generation" ], expected_control_state_revision=workspace["application_control_session"][ "state_revision" ], ) ) assert prepared["application_control_session"]["state"] == "project-ready" assert supervisor.snapshot().host_path.epoch == binding.host_path_epoch assert control.validation_calls == 3 advance_past_fifteen_seconds_with_fresh_endpoint() started = service.start_acquisition( _start_request( acquisition_id=prepared["acquisition"]["acquisition_id"], physical_acceptance=PHYSICAL_ACCEPTANCE, expected_control_session_generation=prepared["application_control_session"][ "session_generation" ], expected_control_state_revision=prepared["application_control_session"][ "state_revision" ], ) ) assert started["acquisition"]["state"] == "starting" assert supervisor.snapshot().host_path.epoch == binding.host_path_epoch assert supervisor.snapshot().authority.control_allowed is True assert control.start_projects == [PROJECT_NAME] assert control.validation_calls == 5 assert len(runtime.start_calls) == 1 def test_existing_control_open_refreshes_before_ttl_reuse_gate( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _runtime = service_with_fake_runtime(tmp_path) monotonic_now = [100.0] suspend_aware_now = [1_000.0] supervisor = service._connection_supervisor # noqa: SLF001 supervisor._monotonic_clock = lambda: monotonic_now[0] # noqa: SLF001 supervisor._suspend_aware_clock = lambda: suspend_aware_now[0] # noqa: SLF001 supervisor._observation_ttl_seconds = 15.0 # noqa: SLF001 control, binding, _ready = _install_binding_validating_ready_control(service) stable_path = _direct_host_path(binding.target_ipv4) monkeypatch.setattr(service, "_sample_host_path", lambda *_args, **_kwargs: stable_path) monotonic_now[0] += 10.0 suspend_aware_now[0] += 10.0 assert supervisor.observe_endpoint( target=EndpointTarget(binding.target_ipv4, binding.target_port), intent_id=binding.intent_id, host_path_epoch=binding.host_path_epoch, reachable=True, ) monotonic_now[0] += 5.01 suspend_aware_now[0] += 5.01 def forbid_reopen_or_recovery() -> tuple[str, dict[str, Any]]: raise AssertionError("stable existing control must not reopen or enter BLE recovery") monkeypatch.setattr(service, "_reuse_or_recover_control_target", forbid_reopen_or_recovery) reused = service.open_application_control_session( OpenApplicationControlSessionRequest( operator_present=True, owner_controlled_device=True, lixelgo_closed=True, battery_storage_confirmed=True, expected_physical_state_confirmed=True, timezone_name="Europe/Moscow", ) ) assert reused["application_control_session"]["state"] == "connection-ready" assert supervisor.snapshot().host_path.epoch == binding.host_path_epoch assert supervisor.snapshot().authority.control_allowed is True assert control.validation_calls == 1 open_operation = next( operation for operation in reused["operations"] if operation["action"] == "application-control.session.open" ) assert open_operation["result"]["connection_lease_reused"] is True assert open_operation["result"]["device_write_performed"] is False def test_existing_control_bootstrap_refreshes_before_ttl_reuse_gate( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _runtime = service_with_fake_runtime(tmp_path) monotonic_now = [100.0] suspend_aware_now = [1_000.0] supervisor = service._connection_supervisor # noqa: SLF001 supervisor._monotonic_clock = lambda: monotonic_now[0] # noqa: SLF001 supervisor._suspend_aware_clock = lambda: suspend_aware_now[0] # noqa: SLF001 supervisor._observation_ttl_seconds = 15.0 # noqa: SLF001 control, binding, _ready = _install_binding_validating_ready_control(service) service._bootstrap_prestart_control_ready_owned = MethodType( # type: ignore[method-assign] # noqa: SLF001 XgridsK1CompatibilityService._bootstrap_prestart_control_ready_owned, # noqa: SLF001 service, ) stable_path = _direct_host_path(binding.target_ipv4) monkeypatch.setattr(service, "_sample_host_path", lambda *_args, **_kwargs: stable_path) monotonic_now[0] += 10.0 suspend_aware_now[0] += 10.0 assert supervisor.observe_endpoint( target=EndpointTarget(binding.target_ipv4, binding.target_port), intent_id=binding.intent_id, host_path_epoch=binding.host_path_epoch, reachable=True, ) monotonic_now[0] += 5.01 suspend_aware_now[0] += 5.01 async def forbid_retirement() -> None: raise AssertionError("stable existing control must not be retired or reopened") monkeypatch.setattr( service, "_retire_prestart_control_for_mode_transition", forbid_retirement, ) asyncio.run( service._bootstrap_prestart_control_ready_owned( # noqa: SLF001 parent_operation_id=None, connection_mode="bridge", ) ) assert control.state == "connection-ready" assert control.validation_calls == 1 assert supervisor.snapshot().host_path.epoch == binding.host_path_epoch assert supervisor.snapshot().authority.control_allowed is True bootstrap = [ operation for operation in service._operations.snapshot() # noqa: SLF001 if operation["action"] == facade_module.ACTION_CONNECTION_CONTROL_BOOTSTRAP ] assert len(bootstrap) == 1 assert bootstrap[0]["status"] == "succeeded" def test_workspace_route_change_still_fails_closed_before_checkpoint( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) monotonic_now = [100.0] suspend_aware_now = [1_000.0] supervisor = service._connection_supervisor # noqa: SLF001 supervisor._monotonic_clock = lambda: monotonic_now[0] # noqa: SLF001 supervisor._suspend_aware_clock = lambda: suspend_aware_now[0] # noqa: SLF001 control, binding, ready = _install_binding_validating_ready_control(service) changed_path = HostPathProbeResult( available=True, fingerprint="test-route:changed-before-workspace", interface="test0", source_ipv4="192.168.1.2", route_class="direct", kernel_route_fingerprint="test-route:changed-before-workspace", ) monkeypatch.setattr(service, "_sample_host_path", lambda *_args, **_kwargs: changed_path) with pytest.raises(ApplicationConnectionBindingLost): service.enter_application_workspace( EnterApplicationWorkspaceRequest( operator_confirmed=True, expected_session_generation=ready["application_control_session"][ "session_generation" ], expected_state_revision=ready["application_control_session"]["state_revision"], ) ) assert control.state == "closed" assert supervisor.snapshot().host_path.epoch != binding.host_path_epoch assert supervisor.snapshot().authority.control_allowed is False assert runtime.start_calls == [] assert control.start_projects == [] def test_start_stale_endpoint_fails_before_receiver_or_device_checkpoint( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) control, binding, ready = _install_binding_validating_ready_control(service) stable_path = _direct_host_path(binding.target_ipv4) monkeypatch.setattr(service, "_sample_host_path", lambda *_args, **_kwargs: stable_path) workspace = service.enter_application_workspace( EnterApplicationWorkspaceRequest( operator_confirmed=True, expected_session_generation=ready["application_control_session"]["session_generation"], expected_state_revision=ready["application_control_session"]["state_revision"], ) ) prepared = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host=binding.target_ipv4, compatibility_attestation=ATTESTATION, expected_control_session_generation=workspace["application_control_session"][ "session_generation" ], expected_control_state_revision=workspace["application_control_session"][ "state_revision" ], ) ) target = EndpointTarget(binding.target_ipv4, binding.target_port) supervisor = service._connection_supervisor # noqa: SLF001 assert supervisor.observe_endpoint( target=target, intent_id=binding.intent_id, host_path_epoch=binding.host_path_epoch, reachable=False, reason_code="tcp-endpoint-unreachable", ) physical_before = service._physical_command_ledger.snapshot() # noqa: SLF001 with pytest.raises(ApplicationConnectionBindingLost): service.start_acquisition( _start_request( acquisition_id=prepared["acquisition"]["acquisition_id"], physical_acceptance=PHYSICAL_ACCEPTANCE, expected_control_session_generation=prepared["application_control_session"][ "session_generation" ], expected_control_state_revision=prepared["application_control_session"][ "state_revision" ], ) ) assert prepared["acquisition"]["state"] == "prepared" assert service._acquisition is not None # noqa: SLF001 assert service._acquisition.state == "prepared" # noqa: SLF001 assert service._physical_command_ledger.snapshot() == physical_before # noqa: SLF001 assert not any( operation["action"] == facade_module.ACTION_ACQUISITION_START for operation in service._operations.snapshot() # noqa: SLF001 ) assert runtime.start_calls == [] assert control.start_projects == [] def test_start_stale_control_proof_fails_before_receiver_or_device_checkpoint( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) control, binding, ready = _install_binding_validating_ready_control(service) stable_path = _direct_host_path(binding.target_ipv4) monkeypatch.setattr(service, "_sample_host_path", lambda *_args, **_kwargs: stable_path) workspace = service.enter_application_workspace( EnterApplicationWorkspaceRequest( operator_confirmed=True, expected_session_generation=ready["application_control_session"]["session_generation"], expected_state_revision=ready["application_control_session"]["state_revision"], ) ) prepared = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host=binding.target_ipv4, compatibility_attestation=ATTESTATION, expected_control_session_generation=workspace["application_control_session"][ "session_generation" ], expected_control_state_revision=workspace["application_control_session"][ "state_revision" ], ) ) def reject_stale_control_proof(_control: object) -> None: raise ApplicationConnectionBindingLost("test MQTT control proof expired") control.validate_connection_binding = MethodType( # type: ignore[method-assign] reject_stale_control_proof, control, ) physical_before = service._physical_command_ledger.snapshot() # noqa: SLF001 with pytest.raises(ApplicationConnectionBindingLost): service.start_acquisition( _start_request( acquisition_id=prepared["acquisition"]["acquisition_id"], physical_acceptance=PHYSICAL_ACCEPTANCE, expected_control_session_generation=prepared["application_control_session"][ "session_generation" ], expected_control_state_revision=prepared["application_control_session"][ "state_revision" ], ) ) assert prepared["acquisition"]["state"] == "prepared" assert service._acquisition is not None # noqa: SLF001 assert service._acquisition.state == "prepared" # noqa: SLF001 assert service._physical_command_ledger.snapshot() == physical_before # noqa: SLF001 assert not any( operation["action"] == facade_module.ACTION_ACQUISITION_START for operation in service._operations.snapshot() # noqa: SLF001 ) assert runtime.start_calls == [] assert control.start_projects == [] def test_next_scan_retires_stale_terminal_live_perception_ingress_before_start( tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) service.live_perception_ingress.begin_session("stale-completed-session") prepared = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) state = service.start_acquisition( _start_request(acquisition_id=prepared["acquisition"]["acquisition_id"]) ) assert runtime.start_calls assert state["acquisition"]["state"] == "starting" assert state["live_perception_shadow"]["active"] is True assert state["live_perception_shadow"]["session_id"] != "stale-completed-session" def test_confirmed_scanning_waits_for_first_authoritative_pcl_before_camera( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) control = FakeInteractiveControlSession() service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 _seed_supervised_connection(service) service._compatibility_attestation = ATTESTATION.model_dump(mode="json") # noqa: SLF001 prepared = service.prepare_acquisition( _prepare_request( project_name="TEST001", host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] pre_pcl_state = service.start_acquisition( _start_request( acquisition_id=acquisition_id, physical_acceptance=PHYSICAL_ACCEPTANCE, ) ) pre_pcl_camera_streams = [ stream for stream in pre_pcl_state["sensor_catalog"]["streams"] if stream.get("semantic_channel_id") == "camera.preview.live" ] assert pre_pcl_state["camera_preview"]["active_source_id"] is None assert pre_pcl_state["camera_preview"]["delivery"] is None assert pre_pcl_state["camera_preview"]["activation_admission"]["state"] == ( "waiting-for-first-authoritative-pcl" ) assert all(stream["activation"]["selected"] is False for stream in pre_pcl_camera_streams) assert all(stream["activation"]["controllable"] is False for stream in pre_pcl_camera_streams) out_dir = service._acquisition_out_dir # noqa: SLF001 assert out_dir is not None out_dir.mkdir(parents=True) events: list[tuple[str, object]] = [] activation_entered = threading.Event() release_activation = threading.Event() camera_state: dict[str, object] = { "phase": "idle", "active_source_id": None, "recording": {"active": False}, } def activate_recording( source_id: str, target: str, session_dir: Path, *, commit_fence: Callable[[Callable[[], bool]], bool], committed_before_start: Callable[[dict[str, object]], None] | None = None, ) -> dict[str, object]: events.append(("select", (source_id, target))) camera_state["active_source_id"] = source_id events.append(("record", session_dir)) camera_state["recording"] = { "active": True, "session": session_dir.name, "active_epoch": 1, "producer_alive": True, "last_segment_age_ms": 0, "last_media_segment_age_ms": 0, "media_ready": True, "current_epoch": { "generation": 1, "init_committed": True, "init_committed_age_ms": 0, "first_media_committed": True, "first_media_committed_age_ms": 0, "committed_media_segment_count": 1, "last_media_segment_age_ms": 0, }, } camera_state["phase"] = "streaming" committed = dict(camera_state) assert committed_before_start is not None assert commit_fence( lambda: committed_before_start(committed) is None ) is True return committed actual_camera_snapshot = service.camera_preview.snapshot() def snapshot_camera() -> dict[str, object]: return { **actual_camera_snapshot, **camera_state, "recording": { **actual_camera_snapshot["recording"], **camera_state["recording"], # type: ignore[arg-type] }, } monkeypatch.setattr(service.camera_preview, "snapshot", snapshot_camera) monkeypatch.setattr( service.camera_preview, "activate_recording_producer", activate_recording, ) real_activate = service._activate_default_acquisition_camera # noqa: SLF001 def gated_activate(**kwargs: object) -> bool: activation_entered.set() assert release_activation.wait(timeout=2.0) return real_activate(**kwargs) # type: ignore[arg-type] monkeypatch.setattr(service, "_activate_default_acquisition_camera", gated_activate) runtime.mark_ready() assert control.state == "scanning" assert camera_state["active_source_id"] is None assert events == [] with service._lock: # noqa: SLF001 start_operation_id = service._acquisition_start_operation_id # noqa: SLF001 assert start_operation_id is not None binding = _seed_supervised_connection(service) physical = _exact_start_physical_proof( operation_id=start_operation_id, acquisition_id=acquisition_id, binding=binding, resolved=True, ) monkeypatch.setattr(service._physical_command_coordinator, "snapshot", lambda: physical) # noqa: SLF001 runtime.pcl_frames = 1 frame = DecodedPointCloudView( context=ConsumerFrameContext( sequence=1, captured_at_epoch_ns=1, received_monotonic_ns=1, processing_started_monotonic_ns=1, encoded_size_bytes=16, live=True, ), frame_id="map", positions_xyz=((0.0, 0.0, 0.0),), ) service._observe_published_runtime_envelope( # noqa: SLF001 frame, runtime.producer_generation, ) # The first PCL admits only the one automatic right-camera activation. # Public manual controls stay closed until that worker proves an exact # recording epoch, preventing a left/right selection race. assert activation_entered.wait(timeout=2.0) activating_state = service.state() activating_camera_streams = [ stream for stream in activating_state["sensor_catalog"]["streams"] if stream.get("semantic_channel_id") == "camera.preview.live" ] assert activating_state["camera_preview"]["activation_admission"]["state"] == "activating" assert all( stream["activation"]["controllable"] is False for stream in activating_camera_streams ) with pytest.raises(RuntimeError, match="автоматического запуска правой камеры"): service.select_camera_preview( CameraPreviewSelectRequest( device_session_id=service._device_session_id, # type: ignore[arg-type] # noqa: SLF001 source_id="sensor.camera.left", ) ) assert events == [] release_activation.set() deadline = time.monotonic() + 2.0 while len(events) < 2 and time.monotonic() < deadline: time.sleep(0.01) assert events == [ ("select", ("sensor.camera.right", "192.168.1.20")), ("record", out_dir), ] assert camera_state["active_source_id"] == "sensor.camera.right" assert camera_state["recording"] == { "active": True, "session": out_dir.name, "active_epoch": 1, "producer_alive": True, "last_segment_age_ms": 0, "last_media_segment_age_ms": 0, "media_ready": True, "current_epoch": { "generation": 1, "init_committed": True, "init_committed_age_ms": 0, "first_media_committed": True, "first_media_committed_age_ms": 0, "committed_media_segment_count": 1, "last_media_segment_age_ms": 0, }, } assert runtime.source_mode == "live" assert control.start_projects == ["TEST001"] assert control.stop_calls == 0 admitted_state = service.state() admitted_camera_streams = [ stream for stream in admitted_state["sensor_catalog"]["streams"] if stream.get("semantic_channel_id") == "camera.preview.live" ] assert admitted_state["camera_preview"]["activation_admission"]["state"] == "admitted" assert any( stream["source_id"] == "sensor.camera.right" and stream["activation"]["selected"] is True and stream["activation"]["controllable"] is True for stream in admitted_camera_streams ) # Every later authoritative PCL for the same lineage is idempotent. service._observe_published_runtime_envelope(frame, runtime.producer_generation) # noqa: SLF001 time.sleep(0.05) assert len(events) == 2 def test_stale_post_publish_pcl_cannot_activate_camera( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) control = FakeInteractiveControlSession() service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 binding = _seed_supervised_connection(service) service._compatibility_attestation = ATTESTATION.model_dump(mode="json") # noqa: SLF001 prepared = service.prepare_acquisition( _prepare_request( project_name="STALEPCL001", host=binding.target_ipv4, compatibility_attestation=ATTESTATION, ) ) service.start_acquisition( _start_request( acquisition_id=prepared["acquisition"]["acquisition_id"], physical_acceptance=PHYSICAL_ACCEPTANCE, ) ) runtime.mark_ready() runtime.pcl_frames = 1 selected: list[object] = [] monkeypatch.setattr( service.camera_preview, "select", lambda *_args, **_kwargs: selected.append(object()), ) frame = DecodedPointCloudView( context=ConsumerFrameContext( sequence=1, captured_at_epoch_ns=1, received_monotonic_ns=1, processing_started_monotonic_ns=1, encoded_size_bytes=16, live=True, ), frame_id="map", positions_xyz=((0.0, 0.0, 0.0),), ) service._observe_published_runtime_envelope( # noqa: SLF001 frame, runtime.producer_generation - 1, ) with service._lock: # noqa: SLF001 service._acquisition.transition("interrupted", message_code="test.stale") # type: ignore[union-attr] # noqa: SLF001 service._observe_published_runtime_envelope(frame, runtime.producer_generation) # noqa: SLF001 time.sleep(0.05) assert selected == [] assert service.camera_preview.snapshot()["active_source_id"] is None def test_failed_post_pcl_camera_activation_retries_on_later_authoritative_frame( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) control = FakeInteractiveControlSession() service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 binding = _seed_supervised_connection(service) service._compatibility_attestation = ATTESTATION.model_dump(mode="json") # noqa: SLF001 prepared = service.prepare_acquisition( _prepare_request( project_name="RETRYPCL001", host=binding.target_ipv4, compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] service.start_acquisition( _start_request( acquisition_id=acquisition_id, physical_acceptance=PHYSICAL_ACCEPTANCE, ) ) runtime.mark_ready() runtime.pcl_frames = 1 with service._lock: # noqa: SLF001 start_operation_id = service._acquisition_start_operation_id # noqa: SLF001 out_dir = service._acquisition_out_dir # noqa: SLF001 assert start_operation_id is not None assert out_dir is not None physical = _exact_start_physical_proof( operation_id=start_operation_id, acquisition_id=acquisition_id, binding=_seed_supervised_connection(service), resolved=True, ) monkeypatch.setattr(service._physical_command_coordinator, "snapshot", lambda: physical) # noqa: SLF001 out_dir.mkdir(parents=True) actual_camera = service.camera_preview.snapshot() camera_state: dict[str, object] = { **actual_camera, "phase": "idle", "generation": None, "active_source_id": None, "recording": { **actual_camera["recording"], "active": False, "session": None, "active_epoch": None, "producer_alive": False, }, "error": None, } select_calls: list[tuple[str, str]] = [] recording_calls: list[Path] = [] retry_calls: list[tuple[str, str, int, str]] = [] def snapshot_camera() -> dict[str, object]: return { **camera_state, "recording": dict(camera_state["recording"]), # type: ignore[arg-type] } def fail_first_activation( source_id: str, target: str, session_dir: Path, *, commit_fence: Callable[[Callable[[], bool]], bool], committed_before_start: Callable[[dict[str, object]], None] | None = None, ) -> dict[str, object]: del commit_fence, committed_before_start select_calls.append((source_id, target)) recording_calls.append(session_dir) camera_state.update( { "phase": "error", "error": { "code": "ffmpeg-start-failed", "message": "synthetic first local spawn failure", }, "generation": 1, "active_source_id": source_id, "recording": { **camera_state["recording"], # type: ignore[arg-type] "active": True, "session": session_dir.name, "active_epoch": None, "producer_alive": False, }, } ) raise RuntimeError("synthetic first local spawn failure") def retry_recording( source_id: str, target: str, *, expected_generation: int, expected_recording_session: str, pre_retry_fence: Callable[[Callable[[], bool]], bool], commit_fence: Callable[[Callable[[], bool]], bool] | None = None, committed_before_start: Callable[[dict[str, object]], None] | None = None, ) -> dict[str, object]: retry_calls.append( (source_id, target, expected_generation, expected_recording_session) ) assert camera_state["phase"] == "error" assert camera_state["generation"] == expected_generation assert pre_retry_fence(lambda: True) is True recording = camera_state["recording"] assert isinstance(recording, dict) assert recording["session"] == expected_recording_session camera_state.update( { "phase": "connecting", "generation": expected_generation + 1, "error": None, "recording": { **recording, "active_epoch": expected_generation + 1, "producer_alive": True, "last_segment_age_ms": None, "last_media_segment_age_ms": None, "media_ready": False, "current_epoch": { "generation": expected_generation + 1, "init_committed": False, "init_committed_age_ms": None, "first_media_committed": False, "first_media_committed_age_ms": None, "committed_media_segment_count": 0, "last_media_segment_age_ms": None, }, }, } ) committed = snapshot_camera() assert commit_fence is not None assert committed_before_start is not None assert commit_fence( lambda: committed_before_start(committed) is None ) is True return committed monkeypatch.setattr(service.camera_preview, "snapshot", snapshot_camera) monkeypatch.setattr( service.camera_preview, "activate_recording_producer", fail_first_activation, ) monkeypatch.setattr( service.camera_preview, "retry_recording_producer", retry_recording, ) frame = DecodedPointCloudView( context=ConsumerFrameContext( sequence=1, captured_at_epoch_ns=1, received_monotonic_ns=1, processing_started_monotonic_ns=1, encoded_size_bytes=16, live=True, ), frame_id="map", positions_xyz=((0.0, 0.0, 0.0),), ) service._observe_published_runtime_envelope(frame, runtime.producer_generation) # noqa: SLF001 deadline = time.monotonic() + 2.0 while len(recording_calls) < 1 and time.monotonic() < deadline: time.sleep(0.01) assert recording_calls == [out_dir] assert select_calls == [("sensor.camera.right", binding.target_ipv4)] # Normal UI polling between attempts must preserve PCL/Rerun and the # scanner-owned session while this exact startup error is retryable. provisional = service.state() assert provisional["acquisition"]["state"] in { "starting", "awaiting_external_start", "acquiring", } assert provisional["camera_preview"]["activation_admission"]["state"] == "activating" assert runtime.source_mode == "live" assert runtime.stop_calls == 0 assert control.stop_calls == 0 # Frames inside the bounded retry window cannot create a worker storm. service._observe_published_runtime_envelope(frame, runtime.producer_generation) # noqa: SLF001 time.sleep(0.05) assert retry_calls == [] with service._lock: # noqa: SLF001 service._camera_activation_retry_not_before_monotonic = 0.0 # noqa: SLF001 service._observe_published_runtime_envelope(frame, runtime.producer_generation) # noqa: SLF001 deadline = time.monotonic() + 2.0 while len(retry_calls) < 1 and time.monotonic() < deadline: time.sleep(0.01) assert retry_calls == [ ( "sensor.camera.right", binding.target_ipv4, 1, out_dir.name, ) ] assert camera_state["generation"] == 2 recording = camera_state["recording"] assert isinstance(recording, dict) assert recording["active_epoch"] == 2 assert recording["producer_alive"] is True with service._lock: # noqa: SLF001 assert service._camera_activation_lineage == ( # noqa: SLF001 acquisition_id, out_dir.name, runtime.producer_generation, ) assert control.start_projects == ["RETRYPCL001"] assert control.stop_calls == 0 admitted = service.state() assert admitted["acquisition"]["state"] == "acquiring" assert admitted["camera_preview"]["activation_admission"]["state"] == "activating" assert admitted["camera_preview"]["recording"]["media_ready"] is False assert admitted["connection_policy"]["actions"]["stop-acquisition"]["allowed"] is True # The same shaped error without the exact retry claim stays terminal; the # classifier never masks storage/archive failures or an unrelated lineage. with service._lock: # noqa: SLF001 service._camera_activation_lineage = None # noqa: SLF001 service._camera_activation_retry_lineage = None # noqa: SLF001 monkeypatch.setattr(service, "_seal_acquisition_capture_clock", lambda: None) camera_state.update( { "phase": "error", "error": { "code": "camera-storage-failed", "message": "synthetic durable archive failure", }, "recording": { **recording, "active_epoch": None, "producer_alive": False, }, } ) terminal = service.state() assert terminal["acquisition"]["state"] == "failed" assert terminal["acquisition"]["result"]["camera_failure_code"] == ( "camera-storage-failed" ) def _install_composite_active_recovery_fixture( service: XgridsK1CompatibilityService, runtime: FakeVisualizationRuntime, monkeypatch: pytest.MonkeyPatch, *, runtime_phase: str = "reconnecting", camera_phase: str = "error", ) -> tuple[FakeInteractiveControlSession, dict[str, object]]: control = FakeInteractiveControlSession() service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 binding = _seed_supervised_connection(service) prepared = service.prepare_acquisition( _prepare_request( project_name="RECOVERY001", host=binding.target_ipv4, compatibility_attestation=ATTESTATION, ) ) acquisition_id = str(prepared["acquisition"]["acquisition_id"]) service.start_acquisition( _start_request( acquisition_id=acquisition_id, physical_acceptance=PHYSICAL_ACCEPTANCE, ) ) with service._lock: # noqa: SLF001 acquisition = service._acquisition # noqa: SLF001 start_operation_id = service._acquisition_start_operation_id # noqa: SLF001 out_dir = service._acquisition_out_dir # noqa: SLF001 assert acquisition is not None assert start_operation_id is not None assert out_dir is not None acquisition.transition("acquiring", message_code="acquisition.acquiring") out_dir.mkdir(parents=True, exist_ok=True) runtime.phase = runtime_phase runtime.source_mode = "live" runtime.source_ready = runtime_phase == "live" runtime.recovery_state = ( "reconnecting" if runtime_phase == "reconnecting" else "inactive" ) runtime.recovery_request_pending = runtime_phase == "reconnecting" runtime.pcl_frames = 4 physical: dict[str, object] = { "status": "resolved", "reason_code": None, "requires_reconciliation": False, "resolved_active_recovery_required": True, "automatic_replay_allowed": False, "normal_session_recovery_supported": False, "recovery_requirement": ("explicit-read-only-deviceinfo-and-non-retained-devicestatus"), "runtime_bound": True, "reconciliation_ready": False, "observed_session_state": None, "active_operation_id": None, "record": { "revision": 7, "operation_id": start_operation_id, "acquisition_id": acquisition_id, "action": "start", "stage": "resolved", "resolution": "start-active-observed", "publish_call_returned": True, "qos2_completed": True, "packet_id": 41, "application_response": { "operation_id": start_operation_id, "action": "start", "success": True, }, "last_status": { "session_state": "scanning", "project_bound": True, "init_ready": True, "mqtt_retained": False, }, "connection": { "intent_id": binding.intent_id, "transport_ref": binding.transport_ref, "connection_mode": binding.connection_mode, "target_ipv4": binding.target_ipv4, "target_port": binding.target_port, }, "reconciliations": [], }, } monkeypatch.setattr( service._physical_command_coordinator, # noqa: SLF001 "snapshot", lambda: physical, ) # START operation ownership is released after the normal application # operation settles. The broad mapping-only fixture has no real durable # checkpoint, so preserve its immutable original START through the same # helper seam used by production checkpoint integration. service._active_acquisition_checkpoint_start_operation_id = MethodType( # type: ignore[method-assign] # noqa: SLF001 lambda _service, **_kwargs: start_operation_id, service, ) camera = service.camera_preview.snapshot() camera.update( { "phase": camera_phase, "active_source_id": facade_module.DEFAULT_ACQUISITION_CAMERA_SOURCE, "recording": { "active": True, "session": out_dir.name, "active_epoch": 1 if camera_phase == "streaming" else None, "producer_alive": camera_phase == "streaming", "producer_age_ms": 1_000, "last_segment_age_ms": 0 if camera_phase == "streaming" else None, "completed_epochs": 0 if camera_phase == "streaming" else 1, "last_summary": None, "source_end_expected": False, }, "error": ( { "code": "camera-source-ended", "message": "synthetic Wi-Fi loss", } if camera_phase == "error" else None ), } ) monkeypatch.setattr(service.camera_preview, "snapshot", lambda: camera) return control, physical def test_camera_first_short_outage_is_observational_without_browser_side_effects( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) control, physical = _install_composite_active_recovery_fixture( service, runtime, monkeypatch, runtime_phase="live", camera_phase="error", ) start_projects_before = list(control.start_projects) stop_calls_before = control.stop_calls state = service.state() recovery = state["connection_recovery"] assert runtime.recovery_requests == [] assert runtime.recovery_request_pending is False assert state["source_mode"] == "live" assert recovery["state"] == "inactive" assert recovery["automatic_read_only_rebind"] is False assert state["acquisition"]["state"] == "acquiring" assert state["selected_device_id"] == "test-ble-transport" assert state["k1_ip"] == "192.168.1.20" assert runtime.stop_calls == 0 assert control.start_projects == start_projects_before assert control.stop_calls == stop_calls_before assert service._physical_command_coordinator.snapshot() is physical # noqa: SLF001 def test_camera_stall_snapshot_does_not_reconnect_live_mqtt_runtime( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) control, physical = _install_composite_active_recovery_fixture( service, runtime, monkeypatch, runtime_phase="live", camera_phase="streaming", ) camera = service.camera_preview.snapshot() recording = camera["recording"] assert isinstance(recording, dict) recording["last_segment_age_ms"] = ( facade_module.ACTIVE_STREAM_CAMERA_STALL_MILLISECONDS ) state = service.state() assert runtime.recovery_requests == [] assert runtime.recovery_request_pending is False assert state["source_mode"] == "live" assert state["acquisition"]["state"] == "acquiring" assert runtime.stop_calls == 0 assert control.stop_calls == 0 assert service._physical_command_coordinator.snapshot() is physical # noqa: SLF001 def test_backend_camera_watchdog_cas_restarts_only_camera_without_device_commands( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) control, physical = _install_composite_active_recovery_fixture( service, runtime, monkeypatch, runtime_phase="live", camera_phase="streaming", ) camera = service.camera_preview.snapshot() camera["generation"] = 1 recording = camera["recording"] assert isinstance(recording, dict) recording.update( { "producer_age_ms": facade_module.ACTIVE_STREAM_CAMERA_STALL_MILLISECONDS + 1, "last_segment_age_ms": facade_module.ACTIVE_STREAM_CAMERA_STALL_MILLISECONDS + 1, "last_media_segment_age_ms": ( facade_module.ACTIVE_STREAM_CAMERA_STALL_MILLISECONDS + 1 ), "committed_media_segment_count": 10, "media_ready": True, "current_epoch": { "generation": 1, "init_committed": True, "init_committed_age_ms": 20_000, "first_media_committed": True, "first_media_committed_age_ms": 20_000, "committed_media_segment_count": 10, "last_media_segment_age_ms": ( facade_module.ACTIVE_STREAM_CAMERA_STALL_MILLISECONDS + 1 ), }, } ) restart_calls: list[tuple[str, str, int, str, int | None, int]] = [] def restart( source_id: str, target: str, *, expected_generation: int, expected_recording_session: str, expected_active_epoch: int | None, expected_recording_media_segment_count: int, pre_detach_fence: Callable[[Callable[[], bool]], bool], commit_fence: Callable[[Callable[[], bool]], bool] | None = None, committed_before_start: Callable[[dict[str, object]], None] | None = None, ) -> dict[str, object]: restart_calls.append( ( source_id, target, expected_generation, expected_recording_session, expected_active_epoch, expected_recording_media_segment_count, ) ) assert pre_detach_fence(lambda: True) is True camera.update( { "phase": "connecting", "generation": 2, "error": None, "recording": { **recording, "active_epoch": 2, "producer_alive": True, "producer_age_ms": 0, "last_segment_age_ms": None, "last_media_segment_age_ms": None, "media_ready": False, "current_epoch": { "generation": 2, "init_committed": False, "init_committed_age_ms": None, "first_media_committed": False, "first_media_committed_age_ms": None, "committed_media_segment_count": 0, "last_media_segment_age_ms": None, }, }, } ) assert commit_fence is not None assert committed_before_start is not None assert commit_fence( lambda: committed_before_start(dict(camera)) is None ) is True return dict(camera) monkeypatch.setattr(service.camera_preview, "restart_recording_producer", restart) start_projects_before = list(control.start_projects) stop_calls_before = control.stop_calls service._observe_camera_producer_stall("camera-stream-stalled", 1) # noqa: SLF001 service._observe_camera_producer_stall("camera-stream-stalled", 1) # noqa: SLF001 assert restart_calls == [ ( facade_module.DEFAULT_ACQUISITION_CAMERA_SOURCE, "192.168.1.20", 1, recording["session"], 1, 10, ) ] assert runtime.phase == "live" assert runtime.recovery_requests == [] assert control.start_projects == start_projects_before assert control.stop_calls == stop_calls_before assert service._physical_command_coordinator.snapshot() is physical # noqa: SLF001 assert camera["recording"]["media_ready"] is False projected = service.state() assert projected["connection_recovery"]["state"] == "inactive" assert projected["connection_recovery"]["camera_recovery"] == "owned" assert projected["connection_recovery"]["camera_media_state"] == "pending-init" assert projected["connection_recovery"]["camera_media_ready"] is False assert projected["connection_recovery"]["camera_epoch"]["generation"] == 2 assert projected["connection_policy"]["actions"]["stop-acquisition"]["allowed"] is True def test_stop_priority_overtakes_blocked_camera_watchdog_candidate( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) control, _physical = _install_composite_active_recovery_fixture( service, runtime, monkeypatch, runtime_phase="live", camera_phase="streaming", ) camera = service.camera_preview.snapshot() camera["generation"] = 1 recording = camera["recording"] assert isinstance(recording, dict) recording.update( { "producer_age_ms": facade_module.ACTIVE_STREAM_CAMERA_STALL_MILLISECONDS + 1, "last_segment_age_ms": facade_module.ACTIVE_STREAM_CAMERA_STALL_MILLISECONDS + 1, "last_media_segment_age_ms": ( facade_module.ACTIVE_STREAM_CAMERA_STALL_MILLISECONDS + 1 ), "committed_media_segment_count": 10, "media_ready": True, "current_epoch": { "generation": 1, "init_committed": True, "init_committed_age_ms": 20_000, "first_media_committed": True, "first_media_committed_age_ms": 20_000, "committed_media_segment_count": 10, "last_media_segment_age_ms": 20_000, }, } ) candidate_blocked = threading.Event() release_candidate = threading.Event() candidate_committed: list[bool] = [] def restart( _source_id: str, _target: str, *, expected_generation: int, expected_recording_session: str, expected_active_epoch: int | None, expected_recording_media_segment_count: int, pre_detach_fence: Callable[[Callable[[], bool]], bool], commit_fence: Callable[[Callable[[], bool]], bool] | None = None, committed_before_start: Callable[[dict[str, object]], None] | None = None, ) -> dict[str, object]: del ( expected_generation, expected_recording_session, expected_active_epoch, expected_recording_media_segment_count, ) assert commit_fence is not None del committed_before_start candidate_blocked.set() assert release_candidate.wait(3.0) committed = commit_fence(lambda: candidate_committed.append(True) or True) if not committed: raise ValueError("camera recovery lineage устарела") return dict(camera) monkeypatch.setattr(service.camera_preview, "restart_recording_producer", restart) stop_owned_entered = threading.Event() def stop_owned( _request: StopAcquisitionRequest, _preadmitted_stop: object | None = None, ) -> dict[str, object]: stop_owned_entered.set() control.request_stop( confirmation=object(), command_context=object(), dispatch_admission_deadline_reached=lambda: False, expected_session_generation=control.session_generation, expected_state_revision=control.state_revision, ) with service._lock: # noqa: SLF001 acquisition = service._acquisition # noqa: SLF001 assert acquisition is not None acquisition.transition( "awaiting_external_stop", message_code="acquisition.stop.device_stopping", ) service._acquisition_stop_operation_id = "priority-stop" # noqa: SLF001 return {"stop": "prepared"} monkeypatch.setattr(service, "_stop_acquisition_owned", stop_owned) observer = threading.Thread( target=service._observe_camera_producer_stall, # noqa: SLF001 args=("camera-stream-stalled", 1), daemon=True, ) observer.start() assert candidate_blocked.wait(3.0) request = _stop_request( acquisition_id=None, mode="graceful", physical_acceptance=PHYSICAL_ACCEPTANCE, ) stop_result: list[dict[str, object]] = [] stop_worker = threading.Thread( target=lambda: stop_result.append(service.stop_acquisition(request)), daemon=True, ) stop_worker.start() assert stop_owned_entered.wait(3.0) stop_worker.join(3.0) assert stop_worker.is_alive() is False assert stop_result == [{"stop": "prepared"}] assert control.stop_calls == 1 assert candidate_committed == [] release_candidate.set() observer.join(3.0) assert observer.is_alive() is False assert candidate_committed == [] def test_stop_priority_overtakes_blocked_physical_snapshot_before_camera_commit( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) _control, physical = _install_composite_active_recovery_fixture( service, runtime, monkeypatch, runtime_phase="live", camera_phase="streaming", ) with service._lock: # noqa: SLF001 acquisition = service._acquisition # noqa: SLF001 out_dir = service._acquisition_out_dir # noqa: SLF001 start_operation_id = service._acquisition_start_operation_id # noqa: SLF001 assert acquisition is not None assert out_dir is not None assert start_operation_id is not None snapshot_blocked = threading.Event() release_snapshot = threading.Event() def blocking_snapshot() -> dict[str, object]: if threading.current_thread().name == "camera-commit-candidate": snapshot_blocked.set() assert release_snapshot.wait(3.0) return physical monkeypatch.setattr( service._physical_command_coordinator, # noqa: SLF001 "snapshot", blocking_snapshot, ) camera_commit_calls: list[str] = [] camera_commit_results: list[bool] = [] camera_commit_worker = threading.Thread( name="camera-commit-candidate", target=lambda: camera_commit_results.append( service._commit_camera_restart_if_still_active( # noqa: SLF001 acquisition_id=acquisition.acquisition_id, evidence_session_id=out_dir.name, start_operation_id=start_operation_id, runtime_producer_generation=runtime.producer_generation, commit=lambda: camera_commit_calls.append("commit") or True, ) ), daemon=True, ) camera_commit_worker.start() assert snapshot_blocked.wait(3.0) stop_owned_entered = threading.Event() def stop_owned( _request: StopAcquisitionRequest, _preadmitted_stop: object | None = None, ) -> dict[str, object]: assert service._camera_stop_priority_counts == { # noqa: SLF001 acquisition.acquisition_id: 1 } stop_owned_entered.set() with service._lock: # noqa: SLF001 acquisition.transition( "awaiting_external_stop", message_code="acquisition.stop.device_stopping", ) service._acquisition_stop_operation_id = "snapshot-priority-stop" # noqa: SLF001 return {"stop": "prepared"} monkeypatch.setattr(service, "_stop_acquisition_owned", stop_owned) stop_result: list[dict[str, object]] = [] stop_worker = threading.Thread( target=lambda: stop_result.append( service.stop_acquisition( _stop_request( acquisition_id=None, mode="graceful", operator_confirmed=True, physical_acceptance=PHYSICAL_ACCEPTANCE, ) ) ), daemon=True, ) stop_worker.start() assert stop_owned_entered.wait(3.0) stop_worker.join(3.0) assert stop_worker.is_alive() is False assert stop_result == [{"stop": "prepared"}] release_snapshot.set() camera_commit_worker.join(3.0) assert camera_commit_worker.is_alive() is False assert camera_commit_results == [False] assert camera_commit_calls == [] def test_stop_priority_overtakes_blocked_initial_camera_popen( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture(service, runtime) with service._lock: # noqa: SLF001 acquisition = service._acquisition # noqa: SLF001 out_dir = service._acquisition_out_dir # noqa: SLF001 assert acquisition is not None assert out_dir is not None camera = service.camera_preview.snapshot() camera.update( { "phase": "idle", "generation": None, "active_source_id": None, "recording": {"active": False}, "error": None, } ) candidate_blocked = threading.Event() release_candidate = threading.Event() candidate_committed: list[bool] = [] def blocked_initial_popen( _source_id: str, _target: str, _session_dir: Path, *, commit_fence: Callable[[Callable[[], bool]], bool], committed_before_start: Callable[[dict[str, object]], None] | None = None, ) -> dict[str, object]: del committed_before_start candidate_blocked.set() assert release_candidate.wait(3.0) if not commit_fence(lambda: candidate_committed.append(True) or True): raise ValueError("camera activation lineage устарела") return dict(camera) monkeypatch.setattr( service.camera_preview, "activate_recording_producer", blocked_initial_popen, ) monkeypatch.setattr(service, "_ensure_camera_preview_process_lease", lambda: False) activation_result: list[bool] = [] activation_errors: list[BaseException] = [] def activate() -> None: try: activation_result.append( service._activate_default_acquisition_camera( # noqa: SLF001 expected_acquisition_id=acquisition.acquisition_id, expected_evidence_session_id=out_dir.name, expected_runtime_generation=runtime.producer_generation, ) ) except BaseException as exc: activation_errors.append(exc) activation = threading.Thread( target=activate, daemon=True, ) activation.start() assert candidate_blocked.wait(3.0) stop_result: list[dict[str, object]] = [] stop_worker = threading.Thread( target=lambda: stop_result.append( service.stop_acquisition( fixture.request.model_copy(update={"acquisition_id": None}) ) ), daemon=True, ) stop_worker.start() stop_worker.join(3.0) assert stop_worker.is_alive() is False assert len(stop_result) == 1 assert stop_result[0]["acquisition"]["state"] == "awaiting_external_stop" assert fixture.control.stop_calls == 1 assert fixture.prepare_calls == [fixture.stop_operation_id] prepared_record = fixture.ledger.snapshot().record assert prepared_record is not None assert prepared_record.operation_id == fixture.stop_operation_id assert prepared_record.stage == "prepared" release_candidate.set() activation.join(3.0) assert activation.is_alive() is False assert activation_result == [] assert len(activation_errors) == 1 assert isinstance(activation_errors[0], ValueError) assert candidate_committed == [] def test_nontransport_camera_failure_remains_terminal_without_recovery_wake( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) control, physical = _install_composite_active_recovery_fixture( service, runtime, monkeypatch, runtime_phase="live", camera_phase="streaming", ) camera = service.camera_preview.snapshot() camera["phase"] = "error" camera["error"] = { "code": "camera-artifact-write-failed", "message": "synthetic local storage failure", } monkeypatch.setattr(service, "_seal_acquisition_capture_clock", lambda: None) state = service.state() assert runtime.recovery_requests == [] assert runtime.recovery_request_pending is False assert state["acquisition"]["state"] == "failed" assert state["acquisition"]["result"]["camera_failure_code"] == ( "camera-artifact-write-failed" ) assert runtime.stop_calls == 1 assert control.stop_calls == 0 assert service._physical_command_coordinator.snapshot() is physical # noqa: SLF001 def test_host_first_recovery_does_not_mask_later_camera_artifact_failure( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) control, physical = _install_composite_active_recovery_fixture( service, runtime, monkeypatch, runtime_phase="live", camera_phase="streaming", ) monkeypatch.setattr(service, "_seal_acquisition_capture_clock", lambda: None) lost_path = HostPathProbeResult( available=False, fingerprint=None, interface=None, source_ipv4=None, route_class="unavailable", reason_code="host-route-unavailable", ) start_projects_before = list(control.start_projects) stop_calls_before = control.stop_calls for _ in range(3): service._connection_supervisor.observe_host_path(lost_path) # noqa: SLF001 reconnecting = service.state() assert reconnecting["phase"] == "reconnecting" assert runtime.recovery_request_pending is True camera = service.camera_preview.snapshot() camera["phase"] = "error" camera["error"] = { "code": "camera-artifact-write-failed", "message": "synthetic local artifact failure after host loss", } failed = service.state() assert failed["acquisition"]["state"] == "failed" assert failed["acquisition"]["result"]["camera_failure_code"] == ( "camera-artifact-write-failed" ) assert failed["source_mode"] == "idle" assert runtime.stop_calls == 1 assert runtime.recovery_request_pending is False assert control.start_projects == start_projects_before assert control.stop_calls == stop_calls_before assert service._physical_command_coordinator.snapshot() is physical # noqa: SLF001 def test_control_first_loss_freezes_topology_before_ephemeral_retirement( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) control, physical = _install_composite_active_recovery_fixture( service, runtime, monkeypatch, runtime_phase="live", camera_phase="streaming", ) control.state = "failed" control.failure = { "reason_code": "mqtt_network_loop_failed", "modeling_command_attempted": True, "safe_to_retry": False, } start_projects_before = list(control.start_projects) stop_calls_before = control.stop_calls state = service.state() assert runtime.recovery_requests == [ ("mqtt_network_loop_failed", runtime.producer_generation), ] assert state["phase"] == "reconnecting" assert state["connection_recovery"]["automatic_read_only_rebind"] is True assert state["acquisition"]["state"] == "acquiring" assert state["selected_device_id"] == "test-ble-transport" assert state["device_session"] is not None assert state["k1_ip"] == "192.168.1.20" assert runtime.stop_calls == 0 assert control.start_projects == start_projects_before assert control.stop_calls == stop_calls_before assert service._physical_command_coordinator.snapshot() is physical # noqa: SLF001 def test_incident_host_route_streak_wakes_recovery_before_binding_retirement( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) control, _physical = _install_composite_active_recovery_fixture( service, runtime, monkeypatch, runtime_phase="live", camera_phase="streaming", ) lost_path = HostPathProbeResult( available=False, fingerprint=None, interface=None, source_ipv4=None, route_class="unavailable", reason_code="host-route-unavailable", ) states: list[dict[str, Any]] = [] for _ in range(3): service._connection_supervisor.observe_host_path(lost_path) # noqa: SLF001 states.append(service.state()) assert runtime.recovery_requests == [ ("host-route-unavailable", runtime.producer_generation), ] assert all(state["selected_device_id"] == "test-ble-transport" for state in states) assert states[-1]["phase"] == "reconnecting" assert states[-1]["connection_recovery"]["automatic_read_only_rebind"] is True assert states[-1]["acquisition"]["state"] == "acquiring" assert control.state == "scanning" assert runtime.stop_calls == 0 @pytest.mark.parametrize("first_symptom", ["camera", "control"]) def test_host_camera_and_late_mqtt_loss_share_one_recovery_owner( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, first_symptom: str, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) control, _physical = _install_composite_active_recovery_fixture( service, runtime, monkeypatch, runtime_phase="live", camera_phase="error" if first_symptom == "camera" else "streaming", ) if first_symptom == "camera": first = service.state() assert first["connection_recovery"]["state"] == "inactive" assert runtime.recovery_requests == [] control.state = "failed" control.failure = { "reason_code": "mqtt_network_loop_failed", "modeling_command_attempted": True, "safe_to_retry": False, } else: control.state = "failed" control.failure = { "reason_code": "mqtt_network_loop_failed", "modeling_command_attempted": True, "safe_to_retry": False, } first = service.state() camera = service.camera_preview.snapshot() camera["phase"] = "error" camera["error"] = { "code": "camera-source-ended", "message": "synthetic later camera loss", } second = service.state() generation = second["connection_recovery"]["generation"] # A later Paho callback sees the already reconnecting runtime and therefore # joins this owner; it cannot queue a second capture wake or lineage. assert service._active_stream_recovery_admitted_for_runtime_loss() is True # noqa: SLF001 assert len(runtime.recovery_requests) == 1 assert second["connection_recovery"]["generation"] == generation assert second["connection_recovery"]["state"] == "reconnecting" assert second["acquisition"]["state"] == "acquiring" assert runtime.stop_calls == 0 def test_active_stream_recovery_survives_old_control_keepalive_failure( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) control, _physical = _install_composite_active_recovery_fixture( service, runtime, monkeypatch, ) admitted = service.state() assert admitted["connection_recovery"]["state"] == "reconnecting" with service._lock: # noqa: SLF001 assert service._active_stream_recovery_started_monotonic is not None # noqa: SLF001 service._active_stream_recovery_started_monotonic -= 60.0 # noqa: SLF001 control.state = "failed" control.failure = { "reason_code": "mqtt_network_loop_failed", "modeling_command_attempted": True, "safe_to_retry": False, } after_keepalive = service.state() assert after_keepalive["phase"] == "reconnecting" assert after_keepalive["connection_recovery"]["elapsed_ms"] >= 60_000 assert after_keepalive["connection_recovery"]["automatic_command_retry"] is False assert after_keepalive["acquisition"]["state"] == "acquiring" assert after_keepalive["selected_device_id"] == "test-ble-transport" assert after_keepalive["k1_ip"] == "192.168.1.20" assert runtime.stop_calls == 0 def test_recovered_projection_requires_a_live_ready_source_and_terminal_lease_retires_owner( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) _control, _physical = _install_composite_active_recovery_fixture( service, runtime, monkeypatch, ) reconnecting = service.state() lineage = service._active_stream_recovery_lineage # noqa: SLF001 assert lineage is not None assert reconnecting["connection_recovery"]["state"] == "reconnecting" runtime.phase = "idle" runtime.source_mode = "idle" runtime.source_ready = False projected_reconnecting_idle = service._active_stream_recovery_projection( # noqa: SLF001 runtime.snapshot() ) assert projected_reconnecting_idle["state"] == "inactive" assert projected_reconnecting_idle["automatic_read_only_rebind"] is False assert projected_reconnecting_idle["acquisition_id"] is None runtime.phase = "reconnecting" runtime.source_mode = "live" runtime.phase = "live" runtime.source_ready = True runtime.recovery_state = "recovered" runtime.recovery_attempt = 7 recovered = service._active_stream_recovery_projection(runtime.snapshot()) # noqa: SLF001 assert recovered["state"] == "recovered" assert recovered["attempt"] == 7 assert recovered["automatic_read_only_rebind"] is True # An out-of-order runtime tail cannot publish recovered while the receiver # is terminal. Durable physical-command history is owned by its ledger, not # by this process-local recovery contract. runtime.phase = "idle" runtime.source_mode = "idle" runtime.source_ready = False projected_idle = service._active_stream_recovery_projection(runtime.snapshot()) # noqa: SLF001 assert projected_idle["state"] == "inactive" assert projected_idle["automatic_read_only_rebind"] is False assert projected_idle["acquisition_id"] is None assert projected_idle["camera_recovery"] == "inactive" service._release_acquisition_session_lease() # noqa: SLF001 retired = service._active_stream_recovery_projection(runtime.snapshot()) # noqa: SLF001 assert retired["state"] == "inactive" assert retired["automatic_read_only_rebind"] is False assert retired["acquisition_id"] is None assert service._active_stream_recovery_lineage is None # noqa: SLF001 def test_local_force_finish_cancels_generation_and_is_idempotent_for_mode_reset( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) _control, physical = _install_composite_active_recovery_fixture( service, runtime, monkeypatch, runtime_phase="reconnecting", camera_phase="error", ) monkeypatch.setattr(service, "_seal_acquisition_capture_clock", lambda: None) state = service.state() acquisition = state["acquisition"] recovery = state["connection_recovery"] lineage = service._active_stream_recovery_lineage # noqa: SLF001 assert lineage is not None assert runtime.recovery_request_pending is True finished = service.force_finish_acquisition_locally( _force_finish_request( acquisition_id=acquisition["acquisition_id"], expected_state_revision=acquisition["state_revision"], expected_recovery_generation=recovery["generation"], ) ) assert finished["acquisition"]["state"] == "interrupted" assert finished["acquisition"]["result"]["device_stop"] == "not-sent" assert finished["acquisition"]["result"]["physical_command_sent"] is False assert finished["connection_recovery"]["state"] == "force-finished" assert runtime.stop_calls == 1 assert runtime.recovery_request_pending is False assert service._active_stream_recovery_lineage_is_current(lineage) is False # noqa: SLF001 assert service._physical_command_coordinator.snapshot() is physical # noqa: SLF001 with service._acquisition_lifecycle_gate: # noqa: SLF001 assert ( service._force_finish_active_acquisition_locally( # noqa: SLF001 reason_code="connection-mode-reset", require_recovery=False, ) is False ) @pytest.mark.parametrize("cleanup_failure", ["runtime", "camera"]) def test_local_force_finish_cleanup_failure_is_visible_retryable_and_fences_late_success( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, cleanup_failure: str, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) control, physical = _install_composite_active_recovery_fixture( service, runtime, monkeypatch, ) monkeypatch.setattr(service, "_seal_acquisition_capture_clock", lambda: None) before = service.state() acquisition = before["acquisition"] recovery = before["connection_recovery"] lineage = service._active_stream_recovery_lineage # noqa: SLF001 assert lineage is not None start_projects_before = list(control.start_projects) stop_calls_before = control.stop_calls original_stop_recording = service.camera_preview.stop_recording camera_failure_active = cleanup_failure == "camera" def stop_recording(**kwargs: object) -> dict[str, object]: nonlocal camera_failure_active if camera_failure_active: camera_failure_active = False raise RuntimeError("synthetic camera local cleanup failure") return original_stop_recording(**kwargs) # type: ignore[arg-type,return-value] if cleanup_failure == "runtime": runtime.stop_error = RuntimeError("synthetic runtime local cleanup failure") else: monkeypatch.setattr(service.camera_preview, "stop_recording", stop_recording) with pytest.raises(RuntimeError, match=f"synthetic {cleanup_failure} local cleanup failure"): service.force_finish_acquisition_locally( _force_finish_request( acquisition_id=acquisition["acquisition_id"], expected_state_revision=acquisition["state_revision"], expected_recovery_generation=recovery["generation"], ) ) failed = service.state() failed_operation = failed["last_operation"] assert failed["acquisition"]["state"] == "failed" assert failed["acquisition"]["cleanup_pending"] is True assert failed["acquisition"]["result"]["local_force_finish"] is True assert failed["acquisition"]["result"]["device_stop"] == "not-sent" assert failed["acquisition"]["result"]["physical_command_sent"] is False assert failed_operation["action"] == facade_module.ACTION_ACQUISITION_FORCE_FINISH assert failed_operation["status"] == "failed" assert failed_operation["stage_code"] == "local-cleanup-failed" assert failed_operation["error"]["retryable"] is True assert failed_operation["error"]["safe_to_retry"] is True assert failed_operation["error"]["side_effect_status"] == "none" assert service._active_stream_recovery_lineage_is_current(lineage) is False # noqa: SLF001 assert control.start_projects == start_projects_before assert control.stop_calls == stop_calls_before assert service._physical_command_coordinator.snapshot() is physical # noqa: SLF001 # The retry is local finalization only. It seals the retained evidence # lease through the compatibility stop seam and cannot revive recovery or # publish a physical command. runtime.stop_error = None recovered = service.stop() assert recovered["acquisition"]["state"] == "failed" assert recovered["acquisition"]["cleanup_pending"] is False assert recovered["source_mode"] == "idle" assert service._active_stream_recovery_lineage_is_current(lineage) is False # noqa: SLF001 assert control.start_projects == start_projects_before assert control.stop_calls == stop_calls_before assert service._physical_command_coordinator.snapshot() is physical # noqa: SLF001 def test_connection_mode_reset_supersedes_queued_force_finish_without_state_revival( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) _control, physical = _install_composite_active_recovery_fixture( service, runtime, monkeypatch, runtime_phase="reconnecting", camera_phase="error", ) monkeypatch.setattr(service, "_seal_acquisition_capture_clock", lambda: None) queued = service.state() queued_acquisition = queued["acquisition"] queued_recovery = queued["connection_recovery"] assert runtime.recovery_request_pending is True with service._acquisition_lifecycle_gate: # noqa: SLF001 reset_finished = service._force_finish_active_acquisition_locally( # noqa: SLF001 reason_code="connection-mode-reset", require_recovery=False, ) assert reset_finished is True with pytest.raises( facade_module.LocalAcquisitionLifecycleError, match="acquisition changed", ): service.force_finish_acquisition_locally( _force_finish_request( acquisition_id=queued_acquisition["acquisition_id"], expected_state_revision=queued_acquisition["state_revision"], expected_recovery_generation=queued_recovery["generation"], ) ) after = service.state() assert after["acquisition"]["state"] == "interrupted" assert after["connection_recovery"]["state"] == "force-finished" assert runtime.stop_calls == 1 assert runtime.recovery_request_pending is False assert service._physical_command_coordinator.snapshot() is physical # noqa: SLF001 def test_active_stream_recovery_scanning_resumes_same_physical_lineage_without_commands( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) control, physical = _install_composite_active_recovery_fixture( service, runtime, monkeypatch, ) service.state() lineage = service._active_stream_recovery_lineage # noqa: SLF001 assert lineage is not None physical["reconciliation_ready"] = True physical["observed_session_state"] = "scanning" control.state = "connection-ready" start_projects_before = list(control.start_projects) stop_calls_before = control.stop_calls reconcile_ids: list[str] = [] def reconcile_resolved_active(*, reconciliation_id: str) -> dict[str, object]: reconcile_ids.append(reconciliation_id) record = physical["record"] assert isinstance(record, dict) record["revision"] = int(record["revision"]) + 1 return record monkeypatch.setattr( service._physical_command_coordinator, # noqa: SLF001 "reconcile_resolved_active", reconcile_resolved_active, ) monkeypatch.setattr( control, "request_start", lambda **_kwargs: pytest.fail("recovery must not repeat START"), ) monkeypatch.setattr( control, "request_stop", lambda **_kwargs: pytest.fail("recovery must not send STOP"), ) decision = asyncio.run( service._reconcile_active_stream_physical_state_owned( # noqa: SLF001 lineage, attempt=3, ) ) assert decision == "resume" assert reconcile_ids == [ facade_module._active_stream_reconciliation_id( # noqa: SLF001 lineage, attempt=3, ) ] assert control.state == "scanning" assert control.start_projects == start_projects_before assert control.stop_calls == stop_calls_before # The physical audit revision advanced before MQTT SUBACK. A failed first # resubscribe must admit the same frozen lineage on attempt two. assert service._admit_active_stream_recovery_lineage() is lineage # noqa: SLF001 assert ( physical["record"] is service._physical_command_coordinator.snapshot()[ # noqa: SLF001 "record" ] ) def test_active_stream_control_adoption_gets_fresh_budget_after_slow_proof( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) control, physical = _install_composite_active_recovery_fixture( service, runtime, monkeypatch, ) service.state() lineage = service._active_stream_recovery_lineage # noqa: SLF001 assert lineage is not None physical["reconciliation_ready"] = True physical["observed_session_state"] = "scanning" control.state = "connection-ready" start_projects_before = list(control.start_projects) stop_calls_before = control.stop_calls original_adopt = control.adopt_reconciled_scanning original_snapshot = control.snapshot clock = [200.0] adoption_pending = [False] adoption_snapshots = [0] class FacadeTimeProxy: def monotonic(self) -> float: return clock[0] def __getattr__(self, name: str) -> Any: return getattr(time, name) def reconcile_resolved_active(*, reconciliation_id: str) -> dict[str, object]: assert reconciliation_id record = physical["record"] assert isinstance(record, dict) record["revision"] = int(record["revision"]) + 1 return record def delayed_adopt(**kwargs: object) -> dict[str, object]: result = original_adopt(**kwargs) adoption_pending[0] = True control.state = "active-recovery-requested" clock[0] = 205.01 return result def delayed_snapshot() -> dict[str, object]: if adoption_pending[0]: adoption_snapshots[0] += 1 if adoption_snapshots[0] >= 2: control.state = "scanning" clock[0] = 205.5 return original_snapshot() monkeypatch.setattr( service._physical_command_coordinator, # noqa: SLF001 "reconcile_resolved_active", reconcile_resolved_active, ) monkeypatch.setattr(control, "adopt_reconciled_scanning", delayed_adopt) monkeypatch.setattr(control, "snapshot", delayed_snapshot) monkeypatch.setattr(facade_module, "time", FacadeTimeProxy()) monkeypatch.setattr( control, "request_start", lambda **_kwargs: pytest.fail("recovery must not repeat START"), ) monkeypatch.setattr( control, "request_stop", lambda **_kwargs: pytest.fail("recovery must not send STOP"), ) decision = asyncio.run( service._reconcile_active_stream_physical_state_owned( # noqa: SLF001 lineage, attempt=4, ) ) assert decision == "resume" assert adoption_snapshots[0] >= 2 assert control.start_projects == start_projects_before assert control.stop_calls == stop_calls_before def test_epoch_one_to_three_rebind_namespaces_prior_acquisition_attempt_collision( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: """Regress the 2026-08-12 acq-cc9f5310 Wi-Fi recovery failure.""" service, runtime = service_with_fake_runtime(tmp_path) control, physical = _install_composite_active_recovery_fixture( service, runtime, monkeypatch, ) with service._lock: # noqa: SLF001 # Match the live process-local counter; another acquisition had # already persisted auto-rebind:2:6 in the global ledger history. service._active_stream_recovery_generation = 1 # noqa: SLF001 service.state() lineage = service._active_stream_recovery_lineage # noqa: SLF001 assert lineage is not None assert lineage.recovery_generation == 2 assert service._connection_supervisor.snapshot().host_path.epoch == 1 # noqa: SLF001 service._connection_supervisor.observe_host_path( # noqa: SLF001 HostPathProbeResult( available=False, fingerprint=None, interface=None, source_ipv4=None, route_class="unavailable", reason_code="host-route-unavailable", ) ) service._connection_supervisor.observe_host_path( # noqa: SLF001 HostPathProbeResult( available=True, fingerprint="route-after-wifi-return", interface="test0", source_ipv4="192.168.1.100", route_class="direct", ) ) assert service._connection_supervisor.snapshot().host_path.epoch == 3 # noqa: SLF001 assert service._active_stream_recovery_lineage_is_current(lineage) is True # noqa: SLF001 physical["reconciliation_ready"] = True physical["observed_session_state"] = "scanning" control.state = "connection-ready" start_projects_before = list(control.start_projects) stop_calls_before = control.stop_calls historical_ids = {"auto-rebind:2:6", "auto-rebind:2:7"} reconcile_ids: list[str] = [] def reconcile_resolved_active(*, reconciliation_id: str) -> dict[str, object]: if reconciliation_id in historical_ids: raise facade_module.PhysicalCommandTransitionError( "physical reconciliation id has already been used" ) reconcile_ids.append(reconciliation_id) record = physical["record"] assert isinstance(record, dict) record["revision"] = int(record["revision"]) + 1 return record monkeypatch.setattr( service._physical_command_coordinator, # noqa: SLF001 "reconcile_resolved_active", reconcile_resolved_active, ) monkeypatch.setattr( control, "request_start", lambda **_kwargs: pytest.fail("recovery must not replay START"), ) monkeypatch.setattr( control, "request_stop", lambda **_kwargs: pytest.fail("recovery must not publish STOP"), ) monkeypatch.setattr( service, "scan_ble", lambda *_args, **_kwargs: pytest.fail("recovery must not touch BLE"), ) monkeypatch.setattr( service, "connect", lambda *_args, **_kwargs: pytest.fail("recovery must not mutate network state"), ) decision = asyncio.run( service._reconcile_active_stream_physical_state_owned( # noqa: SLF001 lineage, attempt=6, ) ) expected_id = facade_module._active_stream_reconciliation_id( # noqa: SLF001 lineage, attempt=6, ) prior_process_lineage = facade_module.dataclass_replace( lineage, snapshot_runtime_id="snapshot-runtime-prior-process", acquisition_id="acq-b0cc1fe4-b934-4a98-a3e5-ecab7afd17c4", physical_operation_id="op-prior-acquisition-start", ) prior_process_id = facade_module._active_stream_reconciliation_id( # noqa: SLF001 prior_process_lineage, attempt=6, ) assert decision == "resume" assert reconcile_ids == [expected_id] assert expected_id not in historical_ids assert expected_id != prior_process_id assert expected_id == facade_module._active_stream_reconciliation_id( # noqa: SLF001 lineage, attempt=6, ) assert len(expected_id + ".device-info") <= 160 # Physical rebind only authorizes transport recovery. Visible recovery is # still fenced on the later non-empty post-published PCL. assert runtime.snapshot()["phase"] == "reconnecting" assert runtime.snapshot()["source_ready"] is False assert control.start_projects == start_projects_before assert control.stop_calls == stop_calls_before @pytest.mark.parametrize( ("observed_state", "expected_reason", "reconcile_expected"), [ ("ready", "device-reported-standby", True), ("scan_over", "device-reported-scan-over", True), ], ) def test_active_stream_recovery_device_standby_never_restarts_scanner( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, observed_state: str, expected_reason: str, reconcile_expected: bool, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) control, physical = _install_composite_active_recovery_fixture( service, runtime, monkeypatch, ) service.state() lineage = service._active_stream_recovery_lineage # noqa: SLF001 assert lineage is not None physical["reconciliation_ready"] = True physical["observed_session_state"] = observed_state control.state = "connection-ready" start_projects_before = list(control.start_projects) stop_calls_before = control.stop_calls reconcile_ids: list[str] = [] def reconcile_resolved_active(*, reconciliation_id: str) -> dict[str, object]: reconcile_ids.append(reconciliation_id) record = physical["record"] assert isinstance(record, dict) record["revision"] = int(record["revision"]) + 1 physical["resolved_active_recovery_required"] = False physical["resolved_scan_over_recovery_required"] = observed_state == "scan_over" physical["requires_reconciliation"] = observed_state == "scan_over" return record monkeypatch.setattr( service._physical_command_coordinator, # noqa: SLF001 "reconcile_resolved_active", reconcile_resolved_active, ) monkeypatch.setattr( control, "request_start", lambda **_kwargs: pytest.fail("standby recovery must not repeat START"), ) monkeypatch.setattr( control, "request_stop", lambda **_kwargs: pytest.fail("standby recovery must not send STOP"), ) decision = asyncio.run( service._reconcile_active_stream_physical_state_owned( # noqa: SLF001 lineage, attempt=4, ) ) assert decision == "standby" assert bool(reconcile_ids) is reconcile_expected assert control.start_projects == start_projects_before assert control.stop_calls == stop_calls_before assert service._active_stream_recovery_state == "standby" # noqa: SLF001 assert service._active_stream_recovery_reason_code == expected_reason # noqa: SLF001 assert physical["resolved_active_recovery_required"] is False assert physical["requires_reconciliation"] is (observed_state == "scan_over") def test_active_stream_recovery_wrong_identity_blocks_without_retry_or_camera_reopen( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) control, _physical = _install_composite_active_recovery_fixture( service, runtime, monkeypatch, ) service.state() lineage = service._active_stream_recovery_lineage # noqa: SLF001 assert lineage is not None start_projects_before = list(control.start_projects) stop_calls_before = control.stop_calls async def monitor_quiescent() -> bool: return True monkeypatch.setattr( service, "_await_connection_monitor_quiescence", monitor_quiescent, ) monkeypatch.setattr( service, "_acquire_k1_lifecycle_process_lease", lambda _holder: None, ) monkeypatch.setattr( service, "_release_k1_lifecycle_process_lease", lambda _holder: None, ) monkeypatch.setattr( service, "_probe_control_endpoint", lambda _target: facade_module._CorrelatedEndpointObservation( # noqa: SLF001 path=_direct_host_path(lineage.target_ipv4), reachable=True, reason_code=None, ), ) async def reject_wrong_identity(**_kwargs: object) -> None: raise facade_module.ConnectionVerificationError( "same IP belongs to another K1", reason_code="control-bootstrap-device-identity-unverified", ) camera_reopens: list[str] = [] monkeypatch.setattr( service, "_bootstrap_prestart_control_ready_owned", reject_wrong_identity, ) monkeypatch.setattr( service.camera_preview, "select", lambda *_args: camera_reopens.append("camera") or {}, ) decision = asyncio.run( service._recover_active_stream_connection_owned(lineage, 1) # noqa: SLF001 ) assert decision == "blocked" assert service._active_stream_recovery_state == "blocked" # noqa: SLF001 assert service._active_stream_recovery_reason_code == ( # noqa: SLF001 "control-bootstrap-device-identity-unverified" ) assert camera_reopens == [] assert control.start_projects == start_projects_before assert control.stop_calls == stop_calls_before def test_active_stream_recovery_owned_path_is_read_only_and_resumes_exact_lineage( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) control, _physical = _install_composite_active_recovery_fixture( service, runtime, monkeypatch, ) service.state() lineage = service._active_stream_recovery_lineage # noqa: SLF001 assert lineage is not None control.state = "idle" start_projects_before = list(control.start_projects) stop_calls_before = control.stop_calls events: list[tuple[str, object]] = [] async def monitor_quiescent() -> bool: events.append(("monitor", True)) return True def probe_exact_target(target_ipv4: str) -> facade_module._CorrelatedEndpointObservation: # noqa: SLF001 events.append(("probe", target_ipv4)) return facade_module._CorrelatedEndpointObservation( # noqa: SLF001 path=_direct_host_path(target_ipv4), reachable=True, reason_code=None, ) async def inspection_only_bootstrap(**kwargs: object) -> None: assert kwargs["connection_mode"] == lineage.connection_mode assert kwargs["inspection_only"] is True events.append(("device-info-status", kwargs["parent_operation_id"])) async def reconcile_same_lineage( candidate: facade_module._ActiveStreamRecoveryLineage, # noqa: SLF001 *, attempt: int, ) -> facade_module.RecoveryDecision: assert candidate is lineage events.append(("physical-read-only", attempt)) return "resume" def recover_local_camera( candidate: facade_module._ActiveStreamRecoveryLineage, # noqa: SLF001 ) -> facade_module.RecoveryDecision: assert candidate is lineage events.append(("camera-local", candidate.evidence_session_id)) return "resume" def forbidden_device_command(**_kwargs: object) -> object: pytest.fail("active stream recovery must not publish START or STOP") async def forbidden_ble_or_network_mutation(*_args: object, **_kwargs: object) -> object: pytest.fail("active stream recovery must not scan, write BLE, or provision Wi-Fi") monkeypatch.setattr(service, "_await_connection_monitor_quiescence", monitor_quiescent) monkeypatch.setattr( service, "_acquire_k1_lifecycle_process_lease", lambda holder: events.append(("lease-acquire", holder)), ) monkeypatch.setattr( service, "_release_k1_lifecycle_process_lease", lambda holder: events.append(("lease-release", holder)), ) monkeypatch.setattr(service, "_probe_control_endpoint", probe_exact_target) monkeypatch.setattr( service, "_bootstrap_prestart_control_ready_owned", inspection_only_bootstrap, ) monkeypatch.setattr( service, "_reconcile_active_stream_physical_state_owned", reconcile_same_lineage, ) monkeypatch.setattr(service, "_recover_active_stream_camera_owned", recover_local_camera) monkeypatch.setattr(control, "request_start", forbidden_device_command) monkeypatch.setattr(control, "request_stop", forbidden_device_command) monkeypatch.setattr(service, "scan_ble", forbidden_ble_or_network_mutation) monkeypatch.setattr(service, "connect", forbidden_ble_or_network_mutation) decision = asyncio.run( service._recover_active_stream_connection_owned(lineage, 5) # noqa: SLF001 ) assert decision == "resume" assert events == [ ("monitor", True), ("lease-acquire", "network"), ("probe", lineage.target_ipv4), ( "device-info-status", ( f"active-stream-recovery:{lineage.acquisition_id}:" f"{lineage.recovery_generation}" ), ), ("physical-read-only", 5), ("lease-release", "network"), ] # Camera recovery is now intentionally downstream of the post-Rerun # checkpoint rebind. Control recovery alone cannot open/promote media. assert ("camera-local", lineage.evidence_session_id) not in events assert control.start_projects == start_projects_before assert control.stop_calls == stop_calls_before assert service._active_stream_recovery_lineage_is_current(lineage) is True # noqa: SLF001 assert service._active_stream_recovery_reason_code == "mqtt-resubscribe-pending" # noqa: SLF001 def test_incident_recovery_retires_epoch_one_control_and_retries_fresh_inspection_binding( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: """Regress the 2026-08-12 acq-209faf83 route-loss failure. The incident START/control owner was bound to host-path epoch 1. Wi-Fi loss rotated that epoch, and the first fresh inspection raced one more association edge. That expected local binding loss must keep retrying; the next inspection must bind the current epoch without replaying any physical or network command. """ service, runtime = service_with_fake_runtime(tmp_path) class IncidentControl(FakeInteractiveControlSession): def __init__(self) -> None: super().__init__() self.opened_bindings: list[ApplicationConnectionBinding] = [] self.close_calls = 0 self.retire_calls = 0 self.binding_validation_calls = 0 def validate_connection_binding(self) -> None: self.binding_validation_calls += 1 raise AssertionError("recovery must not validate/reuse the epoch-1 owner") def close(self) -> None: self.close_calls += 1 super().close() def retire_for_network_change(self, **kwargs: object) -> dict[str, object]: self.retire_calls += 1 return super().retire_for_network_change(**kwargs) def open( self, *, connection_binding: ApplicationConnectionBinding, inspection_only: bool = False, **kwargs: object, ) -> dict[str, object]: self.opened_bindings.append(connection_binding) if len(self.opened_bindings) == 1: # Match the live failure: the newly opened worker observed one # more route/association epoch before its first MQTT publish. service._connection_supervisor.observe_host_path( # noqa: SLF001 recovered_path_b ) self.state = "failed" self.failure = { "reason_code": "application-connection-binding-lost", "safe_to_retry": True, "modeling_command_attempted": False, } return self.snapshot() self.session_generation += 1 super().open( connection_binding=connection_binding, inspection_only=inspection_only, **kwargs, ) assert self.verified_control is not None self.verified_control = { **self.verified_control, "control_session_id": ( f"fake-recovery-control-{self.session_generation}" ), "producer_generation": self.session_generation, } return self.snapshot() control = IncidentControl() service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 _control, _physical = _install_composite_active_recovery_fixture( service, runtime, monkeypatch, runtime_phase="reconnecting", camera_phase="streaming", ) # The fixture installs its own fake session; replace it before freezing the # recovery lineage while retaining the exact already-resolved START proof. service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 control.state = "scanning" original_epoch = service._connection_supervisor.snapshot().host_path.epoch # noqa: SLF001 assert original_epoch == 1 service.state() lineage = service._active_stream_recovery_lineage # noqa: SLF001 assert lineage is not None lost_path = HostPathProbeResult( available=False, fingerprint=None, interface=None, source_ipv4=None, route_class="unavailable", reason_code="host-route-unavailable", ) recovered_path_a = HostPathProbeResult( available=True, fingerprint="incident-route-after-wifi-return-a", interface="test0", source_ipv4="192.168.68.100", route_class="direct", ) recovered_path_b = HostPathProbeResult( available=True, fingerprint="incident-route-after-wifi-return-b", interface="test0", source_ipv4="192.168.68.100", route_class="direct", ) service._connection_supervisor.observe_host_path(lost_path) # noqa: SLF001 assert service._connection_supervisor.snapshot().host_path.epoch == 2 # noqa: SLF001 probe_paths = iter((recovered_path_a, recovered_path_b)) def probe_current_epoch( target_ipv4: str, ) -> facade_module._CorrelatedEndpointObservation: # noqa: SLF001 path = next(probe_paths) service._observe_connection_transport( # noqa: SLF001 target_ipv4, path=path, reachable=True, ) return facade_module._CorrelatedEndpointObservation( # noqa: SLF001 path=path, reachable=True, reason_code=None, ) async def monitor_quiescent() -> bool: return True async def reconcile_same_lineage( candidate: facade_module._ActiveStreamRecoveryLineage, # noqa: SLF001 *, attempt: int, ) -> facade_module.RecoveryDecision: assert candidate is lineage assert attempt == 6 return "resume" service._bootstrap_prestart_control_ready_owned = MethodType( # type: ignore[method-assign] # noqa: SLF001 XgridsK1CompatibilityService._bootstrap_prestart_control_ready_owned, # noqa: SLF001 service, ) monkeypatch.setattr(service, "_await_connection_monitor_quiescence", monitor_quiescent) monkeypatch.setattr(service, "_probe_control_endpoint", probe_current_epoch) monkeypatch.setattr(service, "_acquire_k1_lifecycle_process_lease", lambda _holder: None) monkeypatch.setattr(service, "_release_k1_lifecycle_process_lease", lambda _holder: None) monkeypatch.setattr(service, "_acquire_application_control_process_lease", lambda: None) monkeypatch.setattr(service, "_reconcile_application_control_process_lease", lambda _s: None) monkeypatch.setattr( service, "_reconcile_active_stream_physical_state_owned", reconcile_same_lineage, ) monkeypatch.setattr( service, "_recover_active_stream_camera_owned", lambda candidate: "resume" if candidate is lineage else "blocked", ) monkeypatch.setattr( control, "request_start", lambda **_kwargs: pytest.fail("recovery must not replay START"), ) monkeypatch.setattr( control, "request_stop", lambda **_kwargs: pytest.fail("recovery must not publish STOP"), ) monkeypatch.setattr( service, "scan_ble", lambda *_args, **_kwargs: pytest.fail("recovery must not touch BLE"), ) monkeypatch.setattr( service, "connect", lambda *_args, **_kwargs: pytest.fail("recovery must not mutate network state"), ) first = asyncio.run( service._recover_active_stream_connection_owned(lineage, 5) # noqa: SLF001 ) assert first == "retry" assert service._active_stream_recovery_state == "reconnecting" # noqa: SLF001 assert service._active_stream_recovery_reason_code == ( # noqa: SLF001 "application-connection-binding-lost" ) assert control.opened_bindings[0].host_path_epoch == 3 assert control.close_calls == 1 assert control.retire_calls == 2 assert control.binding_validation_calls == 0 second = asyncio.run( service._recover_active_stream_connection_owned(lineage, 6) # noqa: SLF001 ) assert second == "resume" assert [binding.host_path_epoch for binding in control.opened_bindings] == [3, 4] assert control.opened_bindings[-1].host_path_epoch == ( service._connection_supervisor.snapshot().host_path.epoch # noqa: SLF001 ) assert control.inspection_only is True assert control.state == "connection-ready" assert service._active_stream_recovery_lineage_is_current(lineage) is True # noqa: SLF001 assert service._active_stream_recovery_reason_code == "mqtt-resubscribe-pending" # noqa: SLF001 def test_active_stream_recovery_waits_for_terminal_control_worker_retirement( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) control, _physical = _install_composite_active_recovery_fixture( service, runtime, monkeypatch, ) service.state() lineage = service._active_stream_recovery_lineage # noqa: SLF001 assert lineage is not None control.state = "failed" control.failure = { "reason_code": "mqtt_network_loop_failed", "modeling_command_attempted": True, "safe_to_retry": False, } retire_attempts = 0 def retire_terminal_control(**_kwargs: object) -> dict[str, object]: nonlocal retire_attempts retire_attempts += 1 if retire_attempts == 1: raise ApplicationAcceptanceError("control session worker is still retiring") control.state = "idle" control.verified_control = None return control.snapshot() async def monitor_quiescent() -> bool: return True async def inspection_only_bootstrap(**_kwargs: object) -> None: return None async def reconcile_same_lineage( candidate: facade_module._ActiveStreamRecoveryLineage, # noqa: SLF001 *, attempt: int, ) -> facade_module.RecoveryDecision: assert candidate is lineage assert attempt == 2 return "resume" monkeypatch.setattr(control, "retire_for_network_change", retire_terminal_control) monkeypatch.setattr(service, "_await_connection_monitor_quiescence", monitor_quiescent) monkeypatch.setattr( service, "_acquire_k1_lifecycle_process_lease", lambda _holder: None, ) monkeypatch.setattr( service, "_release_k1_lifecycle_process_lease", lambda _holder: None, ) monkeypatch.setattr( service, "_probe_control_endpoint", lambda _target: facade_module._CorrelatedEndpointObservation( # noqa: SLF001 path=_direct_host_path(lineage.target_ipv4), reachable=True, reason_code=None, ), ) monkeypatch.setattr( service, "_bootstrap_prestart_control_ready_owned", inspection_only_bootstrap, ) monkeypatch.setattr( service, "_reconcile_active_stream_physical_state_owned", reconcile_same_lineage, ) monkeypatch.setattr( service, "_recover_active_stream_camera_owned", lambda candidate: "resume" if candidate is lineage else "blocked", ) decision = asyncio.run( service._recover_active_stream_connection_owned(lineage, 2) # noqa: SLF001 ) assert decision == "resume" assert retire_attempts == 2 assert service._active_stream_recovery_state == "reconnecting" # noqa: SLF001 assert service._active_stream_recovery_reason_code == "mqtt-resubscribe-pending" # noqa: SLF001 def test_active_stream_recovery_exact_device_system_fault_is_terminal_without_commands( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) control, _physical = _install_composite_active_recovery_fixture( service, runtime, monkeypatch, ) service.state() lineage = service._active_stream_recovery_lineage # noqa: SLF001 assert lineage is not None control.state = "idle" start_projects_before = list(control.start_projects) stop_calls_before = control.stop_calls async def monitor_quiescent() -> bool: return True async def bootstrap_system_fault(**kwargs: object) -> None: assert kwargs["inspection_only"] is True control.state = "failed" control.failure = { "reason_code": "application-device-system-error", "modeling_command_attempted": False, "safe_to_retry": False, } monkeypatch.setattr(service, "_await_connection_monitor_quiescence", monitor_quiescent) monkeypatch.setattr( service, "_acquire_k1_lifecycle_process_lease", lambda _holder: None, ) monkeypatch.setattr( service, "_release_k1_lifecycle_process_lease", lambda _holder: None, ) monkeypatch.setattr( service, "_probe_control_endpoint", lambda _target: facade_module._CorrelatedEndpointObservation( # noqa: SLF001 path=_direct_host_path(lineage.target_ipv4), reachable=True, reason_code=None, ), ) monkeypatch.setattr( service, "_bootstrap_prestart_control_ready_owned", bootstrap_system_fault, ) monkeypatch.setattr( service, "_recover_active_stream_camera_owned", lambda _candidate: pytest.fail("system fault must not reopen camera"), ) monkeypatch.setattr( control, "request_start", lambda **_kwargs: pytest.fail("system fault recovery must not repeat START"), ) monkeypatch.setattr( control, "request_stop", lambda **_kwargs: pytest.fail("system fault recovery must not send STOP"), ) decision = asyncio.run( service._recover_active_stream_connection_owned(lineage, 6) # noqa: SLF001 ) assert decision == "fault" assert service._active_stream_recovery_state == "fault" # noqa: SLF001 assert service._active_stream_recovery_reason_code == ( # noqa: SLF001 "active-stream-recovery-system-error" ) assert service._active_stream_recovery_terminal_outcome == "fault" # noqa: SLF001 assert control.start_projects == start_projects_before assert control.stop_calls == stop_calls_before def test_active_stream_recovery_bootstrap_system_error_is_normalized_terminal_fault( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) control, _physical = _install_composite_active_recovery_fixture( service, runtime, monkeypatch, ) service.state() lineage = service._active_stream_recovery_lineage # noqa: SLF001 assert lineage is not None control.state = "idle" start_projects_before = list(control.start_projects) stop_calls_before = control.stop_calls monkeypatch.setattr(service, "_seal_acquisition_capture_clock", lambda: None) async def monitor_quiescent() -> bool: return True async def bootstrap_system_error(**kwargs: object) -> None: assert kwargs["inspection_only"] is True raise facade_module.ConnectionVerificationError( "DeviceInfo reported a system fault", reason_code="application-device-system-error", ) monkeypatch.setattr(service, "_await_connection_monitor_quiescence", monitor_quiescent) monkeypatch.setattr( service, "_acquire_k1_lifecycle_process_lease", lambda _holder: None, ) monkeypatch.setattr( service, "_release_k1_lifecycle_process_lease", lambda _holder: None, ) monkeypatch.setattr( service, "_probe_control_endpoint", lambda _target: facade_module._CorrelatedEndpointObservation( # noqa: SLF001 path=_direct_host_path(lineage.target_ipv4), reachable=True, reason_code=None, ), ) monkeypatch.setattr( service, "_bootstrap_prestart_control_ready_owned", bootstrap_system_error, ) monkeypatch.setattr( service, "_reconcile_active_stream_physical_state_owned", lambda *_args, **_kwargs: pytest.fail( "bootstrap system fault must stop before physical reconciliation" ), ) monkeypatch.setattr( service, "_recover_active_stream_camera_owned", lambda _candidate: pytest.fail("bootstrap system fault must not reopen camera"), ) monkeypatch.setattr( control, "request_start", lambda **_kwargs: pytest.fail("system fault recovery must not repeat START"), ) monkeypatch.setattr( control, "request_stop", lambda **_kwargs: pytest.fail("system fault recovery must not send STOP"), ) decision = asyncio.run( service._recover_active_stream_connection_owned(lineage, 7) # noqa: SLF001 ) assert decision == "fault" assert service._active_stream_recovery_state == "fault" # noqa: SLF001 assert service._active_stream_recovery_reason_code == ( # noqa: SLF001 "active-stream-recovery-system-error" ) assert service._active_stream_recovery_terminal_outcome == "fault" # noqa: SLF001 assert control.start_projects == start_projects_before assert control.stop_calls == stop_calls_before terminal = service.state() assert terminal["acquisition"]["state"] == "failed" assert terminal["acquisition"]["result"]["device_state"] == "fault" assert terminal["source_mode"] == "idle" assert runtime.stop_calls == 1 assert control.start_projects == start_projects_before assert control.stop_calls == stop_calls_before def test_active_stream_recovery_never_restarts_nontransport_camera_error( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) _control, _physical = _install_composite_active_recovery_fixture( service, runtime, monkeypatch, ) service.state() lineage = service._active_stream_recovery_lineage # noqa: SLF001 assert lineage is not None camera = service.camera_preview.snapshot() camera["phase"] = "error" camera["error"] = { "code": "camera-artifact-write-failed", "message": "synthetic local artifact failure", } restart_calls: list[str] = [] monkeypatch.setattr( service.camera_preview, "restart_recording_producer", lambda *_args, **_kwargs: restart_calls.append("restart") or {}, ) decision = service._recover_active_stream_camera_owned(lineage) # noqa: SLF001 assert decision == "blocked" assert restart_calls == [] @pytest.mark.parametrize( ("camera_phase", "camera_error", "producer_alive", "active_epoch"), [ ("connecting", None, False, 7), ( "error", { "code": "invalid-fmp4", "message": "synthetic pre-first-media camera failure", }, False, 7, ), ( "error", { "code": "invalid-fmp4", "message": "synthetic detached pre-finalize camera failure", }, False, None, ), ], ) def test_active_stream_recovery_keeps_pre_first_media_camera_downstream_of_mqtt( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, camera_phase: str, camera_error: dict[str, str] | None, producer_alive: bool, active_epoch: int | None, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) control, _physical = _install_composite_active_recovery_fixture( service, runtime, monkeypatch, camera_phase="streaming", ) service.state() lineage = service._active_stream_recovery_lineage # noqa: SLF001 assert lineage is not None start_projects_before = list(control.start_projects) stop_calls_before = control.stop_calls camera = service.camera_preview.snapshot() camera.update( { "phase": camera_phase, "generation": 7, "active_source_id": facade_module.DEFAULT_ACQUISITION_CAMERA_SOURCE, "recording": { "active": True, "session": lineage.evidence_session_id, "active_epoch": active_epoch, "producer_alive": producer_alive, "producer_age_ms": ( facade_module.ACTIVE_STREAM_CAMERA_STALL_MILLISECONDS + 1 ), "last_segment_age_ms": None, "committed_media_segment_count": 0, "completed_epochs": 0, "last_summary": None, }, "error": camera_error, } ) activation_lineage = ( lineage.acquisition_id, lineage.evidence_session_id, lineage.runtime_producer_generation, ) with service._lock: # noqa: SLF001 service._camera_activation_lineage = activation_lineage # noqa: SLF001 restart_calls: list[str] = [] monkeypatch.setattr( service.camera_preview, "restart_recording_producer", lambda *_args, **_kwargs: restart_calls.append("restart") or {}, ) decision = service._recover_active_stream_camera_owned(lineage) # noqa: SLF001 assert decision == "resume" assert restart_calls == [] with service._lock: # noqa: SLF001 if camera_phase == "error" or producer_alive is False: assert service._camera_activation_lineage is None # noqa: SLF001 assert service._camera_activation_retry_lineage == activation_lineage # noqa: SLF001 else: assert service._camera_activation_lineage == activation_lineage # noqa: SLF001 state = service.state() assert state["phase"] == "reconnecting" assert state["acquisition"]["state"] == "acquiring" assert state["camera_preview"]["activation_admission"]["state"] == "activating" assert runtime.stop_calls == 0 assert control.start_projects == start_projects_before assert control.stop_calls == stop_calls_before def test_active_stream_recovery_never_retries_invalid_fmp4_after_media_commit( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) control, _physical = _install_composite_active_recovery_fixture( service, runtime, monkeypatch, camera_phase="streaming", ) service.state() lineage = service._active_stream_recovery_lineage # noqa: SLF001 assert lineage is not None camera = service.camera_preview.snapshot() camera.update( { "phase": "error", "generation": 7, "active_source_id": facade_module.DEFAULT_ACQUISITION_CAMERA_SOURCE, "recording": { "active": True, "session": lineage.evidence_session_id, "active_epoch": 7, "committed_media_segment_count": 1, "producer_alive": False, "producer_age_ms": 1_000, "last_segment_age_ms": 0, "completed_epochs": 0, "last_summary": None, }, "error": { "code": "invalid-fmp4", "message": "synthetic corruption after the first media commit", }, } ) activation_lineage = ( lineage.acquisition_id, lineage.evidence_session_id, lineage.runtime_producer_generation, ) with service._lock: # noqa: SLF001 service._camera_activation_lineage = activation_lineage # noqa: SLF001 restart_calls: list[str] = [] monkeypatch.setattr( service.camera_preview, "restart_recording_producer", lambda *_args, **_kwargs: restart_calls.append("restart") or {}, ) monkeypatch.setattr(service, "_seal_acquisition_capture_clock", lambda: None) assert service._recover_active_stream_camera_owned(lineage) == "blocked" # noqa: SLF001 assert restart_calls == [] with service._lock: # noqa: SLF001 assert service._camera_activation_lineage == activation_lineage # noqa: SLF001 assert service._camera_activation_retry_lineage is None # noqa: SLF001 terminal = service.state() assert terminal["acquisition"]["state"] == "failed" assert terminal["acquisition"]["result"]["camera_failure_code"] == "invalid-fmp4" assert runtime.stop_calls == 1 assert control.stop_calls == 0 def test_active_stream_recovery_reopens_exact_camera_epoch_once_and_fences_stale_lineage( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) _control, _physical = _install_composite_active_recovery_fixture( service, runtime, monkeypatch, ) state = service.state() lineage = service._active_stream_recovery_lineage # noqa: SLF001 assert lineage is not None camera = dict(state["camera_preview"]) camera["phase"] = "streaming" camera["generation"] = 7 camera["active_source_id"] = facade_module.DEFAULT_ACQUISITION_CAMERA_SOURCE camera["recording"] = { "active": True, "session": lineage.evidence_session_id, "active_epoch": 7, "producer_alive": True, "producer_age_ms": facade_module.ACTIVE_STREAM_CAMERA_STALL_MILLISECONDS + 1, "last_segment_age_ms": (facade_module.ACTIVE_STREAM_CAMERA_STALL_MILLISECONDS + 1), "committed_media_segment_count": 4, } camera_calls: list[tuple[str, str, int, str, int | None, int]] = [] perception_binds: list[tuple[str, int]] = [] def snapshot_camera() -> dict[str, object]: return dict(camera) def reopen_camera( source_id: str, target: str, *, expected_generation: int, expected_recording_session: str, expected_active_epoch: int | None, expected_recording_media_segment_count: int, pre_detach_fence: Callable[[Callable[[], bool]], bool], commit_fence: Callable[[Callable[[], bool]], bool] | None = None, committed_before_start: Callable[[dict[str, object]], None] | None = None, ) -> dict[str, object]: camera_calls.append( ( source_id, target, expected_generation, expected_recording_session, expected_active_epoch, expected_recording_media_segment_count, ) ) assert pre_detach_fence(lambda: True) is True camera.update( { "phase": "connecting", "generation": expected_generation + 1, "active_source_id": source_id, "recording": { "active": True, "session": lineage.evidence_session_id, "active_epoch": 8, "producer_alive": True, "producer_age_ms": 0, "last_segment_age_ms": 0, "last_media_segment_age_ms": None, "committed_media_segment_count": 4, "media_ready": False, "current_epoch": { "generation": 8, "init_committed": False, "init_committed_age_ms": None, "first_media_committed": False, "first_media_committed_age_ms": None, "committed_media_segment_count": 0, "last_media_segment_age_ms": None, }, }, } ) assert commit_fence is not None assert committed_before_start is not None assert commit_fence( lambda: committed_before_start(dict(camera)) is None ) is True return dict(camera) def bind_perception(session: str, reopened: dict[str, object]) -> None: recording = reopened["recording"] assert isinstance(recording, dict) active_epoch = recording["active_epoch"] assert isinstance(active_epoch, int) perception_binds.append((session, active_epoch)) monkeypatch.setattr(service.camera_preview, "snapshot", snapshot_camera) monkeypatch.setattr( service.camera_preview, "restart_recording_producer", reopen_camera, ) monkeypatch.setattr( service, "_bind_live_perception_camera", bind_perception, ) runtime.phase = "live" runtime.source_ready = True runtime.recovery_state = "recovered" with service._lock: # noqa: SLF001 service._active_stream_recovery_state = "recovered" # noqa: SLF001 assert ( # noqa: SLF001 service._recover_active_stream_camera_owned( lineage, require_runtime_reconnecting=False, ) == "resume" ) assert ( # noqa: SLF001 service._recover_active_stream_camera_owned( lineage, require_runtime_reconnecting=False, ) == "resume" ) assert camera_calls == [ ( facade_module.DEFAULT_ACQUISITION_CAMERA_SOURCE, lineage.target_ipv4, 7, lineage.evidence_session_id, 7, 4, ) ] assert perception_binds == [(lineage.evidence_session_id, 8)] assert camera["recording"]["media_ready"] is False recovery = service._active_stream_recovery_projection( # noqa: SLF001 runtime.snapshot(), camera=camera, ) assert recovery["camera_recovery"] == "owned" assert recovery["camera_media_state"] == "pending-init" assert recovery["camera_media_ready"] is False assert recovery["camera_epoch"] == { "generation": 8, "init_committed": False, "init_committed_age_ms": None, "first_media_committed": False, "first_media_committed_age_ms": None, "committed_media_segment_count": 0, "last_media_segment_age_ms": None, } runtime.producer_generation += 1 assert ( # noqa: SLF001 service._recover_active_stream_camera_owned( lineage, require_runtime_reconnecting=False, ) == "blocked" ) assert len(camera_calls) == 1 def test_device_standby_retires_sources_after_terminal_local_stop_failure( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) control = FakeInteractiveControlSession() service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 binding = _seed_supervised_connection(service) service._compatibility_attestation = ATTESTATION.model_dump(mode="json") # noqa: SLF001 prepared = service.prepare_acquisition( _prepare_request( project_name="TEST001", host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] service.start_acquisition( _start_request( acquisition_id=acquisition_id, physical_acceptance=PHYSICAL_ACCEPTANCE, ) ) start_operation_id = service._acquisition_start_operation_id # noqa: SLF001 assert isinstance(start_operation_id, str) physical_proof = _exact_start_physical_proof( operation_id=start_operation_id, acquisition_id=acquisition_id, binding=binding, resolved=True, ) monkeypatch.setattr( service._physical_command_coordinator, # noqa: SLF001 "snapshot", lambda: physical_proof, ) runtime.mark_ready() runtime.pcl_frames = 1 service.state() stopping = service.stop_acquisition( _stop_request( acquisition_id=acquisition_id, mode="graceful", 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.state == "completed" assert recovered["acquisition"]["state"] == "failed" assert recovered["application_control_session"]["state"] == "completed" assert runtime.stop_calls == 1 def test_second_start_conflict_does_not_tear_down_start_owner(tmp_path: Path) -> None: service, runtime = service_with_fake_runtime(tmp_path) prepared = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] service.start_acquisition(_start_request(acquisition_id=acquisition_id)) with pytest.raises(RuntimeError, match="состояния starting"): service.start_acquisition(_start_request(acquisition_id=acquisition_id)) state = service.state() start_operations = [ item for item in state["operations"] if item["action"] == "acquisition.start" ] assert state["acquisition"]["state"] == "starting" assert runtime.stop_calls == 0 assert [item["status"] for item in start_operations] == ["running", "failed"] assert start_operations[-1]["error"]["category"] == "conflict" def test_state_waits_for_atomic_start_handoff( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) prepared = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] entered_start = threading.Event() release_start = threading.Event() state_started = threading.Event() state_finished = threading.Event() worker_errors: list[BaseException] = [] snapshots: list[dict[str, Any]] = [] original_start_live = runtime.start_live def blocked_start_live(*args: object, **kwargs: object) -> None: entered_start.set() if not release_start.wait(timeout=2): raise TimeoutError("test did not release start handoff") original_start_live(*args, **kwargs) # type: ignore[arg-type] def start_worker() -> None: try: service.start_acquisition(_start_request(acquisition_id=acquisition_id)) except BaseException as exc: # pragma: no cover - asserted below worker_errors.append(exc) def state_worker() -> None: state_started.set() try: snapshots.append(service.state()) except BaseException as exc: # pragma: no cover - asserted below worker_errors.append(exc) finally: state_finished.set() monkeypatch.setattr(runtime, "start_live", blocked_start_live) start_thread = threading.Thread(target=start_worker) state_thread = threading.Thread(target=state_worker) start_thread.start() assert entered_start.wait(timeout=2) state_thread.start() assert state_started.wait(timeout=2) assert not state_finished.wait(timeout=0.05) release_start.set() start_thread.join(timeout=2) state_thread.join(timeout=2) assert not start_thread.is_alive() assert not state_thread.is_alive() assert worker_errors == [] assert snapshots[0]["acquisition"]["state"] == "starting" assert runtime.source_mode == "live" assert service._acquisition_session_lease is not None # noqa: SLF001 def test_abort_waits_for_start_handoff_then_stops_owned_producers( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) prepared = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] entered_start = threading.Event() release_start = threading.Event() abort_finished = threading.Event() worker_errors: list[BaseException] = [] original_start_live = runtime.start_live def blocked_start_live(*args: object, **kwargs: object) -> None: entered_start.set() if not release_start.wait(timeout=2): raise TimeoutError("test did not release start handoff") original_start_live(*args, **kwargs) # type: ignore[arg-type] def start_worker() -> None: try: service.start_acquisition(_start_request(acquisition_id=acquisition_id)) except BaseException as exc: # pragma: no cover - asserted below worker_errors.append(exc) def abort_worker() -> None: try: service.abort_acquisition(_abort_request(acquisition_id=acquisition_id)) except BaseException as exc: # pragma: no cover - asserted below worker_errors.append(exc) finally: abort_finished.set() monkeypatch.setattr(runtime, "start_live", blocked_start_live) start_thread = threading.Thread(target=start_worker) abort_thread = threading.Thread(target=abort_worker) start_thread.start() assert entered_start.wait(timeout=2) abort_thread.start() assert not abort_finished.wait(timeout=0.05) release_start.set() start_thread.join(timeout=2) abort_thread.join(timeout=2) assert worker_errors == [] state = service.state() assert state["acquisition"]["state"] == "aborted" assert runtime.source_mode == "idle" assert service._acquisition_session_lease is None # noqa: SLF001 def test_camera_selection_finishes_before_serialized_acquisition_stop( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) prepared = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] device_session_id = prepared["device_session"]["device_session_id"] service.start_acquisition(_start_request(acquisition_id=acquisition_id)) control = FakeInteractiveControlSession() service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 _seed_supervised_connection(service) service._device_session_id = device_session_id # noqa: SLF001 out_dir = service._acquisition_out_dir # noqa: SLF001 assert out_dir is not None entered_camera_arm = threading.Event() release_camera_arm = threading.Event() stop_finished = threading.Event() worker_errors: list[BaseException] = [] events: list[str] = [] def blocked_camera_arm(_out_dir: Path, *, require_session: bool = False) -> None: assert require_session is True events.append("arm") entered_camera_arm.set() if not release_camera_arm.wait(timeout=2): raise TimeoutError("test did not release camera arm") def select_worker() -> None: try: service.select_camera_preview( CameraPreviewSelectRequest( source_id="sensor.camera.left", device_session_id=device_session_id, ) ) except BaseException as exc: # pragma: no cover - asserted below worker_errors.append(exc) def stop_worker() -> None: try: service.stop_acquisition( _stop_request( acquisition_id=acquisition_id, mode="capture-only", ) ) except BaseException as exc: # pragma: no cover - asserted below worker_errors.append(exc) finally: stop_finished.set() camera_snapshot = service.camera_preview.snapshot() camera_snapshot.update( { "phase": "streaming", "generation": 1, "active_source_id": facade_module.DEFAULT_ACQUISITION_CAMERA_SOURCE, "recording": { "active": True, "session": out_dir.name, "active_epoch": 1, "media_ready": True, "current_epoch": { "generation": 1, "init_committed": True, "first_media_committed": True, }, }, } ) monkeypatch.setattr(service, "_arm_camera_recording", blocked_camera_arm) monkeypatch.setattr( service.camera_preview, "snapshot", lambda: camera_snapshot, ) monkeypatch.setattr( service.camera_preview, "select", lambda source_id, _target: ( events.append("select") or { "active_source_id": source_id, "recording": {"active": False}, } ), ) monkeypatch.setattr( service.camera_preview, "stop_recording", lambda **_kwargs: events.append("camera-stop"), ) monkeypatch.setattr(runtime, "stop", lambda: events.append("runtime-stop")) select_thread = threading.Thread(target=select_worker) stop_thread = threading.Thread(target=stop_worker) select_thread.start() assert entered_camera_arm.wait(timeout=2) stop_thread.start() assert not stop_finished.wait(timeout=0.05) release_camera_arm.set() select_thread.join(timeout=2) stop_thread.join(timeout=2) assert worker_errors == [] assert events == ["arm", "select", "camera-stop", "runtime-stop"] assert service.state()["acquisition"]["state"] == "completed" assert service._acquisition_session_lease is None # noqa: SLF001 def test_receiver_start_failure_seals_stopped_session_before_releasing_lease( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) prepared = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] events: list[str] = [] def start_live( _host: str, out_dir: Path, *, duration_seconds: float | None, project_name: str, recover_connection: object | None = None, ) -> None: assert duration_seconds is None assert project_name == PROJECT_NAME assert recover_connection is None events.append("start") out_dir.mkdir(parents=True) runtime.phase = "starting_live" runtime.source_mode = "live" raise RuntimeError("synthetic receiver start failure") def stop_runtime() -> None: events.append("runtime") runtime.phase = "idle" runtime.source_mode = "idle" monkeypatch.setattr(runtime, "start_live", start_live) monkeypatch.setattr(runtime, "stop", stop_runtime) camera_arm_calls: list[Path] = [] monkeypatch.setattr( service, "_arm_camera_recording", lambda out_dir, **_kwargs: camera_arm_calls.append(out_dir), ) monkeypatch.setattr( service.camera_preview, "stop_recording", lambda **_kwargs: events.append("camera"), ) monkeypatch.setattr( facade_module, "seal_capture_clock", lambda _capture_root: events.append("seal"), ) with pytest.raises(RuntimeError, match="synthetic receiver start failure"): service.start_acquisition(_start_request(acquisition_id=acquisition_id)) state = service.state() assert state["acquisition"]["state"] == "failed" assert state["last_operation"]["status"] == "failed" assert events == ["start", "camera", "runtime", "seal"] assert camera_arm_calls == [] assert service._acquisition_session_lease is None # noqa: SLF001 def test_start_cleanup_failure_retains_lease_and_marks_side_effect_unknown( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) prepared = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] def fail_receiver_start( _host: str, out_dir: Path, *, duration_seconds: float | None, project_name: str, recover_connection: Callable[[int], str] | None = None, ) -> None: assert duration_seconds is None assert project_name == PROJECT_NAME assert recover_connection is None out_dir.mkdir() raise RuntimeError("synthetic receiver start failure") monkeypatch.setattr(runtime, "start_live", fail_receiver_start) camera_arm_calls: list[Path] = [] monkeypatch.setattr( service, "_arm_camera_recording", lambda out_dir, **_kwargs: camera_arm_calls.append(out_dir), ) monkeypatch.setattr(facade_module, "seal_capture_clock", lambda _capture_root: None) runtime.stop_error = RuntimeError("synthetic cleanup timeout") with pytest.raises(RuntimeError, match="synthetic receiver start failure"): service.start_acquisition(_start_request(acquisition_id=acquisition_id)) state = service.state() operation = next(item for item in state["operations"] if item["action"] == "acquisition.start") assert state["acquisition"]["state"] == "failed" assert operation["status"] == "failed" assert operation["error"]["side_effect_status"] == "unknown" assert service._acquisition_session_lease is not None # noqa: SLF001 assert camera_arm_calls == [] runtime.stop_error = None service.stop() assert service._acquisition_session_lease is None # noqa: SLF001 def test_receiver_completion_without_point_data_fails_start_operation(tmp_path: Path) -> None: service, runtime = service_with_fake_runtime(tmp_path) prepared = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", duration_seconds=60, compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] service.start_acquisition(_start_request(acquisition_id=acquisition_id)) runtime.phase = "idle" runtime.source_mode = "idle" failed = service.state() assert failed["acquisition"]["state"] == "failed" assert failed["last_operation"]["status"] == "failed" assert failed["acquisition"]["result"]["device_state"] == "unknown" def test_capture_only_stop_never_claims_that_physical_k1_stopped(tmp_path: Path) -> None: service, runtime = service_with_fake_runtime(tmp_path) prepared = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", duration_seconds=60, compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] service.start_acquisition(_start_request(acquisition_id=acquisition_id)) stopped = service.stop_acquisition( _stop_request(acquisition_id=acquisition_id, mode="capture-only") ) assert runtime.stop_calls == 1 assert stopped["acquisition"]["state"] == "completed" assert stopped["acquisition"]["result"] == { "receiver_stopped": True, "device_stop": "unknown", } operations = {item["action"]: item for item in stopped["operations"]} assert operations["acquisition.start"]["status"] == "cancelled" assert operations["acquisition.stop"]["status"] == "succeeded" def test_stop_seals_session_clock_after_camera_and_runtime_before_lease_release( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) out_dir = tmp_path / "evidence-session" out_dir.mkdir() service._acquisition_out_dir = out_dir # noqa: SLF001 events: list[object] = [] monkeypatch.setattr( service.camera_preview, "stop_recording", lambda **_kwargs: events.append("camera"), ) monkeypatch.setattr(runtime, "stop", lambda: events.append("runtime")) monkeypatch.setattr( facade_module, "seal_capture_clock", lambda capture_root: events.append(("seal", capture_root)), ) class Lease: def release(self) -> None: events.append("lease") service._acquisition_session_lease = Lease() # type: ignore[assignment] # noqa: SLF001 service._stop_acquisition_sources( # noqa: SLF001 camera_status="complete", camera_failure_code=None, ) assert events == [ "camera", "runtime", ("seal", out_dir / "captures" / "mqtt_live"), "lease", ] def test_stop_timeout_retains_lease_and_blocks_replacement_acquisition( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) prepared = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] service.start_acquisition(_start_request(acquisition_id=acquisition_id)) out_dir = service._acquisition_out_dir # noqa: SLF001 assert out_dir is not None out_dir.mkdir() seal_calls: list[Path] = [] monkeypatch.setattr( facade_module, "seal_capture_clock", lambda capture_root: seal_calls.append(capture_root), ) runtime.stop_error = RuntimeError("synthetic stop timeout") with pytest.raises(RuntimeError, match="synthetic stop timeout"): service.stop_acquisition(_stop_request(acquisition_id=acquisition_id, mode="capture-only")) assert seal_calls == [] assert service._acquisition_session_lease is not None # noqa: SLF001 assert service.state()["acquisition"]["cleanup_pending"] is True with pytest.raises(RuntimeError, match="evidence-сессия"): service.prepare_acquisition( _prepare_request( project_name="replacement", host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) runtime.stop_error = None retried = service.stop() assert retried["acquisition"]["state"] == "failed" assert len(seal_calls) == 1 assert service._acquisition_session_lease is None # noqa: SLF001 assert retried["acquisition"]["cleanup_pending"] is False replacement = service.prepare_acquisition( _prepare_request( project_name="replacement", host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) assert replacement["acquisition"]["state"] == "prepared" def test_replay_rejects_retained_failed_acquisition_lease( tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) prepared = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] service.start_acquisition(_start_request(acquisition_id=acquisition_id)) runtime.stop_error = RuntimeError("synthetic stop timeout") with pytest.raises(RuntimeError, match="synthetic stop timeout"): service.stop_acquisition(_stop_request(acquisition_id=acquisition_id, mode="capture-only")) with pytest.raises(RuntimeError, match="не запечатана"): service.start_replay("sessions/fixture.k1mqtt", speed=1.0, loop=False) runtime.stop_error = None service.stop() def test_new_explicit_stop_retries_retained_terminal_cleanup( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) prepared = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] service.start_acquisition(_start_request(acquisition_id=acquisition_id)) out_dir = service._acquisition_out_dir # noqa: SLF001 assert out_dir is not None out_dir.mkdir() seal_calls: list[Path] = [] monkeypatch.setattr( facade_module, "seal_capture_clock", lambda capture_root: seal_calls.append(capture_root), ) runtime.stop_error = RuntimeError("synthetic stop timeout") with pytest.raises(RuntimeError, match="synthetic stop timeout"): service.stop_acquisition(_stop_request(acquisition_id=acquisition_id, mode="capture-only")) runtime.stop_error = None recovered = service.stop_acquisition( _stop_request( acquisition_id=acquisition_id, mode="capture-only", idempotency_key="retry-retained-cleanup", ) ) retry_operation = recovered["last_operation"] assert retry_operation["status"] == "succeeded" assert retry_operation["stage_code"] == "retained-cleanup-completed" assert retry_operation["result"]["device_stop"] == "unknown" assert len(seal_calls) == 1 assert service._acquisition_session_lease is None # noqa: SLF001 def test_natural_receiver_completion_fails_acquisition_when_session_clock_cannot_seal( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) prepared = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] service.start_acquisition(_start_request(acquisition_id=acquisition_id)) runtime.pcl_frames = 1 service.state() out_dir = service._acquisition_out_dir # noqa: SLF001 assert out_dir is not None out_dir.mkdir() monkeypatch.setattr( facade_module, "seal_capture_clock", lambda _capture_root: (_ for _ in ()).throw(RuntimeError("synthetic seal failure")), ) runtime.phase = "idle" runtime.source_mode = "idle" with pytest.raises(RuntimeError, match="synthetic seal failure"): service.state() assert service._acquisition is not None # noqa: SLF001 assert service._acquisition.state == "failed" # noqa: SLF001 def test_natural_receiver_completion_reserves_finalization_before_reentrant_callback( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) prepared = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] service.start_acquisition(_start_request(acquisition_id=acquisition_id)) runtime.pcl_frames = 1 service.state() out_dir = service._acquisition_out_dir # noqa: SLF001 assert out_dir is not None out_dir.mkdir() events: list[str] = [] def reentrant_camera_stop(**_kwargs: object) -> None: events.append("camera") nested = service.state() assert nested["acquisition"]["state"] == "finalizing" monkeypatch.setattr(service.camera_preview, "stop_recording", reentrant_camera_stop) monkeypatch.setattr( facade_module, "seal_capture_clock", lambda _capture_root: events.append("seal"), ) runtime.phase = "idle" runtime.source_mode = "idle" completed = service.state() assert completed["acquisition"]["state"] == "completed" assert events == ["camera", "seal"] def test_graceful_stop_waits_for_explicit_operator_confirmation(tmp_path: Path) -> None: service, runtime = service_with_fake_runtime(tmp_path) prepared = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", duration_seconds=60, compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] service.start_acquisition(_start_request(acquisition_id=acquisition_id)) runtime.mark_ready() service.state() runtime.pcl_frames = 1 acquiring = service.state() assert acquiring["acquisition"]["state"] == "acquiring" awaiting = service.stop_acquisition( _stop_request(acquisition_id=acquisition_id, mode="graceful") ) operation_id = awaiting["last_operation"]["operation_id"] assert runtime.stop_calls == 0 assert awaiting["acquisition"]["state"] == "awaiting_external_stop" assert awaiting["last_operation"]["status"] == "operator_action_required" retried = service.stop_acquisition( _stop_request( acquisition_id=acquisition_id, operation_id=operation_id, mode="graceful", ) ) assert retried["acquisition"]["state"] == "awaiting_external_stop" assert retried["last_operation"]["operation_id"] == operation_id assert retried["last_operation"]["status"] == "operator_action_required" with pytest.raises(ValueError, match="исходную stop-operation"): service.stop_acquisition( _stop_request( acquisition_id=acquisition_id, mode="graceful", operator_confirmed=True, ) ) completed = service.stop_acquisition( _stop_request( acquisition_id=acquisition_id, operation_id=operation_id, mode="graceful", operator_confirmed=True, ) ) assert runtime.stop_calls == 1 assert completed["acquisition"]["result"]["device_stop"] == "operator-confirmed" stop_operations = [ item for item in completed["operations"] if item["action"] == "acquisition.stop" ] assert len(stop_operations) == 1 assert stop_operations[0]["operation_id"] == operation_id assert stop_operations[0]["status"] == "succeeded" def test_graceful_stop_retry_by_idempotency_key_reuses_original_operation( tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) prepared = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] service.start_acquisition(_start_request(acquisition_id=acquisition_id)) runtime.mark_ready() service.state() runtime.pcl_frames = 1 service.state() first = service.stop_acquisition( _stop_request( acquisition_id=acquisition_id, idempotency_key="graceful-stop-once", mode="graceful", ) ) first_operation_id = first["last_operation"]["operation_id"] retried = service.stop_acquisition( _stop_request( acquisition_id=acquisition_id, idempotency_key="graceful-stop-once", mode="graceful", ) ) assert retried["last_operation"]["operation_id"] == first_operation_id assert retried["last_operation"]["status"] == "operator_action_required" assert ( len([item for item in retried["operations"] if item["action"] == "acquisition.stop"]) == 1 ) def test_unrelated_graceful_stop_is_rejected_while_confirmation_is_pending( tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) prepared = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] service.start_acquisition(_start_request(acquisition_id=acquisition_id)) runtime.mark_ready() service.state() runtime.pcl_frames = 1 service.state() first = service.stop_acquisition(_stop_request(acquisition_id=acquisition_id, mode="graceful")) expected_operation_id = first["last_operation"]["operation_id"] with pytest.raises(ValueError, match="уже ожидает"): service.stop_acquisition( _stop_request( acquisition_id=acquisition_id, idempotency_key="unrelated-stop-request", mode="graceful", ) ) original = next( item for item in service.state()["operations"] if item["operation_id"] == expected_operation_id ) assert original["status"] == "operator_action_required" def test_graceful_stop_is_rejected_until_point_data_confirms_acquisition( tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) prepared = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] service.start_acquisition(_start_request(acquisition_id=acquisition_id)) with pytest.raises(ValueError, match="подтверждённого потока point cloud"): service.stop_acquisition(_stop_request(acquisition_id=acquisition_id, mode="graceful")) state = service.state() assert runtime.stop_calls == 0 assert state["acquisition"]["state"] == "starting" assert state["last_operation"]["action"] == "acquisition.start" assert state["last_operation"]["status"] == "running" @pytest.mark.parametrize("evidence_policy", ["best-effort", "disabled"]) def test_prepare_rejects_unsupported_evidence_policies( tmp_path: Path, evidence_policy: str, ) -> None: service, _ = service_with_fake_runtime(tmp_path) with pytest.raises(ValueError, match="evidence_policy=required"): service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", evidence_policy=evidence_policy, # type: ignore[arg-type] compatibility_attestation=ATTESTATION, ) ) assert service.state()["compatibility"]["profile_id"] is None @pytest.mark.parametrize( "requested_streams", [ DEFAULT_LIVE_STREAMS[:-1], (*DEFAULT_LIVE_STREAMS, DEFAULT_LIVE_STREAMS[0]), ], ) def test_prepare_rejects_stream_subsets_and_duplicates( tmp_path: Path, requested_streams: tuple[str, ...], ) -> None: service, _ = service_with_fake_runtime(tmp_path) with pytest.raises(ValueError, match="полный проверенный набор"): service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", requested_streams=requested_streams, # type: ignore[arg-type] compatibility_attestation=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) initial = service.state() assert initial["compatibility"] == { "profile_id": None, "decision": "unknown", "permitted_mode": "evidence-only", "firmware_claim": "exact-3.0.2-profile-not-selected", "attestation": None, "vendor_writes_enabled": False, "camera_preview": "unverified", } assert initial["device_calibration"]["compatibility_profile_id"] is None attested = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) assert attested["compatibility"]["profile_id"] == XGRIDS_K1_COMPATIBILITY_PROFILE_ID assert attested["compatibility"]["decision"] == "limited" assert attested["compatibility"]["attestation"]["basis"] == ( "selected-profile-live-device-info-required" ) assert attested["device_session"]["compatibility_profile_id"] == ( XGRIDS_K1_COMPATIBILITY_PROFILE_ID ) def test_prepare_rejects_device_ap_without_completed_quick_connect(tmp_path: Path) -> None: service, _ = service_with_fake_runtime(tmp_path) with pytest.raises(ValueError, match="connection flow"): service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.56.1", compatibility_attestation=QUICK_CONNECT_ATTESTATION, ) ) state = service.state() assert state["device_ref"] is None assert state["compatibility"]["profile_id"] is None def test_runtime_error_terminalizes_pending_graceful_stop(tmp_path: Path) -> None: service, runtime = service_with_fake_runtime(tmp_path) prepared = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] service.start_acquisition(_start_request(acquisition_id=acquisition_id)) runtime.mark_ready() service.state() runtime.pcl_frames = 1 service.state() awaiting = service.stop_acquisition( _stop_request(acquisition_id=acquisition_id, mode="graceful") ) stop_operation_id = awaiting["last_operation"]["operation_id"] runtime.phase = "error" failed = service.state() stop_operation = next( item for item in failed["operations"] if item["operation_id"] == stop_operation_id ) assert failed["acquisition"]["state"] == "failed" assert stop_operation["status"] == "failed" assert stop_operation["error"]["side_effect_status"] == "unknown" assert failed["source_mode"] == "idle" assert failed["phase"] != "error" assert runtime.stop_calls == 1 def test_receiver_completion_terminalizes_unconfirmed_graceful_stop( tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) prepared = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] service.start_acquisition(_start_request(acquisition_id=acquisition_id)) runtime.mark_ready() service.state() runtime.pcl_frames = 1 service.state() awaiting = service.stop_acquisition( _stop_request(acquisition_id=acquisition_id, mode="graceful") ) stop_operation_id = awaiting["last_operation"]["operation_id"] runtime.phase = "idle" runtime.source_mode = "idle" runtime.source_ready = False failed = service.state() stop_operation = next( item for item in failed["operations"] if item["operation_id"] == stop_operation_id ) assert failed["acquisition"]["state"] == "failed" assert failed["acquisition"]["result"] == { "receiver_stopped": True, "device_state": "unknown", } assert stop_operation["status"] == "failed" assert stop_operation["error"]["code"] == ("receiver-completed-before-device-stop-confirmation") def test_unconfirmed_stop_operation_terminalizes_before_clock_seal_error( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) prepared = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] service.start_acquisition(_start_request(acquisition_id=acquisition_id)) runtime.pcl_frames = 1 service.state() awaiting = service.stop_acquisition( _stop_request(acquisition_id=acquisition_id, mode="graceful") ) stop_operation_id = awaiting["last_operation"]["operation_id"] out_dir = service._acquisition_out_dir # noqa: SLF001 assert out_dir is not None out_dir.mkdir() monkeypatch.setattr( facade_module, "seal_capture_clock", lambda _capture_root: (_ for _ in ()).throw(RuntimeError("synthetic seal failure")), ) runtime.phase = "idle" runtime.source_mode = "idle" with pytest.raises(RuntimeError, match="synthetic seal failure"): service.state() state = service.state() stop_operation = next( item for item in state["operations"] if item["operation_id"] == stop_operation_id ) assert state["acquisition"]["state"] == "failed" assert stop_operation["status"] == "failed" assert service._acquisition_session_lease is not None # noqa: SLF001 monkeypatch.setattr(facade_module, "seal_capture_clock", lambda _capture_root: None) service.stop() def test_abort_failure_terminalizes_acquisition_and_pending_start(tmp_path: Path) -> None: service, runtime = service_with_fake_runtime(tmp_path) prepared = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] service.start_acquisition(_start_request(acquisition_id=acquisition_id)) runtime.stop_error = RuntimeError("synthetic receiver stop failure") with pytest.raises(RuntimeError, match="synthetic receiver stop failure"): service.abort_acquisition(_abort_request(acquisition_id=acquisition_id)) state = service.state() operations = {item["action"]: item for item in state["operations"]} assert state["acquisition"]["state"] == "failed" assert state["acquisition"]["result"] == { "receiver_stopped": False, "device_state": "unknown", } assert operations["acquisition.start"]["status"] == "cancelled" assert operations["acquisition.abort"]["status"] == "failed" assert state["source_mode"] == "live" def test_abort_reserves_stopping_before_reentrant_runtime_callback( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) prepared = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] service.start_acquisition(_start_request(acquisition_id=acquisition_id)) runtime.pcl_frames = 1 service.state() out_dir = service._acquisition_out_dir # noqa: SLF001 assert out_dir is not None out_dir.mkdir() events: list[str] = [] monkeypatch.setattr( service.camera_preview, "stop_recording", lambda **_kwargs: events.append("camera"), ) def reentrant_runtime_stop() -> None: events.append("runtime") runtime.phase = "idle" runtime.source_mode = "idle" nested = service.state() assert nested["acquisition"]["state"] == "stopping" monkeypatch.setattr(runtime, "stop", reentrant_runtime_stop) monkeypatch.setattr( facade_module, "seal_capture_clock", lambda _capture_root: events.append("seal"), ) aborted = service.abort_acquisition(_abort_request(acquisition_id=acquisition_id)) assert aborted["acquisition"]["state"] == "aborted" assert events == ["camera", "runtime", "seal"] assert service._acquisition_session_lease is None # noqa: SLF001 def test_clean_close_seals_and_cancels_pending_start_operation( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) prepared = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] service.start_acquisition(_start_request(acquisition_id=acquisition_id)) out_dir = service._acquisition_out_dir # noqa: SLF001 assert out_dir is not None out_dir.mkdir() events: list[str] = [] monkeypatch.setattr( service.camera_preview, "close", lambda: events.append("camera"), ) def close_runtime() -> None: events.append("runtime") runtime.phase = "idle" runtime.source_mode = "idle" monkeypatch.setattr(runtime, "close", close_runtime) monkeypatch.setattr( facade_module, "seal_capture_clock", lambda _capture_root: events.append("seal"), ) service.close() state = service.state() start_operation = next( item for item in state["operations"] if item["action"] == "acquisition.start" ) assert state["acquisition"]["state"] == "interrupted" assert start_operation["status"] == "cancelled" assert events == ["camera", "runtime", "seal"] assert service._acquisition_session_lease is None # noqa: SLF001 def test_clean_close_cancels_pending_external_stop_operation( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) prepared = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] service.start_acquisition(_start_request(acquisition_id=acquisition_id)) runtime.pcl_frames = 1 service.state() awaiting = service.stop_acquisition( _stop_request(acquisition_id=acquisition_id, mode="graceful") ) stop_operation_id = awaiting["last_operation"]["operation_id"] monkeypatch.setattr(service.camera_preview, "close", lambda: None) monkeypatch.setattr(runtime, "close", lambda: runtime.stop()) service.close() state = service.state() stop_operation = next( item for item in state["operations"] if item["operation_id"] == stop_operation_id ) assert state["acquisition"]["state"] == "interrupted" assert stop_operation["status"] == "cancelled" assert all( item["status"] not in {"accepted", "running", "operator_action_required"} for item in state["operations"] if item["action"].startswith("acquisition.") ) @pytest.mark.parametrize("cleanup_failure", [False, True], ids=["clean", "cleanup-failed"]) def test_close_settles_exact_prepared_stop_as_not_dispatched_after_worker_retirement( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, cleanup_failure: bool, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture(service, runtime) service.stop_acquisition(fixture.request) monkeypatch.setattr(service.camera_preview, "close", lambda: None) if cleanup_failure: monkeypatch.setattr( runtime, "close", lambda: (_ for _ in ()).throw(RuntimeError("synthetic shutdown cleanup failure")), ) else: monkeypatch.setattr(runtime, "close", runtime.stop) if cleanup_failure: with pytest.raises(RuntimeError, match="synthetic shutdown cleanup failure"): service.close() else: service.close() operation = service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert operation.status == "failed" assert operation.stage_code == "physical-stop-classified-not-dispatched" assert operation.error is not None assert operation.error["side_effect_status"] == "none" assert operation.error["physical_command_sent"] is False assert operation.error["automatic_replay_allowed"] is False record = fixture.ledger.snapshot().record assert record is not None and record.stage == "prepared" def test_close_never_classifies_stop_none_after_dispatch_boundary( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture(service, runtime) service.stop_acquisition(fixture.request) dispatch = ApplicationMqttPublishEvidence( operation_key="modeling:stop", topic=fixture.envelope.topic, payload_sha256=fixture.envelope.payload_sha256, qos=2, retain=False, packet_id=None, ) assert service._k1_command_dispatch_gate.acquire(blocking=False) # noqa: SLF001 try: fixture.coordinator.publish_dispatching(dispatch) finally: service._k1_command_dispatch_gate.release() # noqa: SLF001 monkeypatch.setattr(service.camera_preview, "close", lambda: None) monkeypatch.setattr(runtime, "close", runtime.stop) service.close() record = fixture.ledger.snapshot().record assert record is not None and record.stage == "dispatching" operation = service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert operation.status == "failed" assert operation.stage_code == "physical-stop-outcome-unknown-local-retirement" assert operation.error is not None assert operation.error["side_effect_status"] == "unknown" assert operation.error["automatic_replay_allowed"] is False def test_close_with_live_prepared_worker_and_busy_dispatch_gate_stays_conservative( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_real_prepared_stop_dispatch_fixture(service, runtime) service.stop_acquisition(fixture.request) monkeypatch.setattr(service.camera_preview, "close", lambda: None) monkeypatch.setattr(runtime, "close", runtime.stop) assert service._k1_command_dispatch_gate.acquire(blocking=False) # noqa: SLF001 try: with pytest.raises( facade_module.LocalAcquisitionLifecycleError, match="publish-переходом STOP", ) as raised: service.close() finally: service._k1_command_dispatch_gate.release() # noqa: SLF001 assert raised.value.reason_code == "acquisition-stop-dispatch-retirement-pending" record = fixture.ledger.snapshot().record assert record is not None and record.stage == "prepared" operation = service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert operation.status == "running" assert operation.stage_code == "awaiting-external-stop" assert operation.error is None assert service._acquisition_stop_operation_id == fixture.stop_operation_id # noqa: SLF001 assert service._acquisition is not None # noqa: SLF001 assert service._acquisition.state == "awaiting_external_stop" # noqa: SLF001 assert runtime.stop_calls == 0 def test_close_defers_real_worker_queued_before_dispatch_without_tearing_owner( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) fixture = _install_actual_worker_recovered_stop_fixture( service, runtime, monkeypatch, ) service.stop_acquisition(fixture.request) assert fixture.transport.before_transport_guard.wait(3.0) cleanup_calls: list[str] = [] monkeypatch.setattr( service.camera_preview, "close", lambda: cleanup_calls.append("camera"), ) monkeypatch.setattr(runtime, "close", lambda: cleanup_calls.append("runtime")) with pytest.raises( facade_module.LocalAcquisitionLifecycleError, match="не завершил PREPARED STOP", ) as raised: service.close() assert raised.value.reason_code == "acquisition-stop-worker-retirement-pending" assert cleanup_calls == [] assert fixture.transport.fake_client_publish_calls == [] assert fixture.transport.publish_attempts == 0 operation = service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert operation.status == "running" assert operation.error is None record = fixture.ledger.snapshot().record assert record is not None and record.stage == "prepared" assert service._acquisition_stop_operation_id == fixture.stop_operation_id # noqa: SLF001 assert service._acquisition is not None # noqa: SLF001 assert service._acquisition.state == "failed" # noqa: SLF001 assert service._acquisition.result is not None # noqa: SLF001 assert service._acquisition.result["recovery_only"] is True # noqa: SLF001 assert runtime.stop_calls == 0 # The shutdown attempt explicitly failed, so the still-owned operation may # resume. Its eventual publish is retained as ambiguous evidence, never # retroactively labelled cancelled or not-dispatched. fixture.transport.release_fake_publish.set() fixture.transport.release_transport_guard.set() closed = _wait_control_state(fixture.control, {"closed"}) assert closed["state"] == "closed" assert len(fixture.transport.fake_client_publish_calls) == 1 record = fixture.ledger.snapshot().record assert record is not None and record.stage in {"dispatching", "observing"} operation = service._operations.get(fixture.stop_operation_id) # noqa: SLF001 assert operation.status == "running" assert operation.stage_code != "physical-stop-classified-not-dispatched" def test_close_failure_fails_pending_operation_and_retains_lease( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) prepared = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] service.start_acquisition(_start_request(acquisition_id=acquisition_id)) monkeypatch.setattr(service.camera_preview, "close", lambda: None) monkeypatch.setattr( runtime, "close", lambda: (_ for _ in ()).throw(RuntimeError("synthetic close timeout")), ) with pytest.raises(RuntimeError, match="synthetic close timeout"): service.close() state = service.state() start_operation = next( item for item in state["operations"] if item["action"] == "acquisition.start" ) assert state["acquisition"]["state"] == "failed" assert start_operation["status"] == "failed" assert start_operation["error"]["side_effect_status"] == "unknown" assert service._acquisition_session_lease is not None # noqa: SLF001 runtime.stop_error = None service.stop() assert service._acquisition_session_lease is None # noqa: SLF001 def test_replay_is_rejected_during_nonterminal_acquisition(tmp_path: Path) -> None: service, _ = service_with_fake_runtime(tmp_path) service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) with pytest.raises(RuntimeError, match="активной acquisition-сессии"): service.start_replay("sessions/fixture.k1mqtt", speed=1.0, loop=False) assert service.state()["acquisition"]["state"] == "prepared" def test_prepare_rejects_active_replay_without_stopping_or_replacing_it( tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) runtime.phase = "replay" runtime.source_mode = "replay" runtime.source_ready = True with pytest.raises(RuntimeError, match="активного live/replay"): service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) state = service.state() assert state["acquisition"] is None assert state["source_mode"] == "replay" assert runtime.stop_calls == 0 assert service._acquisition_session_lease is None # noqa: SLF001 def test_network_provisioning_is_single_flight_and_secret_is_unwrapped_only_at_boundary( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) monkeypatch.setattr( facade_module, "_await_control_endpoint_reachable", _reachable_control_endpoint, ) _set_scanned_devices( service, [{"device_id": "k1-a"}, {"device_id": "k1-b"}], ) boundary_calls: list[tuple[str, str, str, str]] = [] async def scenario() -> dict[str, Any]: entered = asyncio.Event() release = asyncio.Event() async def fake_provision( device_id: str, ssid: str, password: str, *, write_mode: str, on_write_dispatch: Callable[[dict[str, Any], str], None] | None = None, **_: object, ) -> dict[str, Any]: boundary_calls.append((device_id, ssid, password, write_mode)) _dispatch_test_network_write(on_write_dispatch) entered.set() await release.wait() return { "started_at_utc": "2026-07-16T12:00:00Z", "completed_at_utc": "2026-07-16T12:00:01Z", "profile_id": "xgrids-k1-fw3-wifi-v1", "outcome": "lan_address_observed", "observations": [{"status": _wifi_status_read("192.168.1.20")["status"]}], } monkeypatch.setattr(facade_module, "provision_wifi_once", fake_provision) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr( facade_module, "_host_route_class", lambda _target: "direct-or-routed", ) monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) monkeypatch.setattr( facade_module, "_control_endpoint_reachable", lambda _target: True, ) first = asyncio.create_task( service.connect( _connect_request( device_id="k1-a", ssid="lab-network", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, ) ) ) await asyncio.wait_for(entered.wait(), timeout=1.0) with pytest.raises(facade_module.ProvisioningAlreadyRunning): await service.connect( _connect_request( device_id="k1-b", ssid="other-network", password=SecretStr(SECONDARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, ) ) release.set() return await asyncio.wait_for(first, timeout=1.0) connected = asyncio.run(scenario()) assert boundary_calls == [("k1-a", "lab-network", PRIMARY_TEST_CREDENTIAL, "with_response")] 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" ] assert len(provision_operations) == 1 assert provision_operations[0]["status"] == "succeeded" attempt = connected["connection_attempt"] assert attempt["attempt_id"] == provision_operations[0]["operation_id"] assert attempt["connection_mode"] == "bridge" assert attempt["side_effect_status"] == "applied" assert attempt["safe_next_action"] == "start-acquisition" assert [event["stage_code"] for event in attempt["timeline"]] == [ "accepted", "scan-selection-admitted", "ble-provisioning-write", "ble-write-dispatched", "status-observing", "device-topology-applied", "host-wifi-switch-not-authorized", "network-configured", "accepted", "host-route-and-control-endpoint", "device-info-confirmed", ] diagnostic_bundle = attempt["diagnostic_bundle"] assert diagnostic_bundle["redacted"] is True assert diagnostic_bundle["automatic_retry"] is False assert PRIMARY_TEST_CREDENTIAL not in json.dumps(diagnostic_bundle) assert "lab-network" not in json.dumps(diagnostic_bundle) switched = service.select_connection_mode( DesiredConnectionModeRequest( connection_mode="quick-connect", expected_revision=connected["desired_connection_mode_revision"], ) ) assert switched["connection_lifecycle"]["ready_to_start"] is False assert switched["connection_attempt"]["status"] == "succeeded" assert switched["connection_attempt"]["safe_next_action"] == "scan-select-connect" assert ( switched["connection_attempt"]["diagnostic_bundle"]["attempt"]["safe_next_action"] == "scan-select-connect" ) cancelled = service.select_connection_mode( DesiredConnectionModeRequest( connection_mode="bridge", expected_revision=switched["desired_connection_mode_revision"], ) ) assert cancelled["connection_lifecycle"]["ready_to_start"] is True assert cancelled["connection_attempt"]["safe_next_action"] == "start-acquisition" assert ( cancelled["connection_attempt"]["diagnostic_bundle"]["attempt"]["safe_next_action"] == "start-acquisition" ) invalidations: list[bool] = [] monkeypatch.setattr( facade_module, "invalidate_connected_device_session", lambda *_args, **_kwargs: invalidations.append(True) or True, ) lost_path = HostPathProbeResult( available=False, fingerprint=None, interface=None, source_ipv4=None, route_class="unavailable", reason_code="router-link-lost", ) disconnected = cancelled for _ in range(3): service._connection_supervisor.observe_host_path(lost_path) # noqa: SLF001 disconnected = service.state() assert invalidations == [True] assert disconnected["connection_lifecycle"]["active_mode"] is None assert disconnected["connection_lifecycle"]["ready_to_start"] is False assert disconnected["connection_attempt"]["status"] == "succeeded" assert disconnected["connection_attempt"]["safe_next_action"] == ("scan-select-connect") assert ( disconnected["connection_attempt"]["diagnostic_bundle"]["attempt"]["safe_next_action"] == "scan-select-connect" ) def test_replay_cannot_start_while_network_transition_owns_lifecycle_gate( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) _set_scanned_k1(service, device_id="k1-a") async def scenario() -> None: entered = asyncio.Event() release = asyncio.Event() async def held_network_write( *_args: object, on_write_dispatch: Callable[[dict[str, Any], str], None] | None = None, **_kwargs: object, ) -> dict[str, Any]: _dispatch_test_network_write(on_write_dispatch) entered.set() await release.wait() return { "started_at_utc": "2026-08-08T12:00:00Z", "completed_at_utc": "2026-08-08T12:00:01Z", "profile_id": "xgrids-k1-fw3-wifi-v1", "outcome": "lan_address_observed", "write_mode": "with_response", "observations": [ {"status": _wifi_status_read("192.168.68.50", device_id="k1-a")["status"]} ], } monkeypatch.setattr(facade_module, "provision_wifi_once", held_network_write) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr(facade_module, "_host_route_class", lambda _target: "direct-or-routed") monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) monkeypatch.setattr(facade_module, "_control_endpoint_reachable", lambda _target: True) monkeypatch.setattr( facade_module, "_await_control_endpoint_reachable", _reachable_control_endpoint, ) network_task = asyncio.create_task( service.connect( _connect_request( device_id="k1-a", ssid="lab-network", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, ) ) ) await asyncio.wait_for(entered.wait(), timeout=1.0) with pytest.raises(facade_module.ApplicationControlProcessLeaseUnavailable): await asyncio.to_thread( service.start_replay, "sessions/fixture.k1mqtt", 1.0, False, ) assert runtime.phase == "idle" assert runtime.source_mode == "idle" release.set() await asyncio.wait_for(network_task, timeout=1.0) asyncio.run(scenario()) def test_network_transition_cannot_enter_while_replay_start_owns_lifecycle_gate( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) _set_scanned_k1(service, device_id="k1-a") replay_path = service.repository_root / "sessions" / "fixture.k1mqtt" replay_path.parent.mkdir(parents=True, exist_ok=True) replay_path.write_bytes(b"fixture") entered = threading.Event() release = threading.Event() def held_replay_start(_path: Path, *, speed: float, loop: bool) -> None: assert speed == 1.0 assert loop is False runtime.phase = "replay" runtime.source_mode = "replay" entered.set() assert release.wait(timeout=1.0) monkeypatch.setattr(runtime, "start_replay", held_replay_start, raising=False) replay_errors: list[BaseException] = [] def replay_worker() -> None: try: service.start_replay(str(replay_path), speed=1.0, loop=False) except BaseException as exc: # pragma: no cover - assertion captures it below replay_errors.append(exc) thread = threading.Thread(target=replay_worker, daemon=True) thread.start() assert entered.wait(timeout=1.0) try: with pytest.raises(facade_module.NetworkProvisioningConflict) as raised: asyncio.run( service.connect( _connect_request( device_id="k1-a", ssid="lab-network", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, ) ) ) assert raised.value.reason_code == "network-provision-lifecycle-busy" finally: release.set() thread.join(timeout=1.0) assert not thread.is_alive() assert replay_errors == [] assert runtime.phase == "replay" assert runtime.source_mode == "replay" def test_exact_network_idempotency_replay_precedes_expired_candidate_checks( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_devices(service, [{"device_id": "k1-a"}]) monkeypatch.setattr( facade_module, "_await_control_endpoint_reachable", _reachable_control_endpoint, ) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr( facade_module, "_host_route_class", lambda _target: "direct-or-routed", ) monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) monkeypatch.setattr( facade_module, "_control_endpoint_reachable", lambda _target: True, ) writes = 0 async def fake_provision( *_: object, on_write_dispatch: Callable[[dict[str, Any], str], None] | None = None, **__: object, ) -> dict[str, Any]: nonlocal writes writes += 1 _dispatch_test_network_write(on_write_dispatch) return { "started_at_utc": "2026-08-06T08:00:00Z", "completed_at_utc": "2026-08-06T08:00:01Z", "profile_id": "xgrids-k1-fw3-wifi-v1", "outcome": "lan_address_observed", "write_mode": "with_response", "observations": [{"status": _wifi_status_read("192.168.1.20")["status"]}], } monkeypatch.setattr(facade_module, "provision_wifi_once", fake_provision) request = _connect_request( device_id="k1-a", ssid="lab-network", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, idempotency_key="one-browser-intent", ) asyncio.run(service.connect(request)) journal_path = service._require_network_provisioning_idempotency_journal().path # noqa: SLF001 journal_document = journal_path.read_text(encoding="utf-8") assert "one-browser-intent" not in journal_document assert "lab-network" not in journal_document assert PRIMARY_TEST_CREDENTIAL not in journal_document service._devices = [] # noqa: SLF001 service._ble_device_last_seen_monotonic = {} # noqa: SLF001 service._ble_device_last_seen_suspend_aware = {} # noqa: SLF001 replayed = asyncio.run(service.connect(request)) restarted_service, _ = service_with_fake_runtime(tmp_path) restarted = asyncio.run(restarted_service.connect(request)) with pytest.raises(NetworkProvisioningIdempotencyConflict): asyncio.run( restarted_service.connect(request.model_copy(update={"ssid": "different-network"})) ) with pytest.raises(NetworkProvisioningIdempotencyConflict): asyncio.run( restarted_service.connect(request.model_copy(update={"allow_host_wifi_switch": True})) ) assert writes == 1 operations = [item for item in replayed["operations"] if item["action"] == "network.provision"] assert len(operations) == 1 assert operations[0]["status"] == "succeeded" restarted_operation = next( item for item in restarted["operations"] if item["action"] == "network.provision" ) assert restarted_operation["operation_id"] == operations[0]["operation_id"] assert restarted_operation["status"] == "succeeded" assert restarted_operation["stage_code"] == "durable-terminal-replay" assert restarted_operation["result"]["phase"] == "network_applied" assert restarted_operation["result"]["control_state"] == "unknown" assert restarted_operation["result"]["replay_binding_available"] is True assert restarted_operation["result"]["snapshot_runtime_id"] == restarted["snapshot_runtime_id"] assert restarted_operation["result"]["parent_intent_id"] == restarted_operation["operation_id"] assert restarted_operation["result"]["transport_ref"] == "k1-a" assert restarted_operation["result"]["connection_mode"] == "bridge" assert restarted_operation["result"]["target_ipv4"] == "192.168.1.20" assert restarted["connection_attempt"]["phase"] == "network_applied" assert restarted["connection_attempt"]["control_state"] == "unknown" monkeypatch.setattr( facade_module, "_probe_control_endpoint_socket", lambda _target: facade_module.TcpReachabilityProbeResult(reachable=True), ) verified = asyncio.run(restarted_service.verify_connection(ConnectionVerifyRequest())) assert writes == 1 assert verified["last_operation"]["action"] == "connection.verify" assert verified["last_operation"]["status"] == "succeeded" assert verified["connection_attempt"]["attempt_id"] == restarted_operation["operation_id"] assert verified["connection_attempt"]["phase"] == "network_applied" assert verified["connection_attempt"]["control_state"] == "ready" assert verified["connection_attempt"]["safe_next_action"] == "start-acquisition" def test_successful_session_requires_new_scan_generation_before_next_connect( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service, device_id="k1-a") targets = iter(["192.168.68.50", "192.168.68.51"]) writes = 0 async def successful_write( *_args: object, on_write_dispatch: Callable[[dict[str, Any], str], None] | None = None, **_kwargs: object, ) -> dict[str, Any]: nonlocal writes writes += 1 target = next(targets) _dispatch_test_network_write(on_write_dispatch) return { "started_at_utc": "2026-08-08T13:00:00Z", "completed_at_utc": "2026-08-08T13:00:01Z", "profile_id": "xgrids-k1-fw3-wifi-v1", "outcome": "lan_address_observed", "write_mode": "with_response", "observations": [{"status": _wifi_status_read(target, device_id="k1-a")["status"]}], } monkeypatch.setattr(facade_module, "provision_wifi_once", successful_write) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr(facade_module, "_host_route_class", lambda _target: "direct-or-routed") monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) monkeypatch.setattr(facade_module, "_control_endpoint_reachable", lambda _target: True) monkeypatch.setattr( facade_module, "_await_control_endpoint_reachable", _reachable_control_endpoint, ) first = asyncio.run( service.connect( _connect_request( device_id="k1-a", ssid="lab-network", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, ) ) ) first_session = first["device_session"]["device_session_id"] with pytest.raises(facade_module.NetworkProvisioningConflict) as raised: asyncio.run( service.connect( _connect_request( device_id="k1-a", ssid="lab-network", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, ) ) ) assert raised.value.reason_code == "network-provision-candidate-not-fresh" assert service._device_session_id == first_session # noqa: SLF001 assert service._selected_device_id == "k1-a" # noqa: SLF001 assert writes == 1 service._ble_discovery_generation += 1 # noqa: SLF001 _set_scanned_k1(service, device_id="k1-a") with pytest.raises(RuntimeError, match="не сообщило адрес"): asyncio.run( service.connect( _connect_request( device_id="k1-a", ssid="lab-network", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, expected_discovery_generation=1, ) ) ) assert service._device_session_id is None # noqa: SLF001 assert service._selected_device_id is None # noqa: SLF001 assert writes == 2 def test_operation_admission_failure_terminalizes_prepared_network_intent( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) def fail_operation_admission(*_args: object, **_kwargs: object) -> object: raise RuntimeError("synthetic operation journal failure") monkeypatch.setattr(service._operations, "begin", fail_operation_admission) # noqa: SLF001 request = _connect_request( device_id="k1-a", ssid="lab-network", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, idempotency_key="operation-admission-failure", ) with pytest.raises(RuntimeError, match="operation journal failure"): asyncio.run(service.connect(request)) snapshot = service._require_network_provisioning_idempotency_journal().snapshot() # noqa: SLF001 assert snapshot.active_record is None assert len(snapshot.records) == 1 record = snapshot.records[0] assert record.stage == "terminal" assert record.terminal is not None assert record.terminal.outcome == "failed" assert record.terminal.outcome_code == "network.provision.admission_failed" assert record.terminal.error_code == "operation-journal-admission-failed" assert record.terminal.side_effect_status == "none" assert record.terminal.safe_to_retry is True def test_live_process_lease_prevents_false_restart_recovery_of_prepared_request( tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) request = _connect_request( device_id="k1-a", ssid="lab-network", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, idempotency_key="live-owner-prepared-request", ) canonical_request = json.dumps( { "schema_version": "missioncore.xgrids-k1-network-provision-request/v1", "device_id": request.device_id, "ssid": request.ssid, "password": PRIMARY_TEST_CREDENTIAL, "connection_mode": request.connection_mode, "expected_mode_revision": request.expected_mode_revision, "expected_discovery_generation": request.expected_discovery_generation, "expected_reconfiguration_revision": (request.expected_reconfiguration_revision), "expected_reconfiguration_intent_id": (request.expected_reconfiguration_intent_id), "compatibility_attestation": request.compatibility_attestation.model_dump(mode="json"), }, ensure_ascii=False, sort_keys=True, separators=(",", ":"), ).encode("utf-8") owner_lease = ApplicationControlProcessLease.acquire(tmp_path) try: journal = service._require_network_provisioning_idempotency_journal() # noqa: SLF001 operation_id = "op-11111111-2222-4333-8444-555555555555" admitted = journal.begin( idempotency_key=request.idempotency_key, action=facade_module.ACTION_NETWORK_PROVISION, operation_id=operation_id, request_binding_sha256=derive_request_binding_sha256( request.idempotency_key, action=facade_module.ACTION_NETWORK_PROVISION, canonical_request=canonical_request, ), ) assert admitted.record.stage == "prepared" competing_service, _ = service_with_fake_runtime(tmp_path) still_live = journal.snapshot().active_record assert still_live is not None assert still_live.operation_id == operation_id assert still_live.stage == "prepared" finally: owner_lease.release() # The already-running competing facade may take over only after the OS # lease proves that the original process is gone. It replays a durable, # no-side-effect terminal result without touching BLE. replayed = asyncio.run(competing_service.connect(request)) terminal = journal.snapshot().records[-1] operation = next( item for item in replayed["operations"] if item["action"] == "network.provision" ) assert terminal.stage == "terminal" assert terminal.terminal is not None assert terminal.terminal.side_effect_status == "none" assert terminal.terminal.safe_to_retry is True assert operation["operation_id"] == operation_id assert operation["status"] == "failed" assert operation["stage_code"] == "durable-terminal-replay" @pytest.mark.parametrize("legacy_stage", ["dispatching", "observing"]) def test_restart_terminalizes_dispatched_legacy_ledger_as_interrupted_audit( tmp_path: Path, legacy_stage: str, ) -> None: service, _ = service_with_fake_runtime(tmp_path) operation_id = f"legacy-{legacy_stage}-operation" _seed_legacy_network_mutation_without_idempotency( service, operation_id=operation_id, stage=legacy_stage, ) journal_path = service._require_network_provisioning_idempotency_journal().path # noqa: SLF001 assert not journal_path.exists() restarted, _ = service_with_fake_runtime(tmp_path) idempotency = restarted._require_network_provisioning_idempotency_journal().snapshot() # noqa: SLF001 assert idempotency.status == "ready" assert idempotency.active_record is None terminal = idempotency.records[-1] assert terminal.operation_id == operation_id assert terminal.action == facade_module.ACTION_NETWORK_PROVISION assert terminal.stage == "terminal" assert terminal.terminal is not None assert terminal.terminal.outcome_code == "network.provision.interrupted" assert terminal.terminal.side_effect_status == "reconciled" assert terminal.terminal.safe_to_retry is False persisted = journal_path.read_text(encoding="utf-8") assert "test-ble-transport" not in persisted assert "WIFI_CLIENT" not in persisted assert '"stage":"terminal"' in persisted state = restarted.state() assert state["network_mutation_ledger"]["stage"] == "resolved" assert state["network_mutation_ledger"]["resolution"] == "interrupted" assert state["network_write_reconciliation"] is None def test_restart_resolves_legacy_prepared_as_not_dispatched_without_adoption( tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _seed_legacy_network_mutation_without_idempotency( service, operation_id="legacy-prepared-operation", stage="prepared", ) journal_path = service._require_network_provisioning_idempotency_journal().path # noqa: SLF001 assert not journal_path.exists() restarted, _ = service_with_fake_runtime(tmp_path) state = restarted.state() assert state["network_mutation_ledger"]["status"] == "resolved" assert state["network_mutation_ledger"]["resolution"] == "not-dispatched" assert state["network_write_reconciliation"] is None assert state["network_provisioning_idempotency"]["status"] == "empty" assert state["network_provisioning_idempotency"]["active_operation_id"] is None assert not journal_path.exists() def test_restart_supersedes_cross_journal_mismatch_without_blocking_new_intent( tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _seed_unresolved_network_mutation( service, operation_id="legacy-ledger-operation", idempotency_operation_id="other-idempotency-operation", ) restarted, _ = service_with_fake_runtime(tmp_path) state = restarted.state() assert state["network_mutation_ledger"]["status"] == "resolved" assert state["network_mutation_ledger"]["operation_id"] == "legacy-ledger-operation" assert state["network_mutation_ledger"]["resolution"] == "interrupted" assert state["network_provisioning_idempotency"]["status"] == "ready" assert state["network_provisioning_idempotency"]["reason_code"] is None assert state["network_provisioning_idempotency"]["mutation_allowed"] is True def test_new_explicit_intent_is_admitted_after_interrupted_dispatched_session( tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _seed_unresolved_network_mutation( service, operation_id="interrupted-operation", idempotency_operation_id="interrupted-operation", ) journal = service._require_network_provisioning_idempotency_journal() # noqa: SLF001 recovered = facade_module._recover_network_provisioning_under_exclusive_process_lease( # noqa: SLF001 network_ledger=service._network_mutation_ledger, # noqa: SLF001 idempotency_journal=journal, ) admitted = journal.begin( idempotency_key="new-explicit-operator-intent", action=facade_module.ACTION_NETWORK_PROVISION, operation_id="new-explicit-operation", request_binding_sha256="a" * 64, ) assert recovered.status == "resolved" assert recovered.record is not None assert recovered.record.resolution == "interrupted" assert admitted.disposition == "admitted" assert admitted.record.stage == "prepared" def test_restart_legacy_adoption_preserves_corrupt_journal_and_fails_closed( tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _seed_legacy_network_mutation_without_idempotency(service) journal_path = service._require_network_provisioning_idempotency_journal().path # noqa: SLF001 corrupt = b'{"schema_version":"corrupt","records":[]}\n' journal_path.write_bytes(corrupt) journal_path.chmod(0o600) restarted, _ = service_with_fake_runtime(tmp_path) state = restarted.state() assert journal_path.read_bytes() == corrupt assert state["network_mutation_ledger"]["status"] == "unresolved" assert state["network_provisioning_idempotency"]["status"] == "corrupt" assert state["network_provisioning_idempotency"]["reason_code"] == ( "network-provisioning-idempotency-corrupt" ) assert state["network_provisioning_idempotency"]["mutation_allowed"] is False @pytest.mark.parametrize( "corruption", [ "wrong-mode", "oversize", "symlink", "ledger-wrong-mode", "both-corrupt", "journal-disappeared", ], ) def test_explicit_connect_quarantines_corrupt_network_audit_without_replay( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, corruption: str, ) -> None: service, _ = service_with_fake_runtime(tmp_path) journal = service._require_network_provisioning_idempotency_journal() # noqa: SLF001 path = journal.path ledger_path = service._network_mutation_ledger.path # noqa: SLF001 path.parent.mkdir(parents=True, exist_ok=True) foreign_target = tmp_path / "foreign-audit-target" if corruption in {"wrong-mode", "both-corrupt", "journal-disappeared"}: path.write_text('{"schema_version":"wrong"}\n', encoding="utf-8") path.chmod(0o644) elif corruption == "oversize": path.write_bytes(b"x" * (300 * 1024)) path.chmod(0o600) else: if corruption == "symlink": foreign_target.write_text("foreign", encoding="utf-8") path.unlink(missing_ok=True) path.symlink_to(foreign_target) if corruption in {"ledger-wrong-mode", "both-corrupt"}: ledger_path.write_text('{"schema_version":"wrong"}\n', encoding="utf-8") ledger_path.chmod(0o644) if corruption == "journal-disappeared": service._network_provisioning_idempotency_journal = None # noqa: SLF001 service._network_provisioning_idempotency_reason = ( # noqa: SLF001 "network-provisioning-idempotency-corrupt" ) path.unlink() _set_scanned_k1(service, device_id="k1-a") async def successful_write( *_args: object, on_write_dispatch: Callable[[dict[str, Any], str], None] | None = None, **_kwargs: object, ) -> dict[str, Any]: _dispatch_test_network_write(on_write_dispatch) return { "started_at_utc": "2026-08-08T10:00:00Z", "completed_at_utc": "2026-08-08T10:00:01Z", "profile_id": "xgrids-k1-fw3-wifi-v1", "outcome": "lan_address_observed", "write_mode": "with_response", "baseline_status": _wifi_status_read(None, device_id="k1-a")["status"], "observations": [ {"status": _wifi_status_read("192.168.68.50", device_id="k1-a")["status"]} ], } monkeypatch.setattr(facade_module, "provision_wifi_once", successful_write) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr(facade_module, "_host_route_class", lambda _target: "direct-or-routed") monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) monkeypatch.setattr(facade_module, "_control_endpoint_reachable", lambda _target: True) monkeypatch.setattr( facade_module, "_await_control_endpoint_reachable", _reachable_control_endpoint, ) state = asyncio.run( service.connect( _connect_request( device_id="k1-a", ssid="lab-network", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, ) ) ) assert state["connection_mode"] == "bridge" assert state["network_provisioning_idempotency"]["status"] == "ready" journal_quarantines = list(path.parent.glob(f"{path.name}.corrupt-*")) ledger_quarantines = list(ledger_path.parent.glob(f"{ledger_path.name}.corrupt-*")) assert len(journal_quarantines) == ( 1 if corruption in { "wrong-mode", "oversize", "symlink", "both-corrupt", } else 0 ) assert len(ledger_quarantines) == ( 1 if corruption in { "ledger-wrong-mode", "both-corrupt", } else 0 ) if corruption == "symlink": assert foreign_target.read_text(encoding="utf-8") == "foreign" def test_cancelled_bridge_write_is_audited_and_new_explicit_intent_writes_once( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_devices(service, [{"device_id": "k1-a"}]) calls = 0 async def scenario() -> None: entered = asyncio.Event() async def cancelled_write( *_: object, on_write_dispatch: Callable[[dict[str, Any], str], None] | None = None, **__: object, ) -> dict[str, Any]: nonlocal calls calls += 1 assert on_write_dispatch is not None on_write_dispatch( _wifi_status_read(None, device_id="k1-a")["status"], "with_response", ) entered.set() try: await asyncio.Event().wait() except asyncio.CancelledError as exc: exc.operation_stage = "gatt-write" # type: ignore[attr-defined] exc.device_write_attempted = True # type: ignore[attr-defined] exc.device_write_confirmed = True # type: ignore[attr-defined] raise async def successful_second_write( *_: object, on_write_dispatch: Callable[[dict[str, Any], str], None] | None = None, **__: object, ) -> dict[str, Any]: nonlocal calls calls += 1 _dispatch_test_network_write(on_write_dispatch) return { "started_at_utc": "2026-08-08T10:00:00Z", "completed_at_utc": "2026-08-08T10:00:01Z", "profile_id": "xgrids-k1-fw3-wifi-v1", "outcome": "lan_address_observed", "write_mode": "with_response", "baseline_status": _wifi_status_read(None, device_id="k1-a")["status"], "observations": [ {"status": _wifi_status_read("192.168.68.50", device_id="k1-a")["status"]} ], } monkeypatch.setattr(facade_module, "provision_wifi_once", cancelled_write) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr(facade_module, "_host_route_class", lambda _target: "direct-or-routed") monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) monkeypatch.setattr(facade_module, "_control_endpoint_reachable", lambda _target: True) monkeypatch.setattr( facade_module, "_await_control_endpoint_reachable", _reachable_control_endpoint, ) first = asyncio.create_task( service.connect( _connect_request( device_id="k1-a", ssid="lab-network", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, idempotency_key="cancelled-write-1", ) ) ) await entered.wait() first.cancel() with pytest.raises(asyncio.CancelledError): await first monkeypatch.setattr(facade_module, "provision_wifi_once", successful_second_write) second = await service.connect( _connect_request( device_id="k1-a", ssid="lab-network", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, idempotency_key="cancelled-write-2", ) ) assert second["connection_mode"] == "bridge" assert second["k1_ip"] == "192.168.68.50" asyncio.run(scenario()) state = service.state() operation = next( item for item in state["operations"] if item["idempotency_key"] == "cancelled-write-1" ) assert operation["status"] == "failed" assert operation["error"]["code"] == "CancelledError" assert operation["error"]["side_effect_status"] == "unknown" assert operation["error"]["safe_to_retry"] is False assert state["network_mutation_ledger"]["status"] == "resolved" assert state["network_write_reconciliation"] is None assert calls == 2 def test_cancelled_host_mutation_finishes_before_ownership_is_released() -> None: started = threading.Event() release = threading.Event() completed = threading.Event() def bounded_host_mutation() -> str: started.set() assert release.wait(timeout=2.0) completed.set() return "completed" async def scenario() -> None: task = asyncio.create_task( facade_module._run_blocking_operation_without_abandonment( # noqa: SLF001 bounded_host_mutation ) ) for _ in range(100): if started.is_set(): break await asyncio.sleep(0.01) assert started.is_set() task.cancel() await asyncio.sleep(0.01) assert not task.done() task.cancel() await asyncio.sleep(0.01) assert not task.done() release.set() with pytest.raises(asyncio.CancelledError): await task assert completed.is_set() asyncio.run(scenario()) def test_bridge_network_change_retires_terminal_acquisition_and_receiver_error( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) monkeypatch.setattr( facade_module, "_await_control_endpoint_reachable", _reachable_control_endpoint, ) _set_scanned_devices(service, [{"device_id": "k1-a", "name": "XGR-TEST-A"}]) prepared = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) service.abort_acquisition( _abort_request( acquisition_id=prepared["acquisition"]["acquisition_id"], ) ) runtime.phase = "error" runtime.source_mode = "live" stop_calls_before_connect = runtime.stop_calls async def fake_provision( *_: object, on_write_dispatch: Callable[[dict[str, Any], str], None] | None = None, **__: object, ) -> dict[str, Any]: _dispatch_test_network_write(on_write_dispatch) return { "started_at_utc": "2026-07-28T18:11:37Z", "completed_at_utc": "2026-07-28T18:11:44Z", "profile_id": "xgrids-k1-fw3-wifi-v1", "outcome": "lan_address_observed", "observations": [{"status": _wifi_status_read("192.168.1.20")["status"]}], } monkeypatch.setattr(facade_module, "provision_wifi_once", fake_provision) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr( facade_module, "_host_route_class", lambda _target: "direct-or-routed", ) monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) monkeypatch.setattr( facade_module, "_control_endpoint_reachable", lambda _target: True, ) connected = asyncio.run( service.connect( _connect_request( device_id="k1-a", ssid="lab-network", password=SecretStr(PRIMARY_TEST_CREDENTIAL), connection_mode="bridge", compatibility_attestation=ATTESTATION, ) ) ) assert connected["connection_mode"] == "bridge" assert connected["k1_ip"] == "192.168.1.20" assert connected["acquisition"] is None assert connected["source_mode"] == "idle" assert connected["phase"] == "connected" assert connected["device_session"]["connectivity"] == "connected" assert connected["connection_verification"]["lease_state"] == "reachable" assert connected["connection_lifecycle"]["connection_ready"] is True assert runtime.stop_calls == stop_calls_before_connect + 1 def test_bridge_provisioning_reports_host_route_mismatch_without_hiding_device_success( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_devices(service, [{"device_id": "k1-a", "name": "XGR-TEST-A"}]) host_associations: list[tuple[str, str]] = [] async def fake_provision( *_: object, on_write_dispatch: Callable[[dict[str, Any], str], None] | None = None, **__: object, ) -> dict[str, Any]: _dispatch_test_network_write(on_write_dispatch) return { "started_at_utc": "2026-07-28T19:43:03Z", "completed_at_utc": "2026-07-28T19:43:16Z", "profile_id": "xgrids-k1-fw3-wifi-v1", "outcome": "lan_address_observed", "observations": [{"status": _wifi_status_read("192.168.68.50")["status"]}], } monkeypatch.setattr(facade_module, "provision_wifi_once", fake_provision) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr(facade_module, "_host_route_class", lambda _target: "tunnel") monkeypatch.setattr(facade_module, "_inspect_host_path", _tunnel_host_path) monkeypatch.setattr( facade_module, "_await_control_endpoint_reachable", _unreachable_control_endpoint, ) monkeypatch.setattr(facade_module, "_control_endpoint_reachable", lambda _target: False) monkeypatch.setattr( facade_module, "associate_with_ephemeral_wifi_credentials_once", lambda _helper, ssid, password, **_kwargs: ( host_associations.append((ssid, password)) or { "adapter": "CoreWLAN", "outcome": "associated", "already_associated": False, "scan_attempt_count": 1, "scan_elapsed_ms": 20, } ), ) async def connect_and_join_read_only_continuation() -> dict[str, Any]: await service.connect( _connect_request( device_id="k1-a", ssid="lab-router", password=SecretStr(PRIMARY_TEST_CREDENTIAL), connection_mode="bridge", compatibility_attestation=ATTESTATION, allow_host_wifi_switch=True, ) ) with service._lock: # noqa: SLF001 task = service._control_bootstrap_continuation_task # noqa: SLF001 if task is not None: with pytest.raises(facade_module.ConnectionVerificationError): await task return service.state() connected = asyncio.run(connect_and_join_read_only_continuation()) assert host_associations == [("lab-router", PRIMARY_TEST_CREDENTIAL)] assert connected["k1_ip"] == "192.168.68.50" assert connected["phase"] == "device_selected" assert connected["device_session"]["connectivity"] == "offline" assert connected["connection_verification"] == { "status": "endpoint-unreachable", "lease_state": "configured-unverified", "lease_generation": connected["connection_supervisor"]["lease"]["generation"], "endpoint_validation": "host-route", "network_reachability": "unreachable", "reason_code": "tcp-endpoint-unreachable", "host_route_class": "tunnel", "write_performed": True, "observed_at": connected["connection_verification"]["observed_at"], "supervisor_revision": connected["connection_verification"]["supervisor_revision"], } operation = next( item for item in connected["operations"] if item["action"] == "network.provision" ) assert operation["status"] == "succeeded" assert operation["result"]["phase"] == "network_applied" assert operation["result"]["host_wifi_switch_authorized"] is True assert operation["result"]["host_route_ready"] is None assert operation["result"]["host_route_class"] is None assert connected["connection_attempt"]["phase"] == "network_applied" assert connected["connection_attempt"]["control_state"] == "control_not_ready" def test_bridge_provisioning_separates_address_from_reachable_control_endpoint( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_devices(service, [{"device_id": "k1-a", "name": "XGR-TEST-A"}]) async def fake_provision( *_: object, on_write_dispatch: Callable[[dict[str, Any], str], None] | None = None, **__: object, ) -> dict[str, Any]: _dispatch_test_network_write(on_write_dispatch) return { "started_at_utc": "2026-08-06T10:00:00Z", "completed_at_utc": "2026-08-06T10:00:01Z", "profile_id": "xgrids-k1-fw3-wifi-v1", "outcome": "lan_address_observed", "write_mode": "with_response", "observations": [{"status": _wifi_status_read("192.168.68.50")["status"]}], } monkeypatch.setattr(facade_module, "provision_wifi_once", fake_provision) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr(facade_module, "_host_route_class", lambda _target: "direct-or-routed") monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) monkeypatch.setattr( facade_module, "_await_control_endpoint_reachable", _unreachable_control_endpoint, ) monkeypatch.setattr( facade_module, "_control_endpoint_reachable", lambda _target: False, ) async def connect_and_join_read_only_continuation() -> dict[str, Any]: await service.connect( _connect_request( device_id="k1-a", ssid="lab-router", password=SecretStr(PRIMARY_TEST_CREDENTIAL), connection_mode="bridge", compatibility_attestation=ATTESTATION, ) ) with service._lock: # noqa: SLF001 task = service._control_bootstrap_continuation_task # noqa: SLF001 if task is not None: with pytest.raises(facade_module.ConnectionVerificationError): await task return service.state() state = asyncio.run(connect_and_join_read_only_continuation()) assert state["k1_ip"] == "192.168.68.50" assert state["phase"] == "device_selected" assert state["device_session"]["connectivity"] == "offline" assert state["connection_verification"] == { "status": "endpoint-unreachable", "lease_state": "configured-unverified", "lease_generation": state["connection_supervisor"]["lease"]["generation"], "endpoint_validation": "provisioning-status+mqtt-tcp-connect", "network_reachability": "unreachable", "reason_code": "tcp-endpoint-unreachable", "host_route_class": "direct-or-routed", "write_performed": True, "observed_at": state["connection_verification"]["observed_at"], "supervisor_revision": state["connection_verification"]["supervisor_revision"], } operation = next(item for item in state["operations"] if item["action"] == "network.provision") assert operation["status"] == "succeeded" assert operation["stage_code"] == "network-configured" assert operation["result"]["phase"] == "network_applied" assert operation["result"]["control_state"] == "unknown" assert operation["result"]["control_endpoint_reachable"] is None assert state["connection_attempt"]["phase"] == "network_applied" assert state["connection_attempt"]["control_state"] == "control_not_ready" def test_quick_connect_activates_the_device_ap_then_associates_the_host( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) mode_revision = _select_connection_mode(service, "quick-connect") monkeypatch.setattr( facade_module, "_await_control_endpoint_reachable", _reachable_control_endpoint, ) monkeypatch.setattr( facade_module, "_control_endpoint_reachable", lambda _target: True, ) _set_scanned_devices(service, [{"device_id": "k1-a", "name": "XGR-TEST-A"}]) activation_calls: list[tuple[str, str]] = [] association_calls: list[tuple[Path, str, str]] = [] ble_session_open = False monkeypatch.setattr( facade_module, "ensure_wifi_profile_from_credential_source", lambda *_args, **_kwargs: { "schema_version": 1, "adapter": "macOS Keychain", "available": True, "profile_enrolled": True, "credential_source": "exact-firmware-profile", }, ) @asynccontextmanager async def fake_activation_session( device_id: str, *, write_mode: str, on_write_dispatch: Callable[[dict[str, Any], str], None] | None = None, **_: object, ) -> AsyncIterator[dict[str, Any]]: nonlocal ble_session_open activation_calls.append((device_id, write_mode)) _dispatch_test_network_write(on_write_dispatch) ble_session_open = True try: yield { "profile_id": "xgrids-k1-fw3-quick-connect-ap-v1", "started_at_utc": "2026-07-19T15:00:00Z", "completed_at_utc": "2026-07-19T15:00:01Z", "outcome": "ap_ready_observed", "ready_observed": True, "write_performed": True, "write_mode": "with_response", "observations": [{"status": _ap_ready_wifi_status()}], } finally: ble_session_open = False def fake_associate( helper_path: Path, profile_id: str, expected_ssid: str, **_: object, ) -> dict[str, Any]: assert ble_session_open association_calls.append((helper_path, profile_id, expected_ssid)) return { "schema_version": 1, "adapter": "CoreWLAN", "outcome": "associated", "already_associated": False, "profile_enrolled": True, "scan_attempt_count": 2, "scan_elapsed_ms": 900, "credential_source": "exact-firmware-profile", } async def forbidden_provisioning_write(*_: object, **__: object) -> dict[str, Any]: raise AssertionError("Quick Connect must not send router credentials to the K1") monkeypatch.setattr( facade_module, "device_ap_activation_session", fake_activation_session, ) monkeypatch.setattr(facade_module, "associate_with_wifi_profile_once", fake_associate) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_provisioning_write) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) state = asyncio.run( service.connect( _connect_request( device_id="k1-a", connection_mode="quick-connect", compatibility_attestation=QUICK_CONNECT_ATTESTATION, expected_mode_revision=mode_revision, ) ) ) assert activation_calls == [("k1-a", "with_response")] assert not ble_session_open assert len(association_calls) == 1 assert association_calls[0][0].name == "associate_wifi.swift" assert association_calls[0][1] == facade_module.quick_connect_host_profile_id("XGR-TEST-A") assert association_calls[0][2] == "XGR-TEST-A" assert state["connection_mode"] == "quick-connect" assert state["k1_ip"] == "192.168.56.1" assert state["compatibility"]["attestation"]["topology"] == "device-ap" quick_sessions = sorted(service.evidence_root.glob("*viewer_k1_ap_association*")) assert len(quick_sessions) == 1 assert not (quick_sessions[0] / "provisioning.sensitive.json").exists() redacted_manifest = (quick_sessions[0] / "manifest.redacted.json").read_text(encoding="utf-8") assert PRIMARY_TEST_CREDENTIAL not in redacted_manifest assert "host_wifi_profile_id" in redacted_manifest assert '"host_wifi_profile_ready_before_device_write": true' in redacted_manifest assert '"credentials_resolved_by_plugin": true' in redacted_manifest assert "credential_provider_id" in redacted_manifest assert "device_ap_activation_profile_id" in redacted_manifest assert (quick_sessions[0] / "ap-activation.redacted.json").exists() assert ( service._camera_target_for_session( # noqa: SLF001 state["device_session"]["device_session_id"] ) == "192.168.56.1" ) assert state["connection_lifecycle"]["connection_ready"] is True control = state["application_control_session"] workspace = service.enter_application_workspace( EnterApplicationWorkspaceRequest( operator_confirmed=True, expected_session_generation=control["session_generation"], expected_state_revision=control["state_revision"], ) ) workspace_control = workspace["application_control_session"] prepared = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, compatibility_attestation=QUICK_CONNECT_ATTESTATION, expected_control_session_generation=workspace_control["session_generation"], expected_control_state_revision=workspace_control["state_revision"], ) ) assert prepared["acquisition"]["target_host"] == "192.168.56.1" def test_quick_connect_read_only_verify_requires_fresh_ble_status_without_write( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _select_connection_mode(service, "quick-connect") _seed_supervised_connection( service, target_ipv4="192.168.56.1", connection_mode="quick-connect", transport_ref="k1-a", logical_device_id="device-k1-a", with_control=False, ) service._device_session_id = "session-k1-a" # noqa: SLF001 _set_scanned_k1(service, device_id="k1-a") supervisor_generation = service._connection_supervisor.snapshot().lease.generation # noqa: SLF001 service._connection_lease_generation = supervisor_generation # noqa: SLF001 service._connection_verification = { # noqa: SLF001 "status": "endpoint-unreachable", "lease_state": "disconnected", "lease_generation": supervisor_generation, "endpoint_validation": "provisioning-status+mqtt-tcp-connect", "network_reachability": "unreachable", "reason_code": "connection_lease_endpoint_unreachable_after_provision", "write_performed": True, "observed_at": "2026-08-06T10:00:00Z", } monkeypatch.setattr( facade_module, "_control_endpoint_reachable", lambda _target: True, ) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr(facade_module, "_host_route_class", lambda _target: "device-ap") monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) status_reads: list[tuple[str, float, bool]] = [] async def exact_ble_status( device_id: str, *, timeout_seconds: float, rediscover: bool, **_: object, ) -> dict[str, Any]: status_reads.append((device_id, timeout_seconds, rediscover)) status = _wifi_status_read("192.168.56.1", device_id=device_id) status["status"] = _ap_ready_wifi_status() return status monkeypatch.setattr(facade_module, "read_wifi_status_once", exact_ble_status) state = asyncio.run( service.verify_connection( ConnectionVerifyRequest( device_id="k1-a", compatibility_attestation=QUICK_CONNECT_ATTESTATION, expected_discovery_generation=0, ) ) ) assert status_reads == [("k1-a", 20.0, False)] assert state["connection_verification"]["lease_state"] == "reachable" assert state["connection_verification"]["network_reachability"] == "reachable" assert state["device_session"]["connectivity"] == "connected" assert state["connection_verification"]["write_performed"] is False assert state["connection_verification"]["endpoint_validation"] == ( "ble-wifi-status-read+mqtt-tcp-connect" ) assert state["last_operation"]["action"] == "connection.verify" assert state["last_operation"]["status"] == "succeeded" def test_direct_connect_reuses_the_reviewed_ble_provisioning_frame( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) mode_revision = _select_connection_mode(service, "direct-connect") monkeypatch.setattr( facade_module, "_await_control_endpoint_reachable", _reachable_control_endpoint, ) _set_scanned_devices(service, [{"device_id": "k1-a", "name": "XGR-TEST-A"}]) provisioning_calls: list[tuple[str, str, str]] = [] async def fake_provision( device_id: str, ssid: str, password: str, *, on_write_dispatch: Callable[[dict[str, Any], str], None] | None = None, **_: object, ) -> dict[str, Any]: provisioning_calls.append((device_id, ssid, password)) _dispatch_test_network_write(on_write_dispatch) return { "started_at_utc": "2026-07-19T01:00:00Z", "completed_at_utc": "2026-07-19T01:00:01Z", "profile_id": "xgrids-k1-fw3-wifi-v1", "outcome": "lan_address_observed", "observations": [{"status": _wifi_status_read("172.20.10.2")["status"]}], } def forbidden_host_association(*_: object, **__: object) -> dict[str, Any]: raise AssertionError("Direct Connect must not switch the host Wi-Fi network") monkeypatch.setattr(facade_module, "provision_wifi_once", fake_provision) monkeypatch.setattr( facade_module, "associate_with_wifi_profile_once", forbidden_host_association, ) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr( facade_module, "_host_route_class", lambda _target: "direct-or-routed", ) monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) monkeypatch.setattr( facade_module, "_control_endpoint_reachable", lambda _target: True, ) state = asyncio.run( service.connect( _connect_request( device_id="k1-a", ssid="controller-hotspot", password=SecretStr(PRIMARY_TEST_CREDENTIAL), connection_mode="direct-connect", compatibility_attestation=DIRECT_CONNECT_ATTESTATION, expected_mode_revision=mode_revision, ) ) ) assert provisioning_calls == [("k1-a", "controller-hotspot", PRIMARY_TEST_CREDENTIAL)] assert state["connection_mode"] == "direct-connect" assert state["k1_ip"] == "172.20.10.2" assert state["compatibility"]["attestation"]["topology"] == ("controller-hotspot") def test_quick_connect_missing_credential_provider_stops_before_ap_write( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) mode_revision = _select_connection_mode(service, "quick-connect") _set_scanned_devices(service, [{"device_id": "k1-a", "name": "XGR-TEST-A"}]) service._selected_device_id = "previous-k1" # noqa: SLF001 service._k1_ip = "192.168.1.20" # noqa: SLF001 service._connection_mode = "bridge" # noqa: SLF001 monkeypatch.setattr( facade_module, "ensure_wifi_profile_from_credential_source", lambda *_args, **_kwargs: { "schema_version": 1, "adapter": "macOS Keychain", "available": False, "profile_enrolled": False, "credential_source": None, }, ) @asynccontextmanager async def forbidden_activation( *_args: object, **_kwargs: object ) -> AsyncIterator[dict[str, Any]]: raise AssertionError("missing host credential must stop before the K1 AP write") yield {} monkeypatch.setattr( facade_module, "device_ap_activation_session", forbidden_activation, ) with pytest.raises(RuntimeError, match="credential-source-unavailable"): asyncio.run( service.connect( _connect_request( device_id="k1-a", connection_mode="quick-connect", compatibility_attestation=QUICK_CONNECT_ATTESTATION, expected_mode_revision=mode_revision, ) ) ) state = service.state() assert state["selected_device_id"] is None assert state["device_session"] is None assert state["k1_ip"] is None assert state["connection_mode"] is None failed_sessions = list(service.evidence_root.glob("*viewer_k1_ap_association*")) assert len(failed_sessions) == 1 assert (failed_sessions[0] / "operation-reservation.redacted.json").exists() assert not (failed_sessions[0] / "ap-activation.redacted.json").exists() operation = next(item for item in state["operations"] if item["action"] == "network.provision") assert operation["status"] == "failed" assert operation["error"]["side_effect_status"] == "none" assert operation["error"]["safe_to_retry"] is True def test_quick_connect_does_not_start_host_wifi_without_ap_ready_flag( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) mode_revision = _select_connection_mode(service, "quick-connect") _set_scanned_devices(service, [{"device_id": "k1-a", "name": "XGR-TEST-A"}]) monkeypatch.setattr( facade_module, "ensure_wifi_profile_from_credential_source", lambda *_args, **_kwargs: { "schema_version": 1, "adapter": "macOS Keychain", "available": True, "profile_enrolled": False, "credential_source": "exact-firmware-profile", }, ) @asynccontextmanager async def not_ready_session( *_: object, on_write_dispatch: Callable[[dict[str, Any], str], None] | None = None, **__: object, ) -> AsyncIterator[dict[str, Any]]: assert on_write_dispatch is not None on_write_dispatch( _wifi_status_read(None, device_id="k1-a")["status"], "with_response", ) yield { "profile_id": "xgrids-k1-fw3-quick-connect-ap-v1", "started_at_utc": "2026-07-19T15:00:00Z", "completed_at_utc": "2026-07-19T15:00:15Z", "outcome": "no_status_change_before_timeout", "ready_observed": False, "write_performed": True, "write_mode": "with_response", "observations": [], } def forbidden_association(*_: object, **__: object) -> dict[str, Any]: raise AssertionError("host Wi-Fi must wait for the canonical AP-ready flag") monkeypatch.setattr( facade_module, "device_ap_activation_session", not_ready_session, ) monkeypatch.setattr( facade_module, "associate_with_wifi_profile_once", forbidden_association, ) with pytest.raises(RuntimeError, match="не подтвердил готовность"): asyncio.run( service.connect( _connect_request( device_id="k1-a", connection_mode="quick-connect", compatibility_attestation=QUICK_CONNECT_ATTESTATION, expected_mode_revision=mode_revision, ) ) ) quick_sessions = sorted(service.evidence_root.glob("*viewer_k1_ap_association*")) assert len(quick_sessions) == 1 assert (quick_sessions[0] / "ap-activation.redacted.json").exists() assert not (quick_sessions[0] / "manifest.redacted.json").exists() reconciliation = service.state()["network_write_reconciliation"] assert reconciliation["transport_ref"] == "k1-a" assert reconciliation["status"] == "previous-session-result-unknown" assert reconciliation["reason_code"] == "network-mutation-audit-open" assert reconciliation["blocks_new_explicit_intent"] is False assert reconciliation["operation_stage"] == "observing" assert reconciliation["scope"] == "durable-ledger" assert reconciliation["ledger_revision"] == 3 def test_quick_connect_unchanged_ready_baseline_does_not_associate_host_wifi( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) mode_revision = _select_connection_mode(service, "quick-connect") _set_scanned_devices(service, [{"device_id": "k1-a", "name": "XGR-TEST-A"}]) monkeypatch.setattr( facade_module, "ensure_wifi_profile_from_credential_source", lambda *_args, **_kwargs: { "schema_version": 1, "adapter": "macOS Keychain", "available": True, "profile_enrolled": True, "credential_source": "exact-firmware-profile", }, ) ready_status = _ap_ready_wifi_status() @asynccontextmanager async def unchanged_ready_session( *_: object, on_write_dispatch: Callable[[dict[str, Any], str], None] | None = None, **__: object, ) -> AsyncIterator[dict[str, Any]]: assert on_write_dispatch is not None on_write_dispatch(ready_status, "with_response") yield { "profile_id": "xgrids-k1-fw3-quick-connect-ap-v1", "started_at_utc": "2026-08-06T10:00:00Z", "completed_at_utc": "2026-08-06T10:00:01Z", "outcome": "ap_ready_observed", "baseline_status": ready_status, "ready_observed": True, "write_performed": True, "write_mode": "with_response", "observations": [{"status": ready_status}], } def forbidden_association(*_: object, **__: object) -> dict[str, Any]: raise AssertionError("baseline/previous AP-ready is not authority to mutate host Wi-Fi") monkeypatch.setattr( facade_module, "device_ap_activation_session", unchanged_ready_session, ) monkeypatch.setattr( facade_module, "associate_with_wifi_profile_once", forbidden_association, ) with pytest.raises(facade_module.NetworkProvisioningConflict) as raised: asyncio.run( service.connect( _connect_request( device_id="k1-a", connection_mode="quick-connect", compatibility_attestation=QUICK_CONNECT_ATTESTATION, expected_mode_revision=mode_revision, ) ) ) assert raised.value.reason_code == ( "network-provision-target-not-distinguishable-from-baseline" ) state = service.state() assert state["network_mutation_ledger"]["status"] == "unresolved" assert state["network_mutation_ledger"]["stage"] == "observing" assert state["semantic_topology_store"]["status"] == "empty" assert state["selected_device_id"] is None operation = next(item for item in state["operations"] if item["action"] == "network.provision") assert operation["error"]["code"] == ( "network-provision-target-not-distinguishable-from-baseline" ) assert operation["error"]["side_effect_status"] == "unknown" assert operation["error"]["safe_to_retry"] is False def test_failed_connection_change_revokes_the_previous_route( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) mode_revision = _select_connection_mode(service, "quick-connect") _set_scanned_devices(service, [{"device_id": "k1-a", "name": "XGR-TEST-A"}]) service._selected_device_id = "previous-k1" # noqa: SLF001 service._k1_ip = "192.168.1.20" # noqa: SLF001 service._connection_mode = "bridge" # noqa: SLF001 monkeypatch.setattr( facade_module, "ensure_wifi_profile_from_credential_source", lambda *_args, **_kwargs: { "schema_version": 1, "adapter": "macOS Keychain", "available": True, "profile_enrolled": False, "credential_source": "exact-firmware-profile", }, ) @asynccontextmanager async def fake_activation_session( *_: object, on_write_dispatch: Callable[[dict[str, Any], str], None] | None = None, **__: object, ) -> AsyncIterator[dict[str, Any]]: assert on_write_dispatch is not None on_write_dispatch( _wifi_status_read(None, device_id="k1-a")["status"], "with_response", ) yield { "profile_id": "xgrids-k1-fw3-quick-connect-ap-v1", "started_at_utc": "2026-07-19T15:00:00Z", "completed_at_utc": "2026-07-19T15:00:01Z", "outcome": "ap_ready_observed", "ready_observed": True, "write_performed": True, "write_mode": "with_response", "observations": [{"status": _ap_ready_wifi_status()}], } def failed_association(*_: object, **__: object) -> dict[str, Any]: raise facade_module.HostWifiProfileError( "network-not-found", scan_attempt_count=4, scan_elapsed_ms=15014, ) monkeypatch.setattr( facade_module, "device_ap_activation_session", fake_activation_session, ) monkeypatch.setattr(facade_module, "associate_with_wifi_profile_once", failed_association) with pytest.raises(RuntimeError, match="network-not-found"): asyncio.run( service.connect( _connect_request( device_id="k1-a", connection_mode="quick-connect", compatibility_attestation=QUICK_CONNECT_ATTESTATION, expected_mode_revision=mode_revision, ) ) ) state = service.state() # AP-ready is a semantic device-side commit. Host association may fail, # but the old Bridge route must not be resurrected and the new Quick # topology remains explicit, configured and offline. assert state["selected_device_id"] == "k1-a" assert state["k1_ip"] == facade_module.AP_FALLBACK_IPV4 assert state["connection_mode"] == "quick-connect" assert state["compatibility"]["attestation"]["topology"] == "device-ap" assert state["device_session"]["connectivity"] == "offline" assert state["connection_verification"]["lease_state"] == ("configured-unverified") operation = next(item for item in state["operations"] if item["action"] == "network.provision") assert operation["error"]["scan_attempt_count"] == 4 assert operation["error"]["scan_elapsed_ms"] == 15014 quick_sessions = sorted(service.evidence_root.glob("*viewer_k1_ap_association*")) failure_evidence = json.loads( (quick_sessions[0] / "host-wifi-association.redacted.json").read_text(encoding="utf-8") ) assert failure_evidence["reason_code"] == "network-not-found" assert failure_evidence["scan_attempt_count"] == 4 assert failure_evidence["scan_elapsed_ms"] == 15014 def test_quick_connect_keychain_failure_after_ap_write_preserves_side_effect_facts( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) mode_revision = _select_connection_mode(service, "quick-connect") _set_scanned_devices(service, [{"device_id": "k1-a", "name": "XGR-TEST-A"}]) monkeypatch.setattr( facade_module, "ensure_wifi_profile_from_credential_source", lambda *_args, **_kwargs: { "schema_version": 1, "adapter": "macOS Keychain", "available": True, "profile_enrolled": False, "credential_source": "exact-firmware-profile", }, ) @asynccontextmanager async def ready_activation( *_: object, on_write_dispatch: Callable[[dict[str, Any], str], None] | None = None, **__: object, ) -> AsyncIterator[dict[str, Any]]: assert on_write_dispatch is not None on_write_dispatch( _wifi_status_read(None, device_id="k1-a")["status"], "with_response", ) yield { "profile_id": "xgrids-k1-fw3-quick-connect-ap-v1", "started_at_utc": "2026-08-06T10:00:00Z", "completed_at_utc": "2026-08-06T10:00:01Z", "outcome": "ap_ready_observed", "ready_observed": True, "write_performed": True, "write_mode": "with_response", "observations": [{"status": _ap_ready_wifi_status()}], } def failed_post_write_profile_read(*_: object, **__: object) -> dict[str, Any]: raise facade_module.HostWifiProfileError( "keychain-authorization-required", ) monkeypatch.setattr(facade_module, "device_ap_activation_session", ready_activation) monkeypatch.setattr( facade_module, "associate_with_wifi_profile_once", failed_post_write_profile_read, ) with pytest.raises( facade_module.HostWifiProfileError, match="keychain-authorization-required", ): asyncio.run( service.connect( _connect_request( device_id="k1-a", connection_mode="quick-connect", compatibility_attestation=QUICK_CONNECT_ATTESTATION, expected_mode_revision=mode_revision, ) ) ) state = service.state() operation = next(item for item in state["operations"] if item["action"] == "network.provision") assert operation["stage_code"] == "host-wifi-association-failed" assert operation["error"]["code"] == "keychain-authorization-required" assert operation["error"]["host_diagnostic"]["code"] == ("host.keychain.interaction-required") assert operation["error"]["side_effect_status"] == "confirmed" assert operation["error"]["safe_to_retry"] is False assert "helper_stage" not in operation["error"] assert state["network_write_reconciliation"] is None def test_network_provisioning_rejects_an_ipv4_owned_by_the_local_host( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, caplog: pytest.LogCaptureFixture, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_devices(service, [{"device_id": "k1-a"}]) async def fake_provision( *_: object, on_write_dispatch: Callable[[dict[str, Any], str], None] | None = None, **__: object, ) -> dict[str, Any]: baseline_status = _ap_ready_wifi_status() assert on_write_dispatch is not None on_write_dispatch(baseline_status, "with_response") 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", "write_mode": "with_response", "baseline_status": baseline_status, "observations": [ { "status": { "mode": "WIFI_CLIENT", "ipv4": "10.255.254.51", "status_code": 1, "reserved": 0, } } ], } monkeypatch.setattr(facade_module, "provision_wifi_once", fake_provision) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: True) with ( caplog.at_level(logging.ERROR, logger=facade_module.__name__), pytest.raises(RuntimeError, match="уже принадлежит этому компьютеру"), ): asyncio.run( service.connect( _connect_request( device_id="k1-a", ssid="lab-network", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, ) ) ) state = service.state() # The K1 already confirmed its new device-side topology before the local # address conflict was discovered. Preserve that truth while withholding # all host/control authority. assert state["selected_device_id"] == "k1-a" assert state["k1_ip"] == "10.255.254.51" assert state["connection_mode"] == "bridge" assert state["device_session"]["connectivity"] == "offline" 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"] == "confirmed" assert state["network_write_reconciliation"] is None failure_log = next( record for record in caplog.records if getattr(record, "event_code", None) == "k1_network_provision_failed" ) assert failure_log.operation_stage == "ble-provisioning-write" assert failure_log.connection_mode == "bridge" assert failure_log.error_code == "RuntimeError" assert failure_log.safe_to_retry is False assert failure_log.side_effect_status == "confirmed" assert failure_log.network_change_attempted is True assert failure_log.device_write_attempted is True assert failure_log.device_write_confirmed is True assert PRIMARY_TEST_CREDENTIAL not in caplog.text assert "lab-network" not in caplog.text def test_ambiguous_ble_write_is_audit_only_for_next_explicit_intent( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, caplog: pytest.LogCaptureFixture, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_devices(service, [{"device_id": "k1-a"}]) calls = 0 async def ambiguous_write( *_: object, on_write_dispatch: Callable[[dict[str, Any], str], None] | None = None, **__: object, ) -> dict[str, Any]: nonlocal calls calls += 1 assert on_write_dispatch is not None on_write_dispatch( _wifi_status_read(None, device_id="k1-a")["status"], "with_response", ) exc = RuntimeError("synthetic transport failure") exc.operation_stage = "gatt-write" # type: ignore[attr-defined] exc.device_write_attempted = True # type: ignore[attr-defined] exc.device_write_confirmed = False # type: ignore[attr-defined] exc.att_error_code = 4 # type: ignore[attr-defined] exc.att_error_name = "INVALID_PDU" # type: ignore[attr-defined] exc.resolved_write_mode = "with_response" # type: ignore[attr-defined] exc.write_characteristic_properties = ( # type: ignore[attr-defined] "notify", "write", ) exc.max_write_without_response_size = 253 # type: ignore[attr-defined] exc.frame_length = 99 # type: ignore[attr-defined] raise exc monkeypatch.setattr(facade_module, "provision_wifi_once", ambiguous_write) with ( caplog.at_level(logging.ERROR, logger=facade_module.__name__), pytest.raises(RuntimeError, match="synthetic transport failure"), ): asyncio.run( service.connect( _connect_request( device_id="k1-a", ssid="lab-network", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, idempotency_key="ambiguous-write-1", ) ) ) state = service.state() operation = next(item for item in state["operations"] if item["action"] == "network.provision") assert operation["error"] == { "category": "device", "code": "RuntimeError", "retryable": False, "safe_to_retry": False, "side_effect_status": "unknown", "operation_stage": "gatt-write", "device_write_attempted": True, "device_write_confirmed": False, "ble_att_error_code": 4, "ble_att_error_name": "INVALID_PDU", "resolved_write_mode": "with_response", "max_write_without_response_size": 253, "frame_length": 99, "write_characteristic_properties": ["notify", "write"], } audit = state["network_write_reconciliation"] assert audit["status"] == "previous-session-result-unknown" assert audit["operation_id"] == operation["operation_id"] assert audit["reason_code"] == "network-mutation-audit-open" assert audit["required_action"] == "none" assert audit["blocks_new_explicit_intent"] is False failure_log = next( record for record in caplog.records if getattr(record, "event_code", None) == "k1_network_provision_failed" ) assert failure_log.resolved_write_mode == "with_response" assert failure_log.write_characteristic_properties == ["notify", "write"] assert failure_log.max_write_without_response_size == 253 assert failure_log.frame_length == 99 restarted_service, _ = service_with_fake_runtime(tmp_path) _set_scanned_devices(restarted_service, [{"device_id": "k1-a"}]) restarted_state = restarted_service.state() assert restarted_state["network_write_reconciliation"] is None assert restarted_state["network_mutation_ledger"]["mutation_allowed"] is True assert restarted_state["network_mutation_ledger"]["resolution"] == "interrupted" assert ( restarted_state["connection_policy"]["actions"]["provision-fresh-device"]["allowed"] is True ) assert calls == 1 def test_unchanged_status_does_not_confirm_without_response_write( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, caplog: pytest.LogCaptureFixture, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_devices(service, [{"device_id": "k1-a"}]) unchanged_status = _wifi_status_read(None, device_id="k1-a")["status"] async def unchanged_write( *_: object, on_write_dispatch: Callable[[dict[str, Any], str], None] | None = None, **__: object, ) -> dict[str, Any]: assert on_write_dispatch is not None on_write_dispatch(unchanged_status, "without_response") return { "started_at_utc": "2026-08-06T10:00:00Z", "completed_at_utc": "2026-08-06T10:00:01Z", "profile_id": "xgrids-k1-fw3-wifi-v1", "outcome": "no_status_change_before_timeout", "write_mode": "without_response", "baseline_status": unchanged_status, "observations": [{"status": unchanged_status}], } monkeypatch.setattr(facade_module, "provision_wifi_once", unchanged_write) with ( caplog.at_level(logging.ERROR, logger=facade_module.__name__), pytest.raises(RuntimeError, match="не сообщило адрес"), ): asyncio.run( service.connect( _connect_request( device_id="k1-a", ssid="lab-network", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, ) ) ) record = next( item for item in caplog.records if getattr(item, "event_code", None) == "k1_network_provision_failed" ) assert record.device_write_attempted is True assert record.device_write_confirmed is False assert record.side_effect_status == "unknown" fence = service.state()["network_write_reconciliation"] assert fence is not None assert fence["transport_ref"] == "k1-a" assert fence["connection_mode"] == "bridge" assert fence["operation_stage"] == "observing" assert fence["reason_code"] == "network-mutation-audit-open" assert fence["required_action"] == "none" assert fence["blocks_new_explicit_intent"] is False assert fence["scope"] == "durable-ledger" assert fence["ledger_revision"] == 3 ledger = service.state()["network_mutation_ledger"] assert ledger["status"] == "unresolved" assert ledger["mutation_allowed"] is True assert ledger["stage"] == "observing" assert ledger["revision"] == 3 def test_same_bridge_baseline_does_not_confirm_with_response_write( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_devices(service, [{"device_id": "k1-a"}]) unchanged_status = _wifi_status_read("192.168.68.50", device_id="k1-a")["status"] async def unchanged_write( *_: object, on_write_dispatch: Callable[[dict[str, Any], str], None] | None = None, **__: object, ) -> dict[str, Any]: assert on_write_dispatch is not None on_write_dispatch(unchanged_status, "with_response") return { "started_at_utc": "2026-08-06T10:00:00Z", "completed_at_utc": "2026-08-06T10:00:01Z", "profile_id": "xgrids-k1-fw3-wifi-v1", "outcome": "no_status_change_before_timeout", "write_mode": "with_response", "baseline_status": unchanged_status, "observations": [{"status": unchanged_status}], } monkeypatch.setattr(facade_module, "provision_wifi_once", unchanged_write) with pytest.raises(RuntimeError, match="не сообщило адрес"): asyncio.run( service.connect( _connect_request( device_id="k1-a", ssid="replacement-network", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, ) ) ) state = service.state() assert state["network_mutation_ledger"]["status"] == "unresolved" assert state["network_mutation_ledger"]["stage"] == "observing" assert state["network_mutation_ledger"]["resolution"] is None assert state["network_write_reconciliation"] is not None assert state["semantic_topology_store"]["status"] == "empty" assert state["selected_device_id"] is None @pytest.mark.parametrize( ("connection_mode", "attestation", "observed_ipv4"), [ ("bridge", ATTESTATION, "192.168.68.99"), ("direct-connect", DIRECT_CONNECT_ATTESTATION, "172.20.10.2"), ], ) def test_live_client_baseline_with_different_ipv4_keeps_write_ambiguous( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, connection_mode: NetworkConnectionMode, attestation: CompatibilityAttestationRequest, observed_ipv4: str, ) -> None: service, _ = service_with_fake_runtime(tmp_path) mode_revision = _select_connection_mode(service, connection_mode) _set_scanned_devices(service, [{"device_id": "k1-a"}]) baseline = _wifi_status_read("192.168.68.40", device_id="k1-a")["status"] async def changed_client_address( *_: object, on_write_dispatch: Callable[[dict[str, Any], str], None] | None = None, **__: object, ) -> dict[str, Any]: assert on_write_dispatch is not None on_write_dispatch(baseline, "with_response") return { "started_at_utc": "2026-08-06T10:00:00Z", "completed_at_utc": "2026-08-06T10:00:01Z", "profile_id": "xgrids-k1-fw3-wifi-v1", "outcome": "lan_address_observed", "write_mode": "with_response", "baseline_status": baseline, "observations": [ { "status": _wifi_status_read( observed_ipv4, device_id="k1-a", )["status"] } ], } monkeypatch.setattr(facade_module, "provision_wifi_once", changed_client_address) with pytest.raises(RuntimeError, match="не сообщило адрес"): asyncio.run( service.connect( _connect_request( device_id="k1-a", ssid="replacement-network", password=SecretStr(PRIMARY_TEST_CREDENTIAL), connection_mode=connection_mode, compatibility_attestation=attestation, expected_mode_revision=mode_revision, ) ) ) state = service.state() assert state["network_mutation_ledger"]["status"] == "unresolved" assert state["network_mutation_ledger"]["stage"] == "observing" assert state["network_mutation_ledger"]["resolution"] is None assert state["network_write_reconciliation"] is not None assert state["semantic_topology_store"]["status"] == "empty" assert state["selected_device_id"] is None def test_read_only_reconciliation_terminalizes_the_matching_idempotency_edge( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service) _seed_unresolved_network_mutation( service, operation_id="lost-response-operation", ) reads = 0 async def read_current_status(*_: object, **__: object) -> dict[str, Any]: nonlocal reads reads += 1 return _wifi_status_read("192.168.68.50") monkeypatch.setattr(facade_module, "read_wifi_status_once", read_current_status) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr(facade_module, "_host_route_class", lambda _target: "direct-or-routed") monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) monkeypatch.setattr(facade_module, "_control_endpoint_reachable", lambda _target: True) state = asyncio.run( service.verify_connection( ConnectionVerifyRequest( device_id="test-ble-transport", compatibility_attestation=ATTESTATION, expected_discovery_generation=0, ) ) ) assert reads == 1 assert state["connection_mode"] == "bridge" assert state["k1_ip"] == "192.168.68.50" assert state["network_write_reconciliation"] is None assert state["network_mutation_ledger"]["status"] == "resolved" assert state["network_mutation_ledger"]["resolution"] == "target-observed" assert state["network_provisioning_idempotency"] == { "status": "ready", "revision": state["network_provisioning_idempotency"]["revision"], "reason_code": None, "active_operation_id": None, "active_action": None, "active_stage": None, "terminal_record_count": 1, "mutation_allowed": True, } idempotency_record = ( service._require_network_provisioning_idempotency_journal() # noqa: SLF001 .snapshot() .records[0] ) assert idempotency_record.operation_id == "lost-response-operation" assert idempotency_record.stage == "terminal" assert idempotency_record.terminal is not None assert idempotency_record.terminal.outcome == "succeeded" assert idempotency_record.terminal.outcome_code == "network.provision.reconciled" assert idempotency_record.terminal.side_effect_status == "reconciled" def test_restart_interrupts_legacy_edge_before_optional_read_only_verify( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) operation_id = "legacy-read-only-reconciliation" _seed_legacy_network_mutation_without_idempotency( service, operation_id=operation_id, stage="observing", ) restarted, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(restarted) reads = 0 async def read_current_status(*_: object, **__: object) -> dict[str, Any]: nonlocal reads reads += 1 return _wifi_status_read("192.168.68.50") monkeypatch.setattr(facade_module, "read_wifi_status_once", read_current_status) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr(facade_module, "_host_route_class", lambda _target: "direct-or-routed") monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) monkeypatch.setattr(facade_module, "_control_endpoint_reachable", lambda _target: True) state = asyncio.run( restarted.verify_connection( ConnectionVerifyRequest( device_id="test-ble-transport", compatibility_attestation=ATTESTATION, expected_discovery_generation=0, ) ) ) assert reads == 1 assert state["network_write_reconciliation"] is None assert state["network_mutation_ledger"]["status"] == "resolved" assert state["network_mutation_ledger"]["resolution"] == "interrupted" idempotency = restarted._require_network_provisioning_idempotency_journal().snapshot() # noqa: SLF001 assert idempotency.status == "ready" assert idempotency.active_record is None terminal = idempotency.records[-1] assert terminal.operation_id == operation_id assert terminal.stage == "terminal" assert terminal.terminal is not None assert terminal.terminal.outcome_code == "network.provision.interrupted" assert terminal.terminal.side_effect_status == "reconciled" def test_read_only_reconciliation_rejects_cross_journal_mismatch_before_gatt( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service) fence = _seed_unresolved_network_mutation( service, operation_id="network-ledger-operation", idempotency_operation_id="idempotency-journal-operation", ) async def forbidden_status_read(*_: object, **__: object) -> dict[str, Any]: raise AssertionError("cross-journal mismatch must fail before GATT") monkeypatch.setattr(facade_module, "read_wifi_status_once", forbidden_status_read) with pytest.raises(facade_module.ConnectionVerificationError) as raised: asyncio.run( service.verify_connection( ConnectionVerifyRequest( device_id="test-ble-transport", compatibility_attestation=ATTESTATION, expected_discovery_generation=0, ) ) ) assert raised.value.reason_code == "connection-verify-idempotency-operation-mismatch" state = service.state() assert state["network_write_reconciliation"] == fence assert state["network_mutation_ledger"]["status"] == "unresolved" assert state["network_provisioning_idempotency"]["status"] == "blocked" assert state["network_provisioning_idempotency"]["active_operation_id"] == ( "idempotency-journal-operation" ) def test_read_only_addressless_status_keeps_network_write_reconciliation_fence( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service) _seed_unresolved_network_mutation(service) async def read_current_status(*_: object, **__: object) -> dict[str, Any]: return _wifi_status_read(None) monkeypatch.setattr(facade_module, "read_wifi_status_once", read_current_status) with pytest.raises( facade_module.ConnectionVerificationError, match="не сообщил адрес общей локальной сети", ) as raised: asyncio.run( service.verify_connection( ConnectionVerifyRequest( device_id="test-ble-transport", compatibility_attestation=ATTESTATION, expected_discovery_generation=0, ) ) ) assert raised.value.reason_code == "connection-verify-address-unavailable" fence = service.state()["network_write_reconciliation"] assert fence is not None assert fence["operation_id"] == "ambiguous-operation" assert fence["operation_stage"] == "dispatching" assert fence["scope"] == "durable-ledger" assert fence["ledger_revision"] == 2 def test_read_only_ble_status_for_another_transport_keeps_reconciliation_fence( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service, device_id="k1-b") fence = _seed_unresolved_network_mutation(service, transport_ref="k1-a") async def read_other_status(*_: object, **__: object) -> dict[str, Any]: raise AssertionError("target mismatch must fail before a GATT read") monkeypatch.setattr(facade_module, "read_wifi_status_once", read_other_status) with pytest.raises( facade_module.ConnectionVerificationError, match="относится к другому K1", ) as raised: asyncio.run( service.verify_connection( ConnectionVerifyRequest( device_id="k1-b", compatibility_attestation=ATTESTATION, expected_discovery_generation=0, ) ) ) assert raised.value.reason_code == "connection-verify-reconciliation-target-mismatch" assert service.state()["network_write_reconciliation"] == fence @pytest.mark.parametrize( ("intended_mode", "attestation", "requested_mode"), [ ("bridge", DIRECT_CONNECT_ATTESTATION, "direct-connect"), ("direct-connect", ATTESTATION, "bridge"), ], ) def test_read_only_reconciliation_requires_exact_requested_mode_despite_shared_status( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, intended_mode: NetworkConnectionMode, attestation: CompatibilityAttestationRequest, requested_mode: str, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service) original_fence = _seed_unresolved_network_mutation( service, intended_mode=intended_mode, ) async def read_current_status(*_: object, **__: object) -> dict[str, Any]: raise AssertionError("mode mismatch must fail before a GATT read") monkeypatch.setattr(facade_module, "read_wifi_status_once", read_current_status) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr(facade_module, "_host_route_class", lambda _target: "direct-or-routed") monkeypatch.setattr(facade_module, "_control_endpoint_reachable", lambda _target: True) monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) with pytest.raises(facade_module.ConnectionVerificationError) as raised: asyncio.run( service.verify_connection( ConnectionVerifyRequest( device_id="test-ble-transport", compatibility_attestation=attestation, expected_discovery_generation=0, ) ) ) assert raised.value.reason_code == "connection-verify-reconciliation-target-mismatch" state = service.state() assert state["connection_mode"] is None assert state["k1_ip"] is None assert state["network_write_reconciliation"] == original_fence ledger = state["network_mutation_ledger"] assert ledger["status"] == "unresolved" assert ledger["mutation_allowed"] is True assert ledger["intended_mode"] == intended_mode assert ledger["revision"] == 2 assert ledger["resolution"] is None verify_operation = next( item for item in state["operations"] if item["action"] == "connection.verify" ) assert verify_operation["status"] == "failed" def test_durable_restart_interrupts_old_attempt_without_implicit_gatt_recovery( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: first, _ = service_with_fake_runtime(tmp_path) _seed_unresolved_network_mutation( first, operation_id="durable-restart-reconciliation", transport_ref=DURABLE_K1_UUID, ) restarted, _ = service_with_fake_runtime(tmp_path) captured = _durable_status_capture() status_reads: list[tuple[str, bool, str | None]] = [] pin_calls: list[tuple[object, str]] = [] write_calls: list[str] = [] async def read_server_target( device_id: str, *, captured_device: object | None = None, recovery_device_session_id: str | None = None, allow_known_device_retrieval: bool = False, on_gatt_validated: Callable[[object], None] | None = None, **_: object, ) -> dict[str, Any]: status_reads.append((device_id, allow_known_device_retrieval, recovery_device_session_id)) assert captured_device is None assert on_gatt_validated is not None on_gatt_validated(captured) return _wifi_status_read("192.168.68.50", device_id=device_id) async def forbidden_write(*_: object, **__: object) -> dict[str, Any]: write_calls.append("write") raise AssertionError("durable reconciliation must not write to K1") monkeypatch.setattr(facade_module, "read_wifi_status_once", read_server_target) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_write) monkeypatch.setattr( facade_module, "pin_connected_device_handle", lambda handle, *, device_session_id: pin_calls.append((handle, device_session_id)), ) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr(facade_module, "_host_route_class", lambda _target: "direct-or-routed") monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) monkeypatch.setattr(facade_module, "_control_endpoint_reachable", lambda _target: True) before = restarted.state() assert before["devices"] == [] assert before["selected_device_id"] is None assert before["network_mutation_ledger"]["status"] == "resolved" assert before["network_mutation_ledger"]["resolution"] == "interrupted" with pytest.raises(facade_module.ConnectionVerificationError) as raised: asyncio.run( restarted.verify_connection( ConnectionVerifyRequest( device_id=DURABLE_K1_UUID, source="durable-configured-state", compatibility_attestation=ATTESTATION, ) ) ) assert raised.value.reason_code == "connection-verify-candidate-not-fresh" state = restarted.state() assert status_reads == [] assert write_calls == [] assert pin_calls == [] assert state["selected_device_id"] is None assert state["device_session"] is None assert state["network_write_reconciliation"] is None assert state["network_mutation_ledger"]["status"] == "resolved" assert state["network_mutation_ledger"]["resolution"] == "interrupted" assert state["network_provisioning_idempotency"]["status"] == "ready" assert state["network_provisioning_idempotency"]["active_operation_id"] is None assert state["network_provisioning_idempotency"]["terminal_record_count"] == 1 terminal = ( restarted._require_network_provisioning_idempotency_journal() # noqa: SLF001 .snapshot() .records[-1] ) assert terminal.operation_id == "durable-restart-reconciliation" assert terminal.stage == "terminal" assert terminal.terminal is not None assert terminal.terminal.outcome_code == "network.provision.interrupted" assert terminal.terminal.side_effect_status == "reconciled" assert state["connection_supervisor"]["authority"]["control_allowed"] is False # Without an independently durable current/configured topology, startup's # interrupted audit must not turn an arbitrary new advertisement into an # implicit recovery continuation. _set_scanned_k1(restarted, device_id="replacement-k1") fresh_policy = restarted.state()["connection_policy"] assert fresh_policy["actions"]["observe-fresh-device-network"]["allowed"] is True assert fresh_policy["recommended_action"] == "select-connection-intent" @pytest.mark.parametrize( ("device_id", "attestation", "source", "reason_code"), [ ( "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE", ATTESTATION, "durable-configured-state", "connection-verify-reconciliation-target-mismatch", ), ( DURABLE_K1_UUID, QUICK_CONNECT_ATTESTATION, "durable-configured-state", "connection-verify-reconciliation-target-mismatch", ), ( DURABLE_K1_UUID, ATTESTATION, "fresh-scan", "connection-verify-source-mismatch", ), ], ) def test_durable_restart_rejects_request_target_mismatch_before_gatt( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, device_id: str, attestation: CompatibilityAttestationRequest, source: str, reason_code: str, ) -> None: first, _ = service_with_fake_runtime(tmp_path) _seed_unresolved_network_mutation( first, operation_id="durable-request-mismatch", transport_ref=DURABLE_K1_UUID, ) restarted, _ = service_with_fake_runtime(tmp_path) reads: list[str] = [] async def forbidden_read(*_: object, **__: object) -> dict[str, Any]: reads.append("read") raise AssertionError("request mismatch must fail before GATT") monkeypatch.setattr(facade_module, "read_wifi_status_once", forbidden_read) monkeypatch.setattr( facade_module, "provision_wifi_once", lambda *_args, **_kwargs: (_ for _ in ()).throw( AssertionError("request mismatch must not write") ), ) with pytest.raises(facade_module.ConnectionVerificationError) as raised: asyncio.run( restarted.verify_connection( ConnectionVerifyRequest( device_id=device_id, source=source, # type: ignore[arg-type] compatibility_attestation=attestation, **({"expected_discovery_generation": 0} if source == "fresh-scan" else {}), ) ) ) assert raised.value.reason_code == "connection-verify-candidate-not-fresh" assert reads == [] state = restarted.state() assert state["network_write_reconciliation"] is None assert state["network_mutation_ledger"]["status"] == "resolved" assert state["network_mutation_ledger"]["resolution"] == "interrupted" assert state["selected_device_id"] is None assert state["device_session"] is None def test_durable_restart_same_bridge_baseline_cannot_resolve_ambiguous_write( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: baseline = NetworkStatusEvidence( mode="WIFI_CLIENT", ipv4="192.168.68.50", status_code=1, reserved=0, ) first, _ = service_with_fake_runtime(tmp_path) _seed_unresolved_network_mutation( first, operation_id="durable-unchanged-bridge-baseline", transport_ref=DURABLE_K1_UUID, baseline_status=baseline, ) restarted, _ = service_with_fake_runtime(tmp_path) captured = _durable_status_capture() reads = 0 pin_calls: list[tuple[object, str]] = [] async def read_unchanged_bridge_status( device_id: str, *, allow_known_device_retrieval: bool = False, on_gatt_validated: Callable[[object], None] | None = None, **_: object, ) -> dict[str, Any]: nonlocal reads reads += 1 assert device_id == DURABLE_K1_UUID assert allow_known_device_retrieval is True assert on_gatt_validated is not None on_gatt_validated(captured) return _wifi_status_read("192.168.68.50", device_id=device_id) monkeypatch.setattr( facade_module, "read_wifi_status_once", read_unchanged_bridge_status, ) monkeypatch.setattr( facade_module, "pin_connected_device_handle", lambda handle, *, device_session_id: pin_calls.append((handle, device_session_id)), ) with pytest.raises(facade_module.ConnectionVerificationError) as raised: asyncio.run( restarted.verify_connection( ConnectionVerifyRequest( device_id=DURABLE_K1_UUID, source="durable-configured-state", compatibility_attestation=ATTESTATION, ) ) ) assert raised.value.reason_code == "connection-verify-candidate-not-fresh" assert reads == 0 assert pin_calls == [] state = restarted.state() assert state["network_write_reconciliation"] is None assert state["network_mutation_ledger"]["status"] == "resolved" assert state["network_mutation_ledger"]["resolution"] == "interrupted" assert state["network_provisioning_idempotency"]["status"] == "ready" assert state["semantic_topology_store"]["status"] == "empty" assert state["selected_device_id"] is None assert state["device_session"] is None @pytest.mark.parametrize( ("intended_mode", "attestation", "baseline", "previous", "observed_status"), [ ( "quick-connect", QUICK_CONNECT_ATTESTATION, NetworkStatusEvidence("WIFI_CLIENT", "192.168.68.50", 1, 0), PreviousConnectionEvidence( DURABLE_K1_UUID, "quick-connect", "192.168.56.1", "previous-quick-session", ), _ap_ready_wifi_status(), ), ( "bridge", ATTESTATION, NetworkStatusEvidence("WIFI_AP", "192.168.56.1", 1, 1), PreviousConnectionEvidence( DURABLE_K1_UUID, "bridge", "192.168.68.40", "previous-bridge-session", ), _wifi_status_read("192.168.68.99")["status"], ), ( "direct-connect", DIRECT_CONNECT_ATTESTATION, NetworkStatusEvidence("WIFI_AP", "192.168.56.1", 1, 1), PreviousConnectionEvidence( DURABLE_K1_UUID, "direct-connect", "172.20.10.3", "previous-direct-session", ), _wifi_status_read("172.20.10.2")["status"], ), ], ) def test_durable_restart_previous_topology_cannot_resolve_ambiguous_write( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, intended_mode: NetworkConnectionMode, attestation: CompatibilityAttestationRequest, baseline: NetworkStatusEvidence, previous: PreviousConnectionEvidence, observed_status: dict[str, Any], ) -> None: first, _ = service_with_fake_runtime(tmp_path) _seed_unresolved_network_mutation( first, operation_id=f"durable-previous-{intended_mode}", transport_ref=DURABLE_K1_UUID, intended_mode=intended_mode, baseline_status=baseline, previous_connection=previous, ) restarted, _ = service_with_fake_runtime(tmp_path) captured = _durable_status_capture() reads = 0 pin_calls: list[tuple[object, str]] = [] write_calls: list[str] = [] async def read_previous_topology( device_id: str, *, allow_known_device_retrieval: bool = False, on_gatt_validated: Callable[[object], None] | None = None, **_: object, ) -> dict[str, Any]: nonlocal reads reads += 1 assert device_id == DURABLE_K1_UUID assert allow_known_device_retrieval is True assert on_gatt_validated is not None on_gatt_validated(captured) status_read = _wifi_status_read(None, device_id=device_id) status_read["status"] = observed_status return status_read async def forbidden_write(*_: object, **__: object) -> dict[str, Any]: write_calls.append("write") raise AssertionError("read-only restart reconciliation must not write") monkeypatch.setattr(facade_module, "read_wifi_status_once", read_previous_topology) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_write) monkeypatch.setattr( facade_module, "pin_connected_device_handle", lambda handle, *, device_session_id: pin_calls.append((handle, device_session_id)), ) with pytest.raises(facade_module.ConnectionVerificationError) as raised: asyncio.run( restarted.verify_connection( ConnectionVerifyRequest( device_id=DURABLE_K1_UUID, source="durable-configured-state", compatibility_attestation=attestation, ) ) ) assert raised.value.reason_code == "connection-verify-candidate-not-fresh" assert reads == 0 assert write_calls == [] assert pin_calls == [] state = restarted.state() assert state["network_write_reconciliation"] is None assert state["network_mutation_ledger"]["status"] == "resolved" assert state["network_mutation_ledger"]["resolution"] == "interrupted" assert state["network_provisioning_idempotency"]["status"] == "ready" assert state["semantic_topology_store"]["status"] == "empty" assert state["selected_device_id"] is None assert state["device_session"] is None @pytest.mark.parametrize("outcome", ["baseline", "wrong-mode", "read-failure"]) def test_durable_restart_failed_status_keeps_ambiguity_and_does_not_pin( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, outcome: str, ) -> None: first, _ = service_with_fake_runtime(tmp_path) _seed_unresolved_network_mutation( first, operation_id=f"durable-{outcome}", transport_ref=DURABLE_K1_UUID, ) restarted, _ = service_with_fake_runtime(tmp_path) captured = _durable_status_capture() reads = 0 pin_calls: list[tuple[object, str]] = [] write_calls: list[str] = [] async def read_nonmatching_status( device_id: str, *, allow_known_device_retrieval: bool = False, on_gatt_validated: Callable[[object], None] | None = None, **_: object, ) -> dict[str, Any]: nonlocal reads reads += 1 assert device_id == DURABLE_K1_UUID assert allow_known_device_retrieval is True if outcome == "read-failure": raise RuntimeError("synthetic durable GATT read failure") assert on_gatt_validated is not None on_gatt_validated(captured) result = _wifi_status_read(None, device_id=device_id) if outcome == "wrong-mode": result["status"] = _ap_ready_wifi_status() return result async def forbidden_write(*_: object, **__: object) -> dict[str, Any]: write_calls.append("write") raise AssertionError("failed status observation must not write") monkeypatch.setattr(facade_module, "read_wifi_status_once", read_nonmatching_status) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_write) monkeypatch.setattr( facade_module, "pin_connected_device_handle", lambda handle, *, device_session_id: pin_calls.append((handle, device_session_id)), ) with pytest.raises(facade_module.ConnectionVerificationError): asyncio.run( restarted.verify_connection( ConnectionVerifyRequest( device_id=DURABLE_K1_UUID, source="durable-configured-state", compatibility_attestation=ATTESTATION, ) ) ) assert reads == 0 assert write_calls == [] assert pin_calls == [] state = restarted.state() assert state["network_mutation_ledger"]["status"] == "resolved" assert state["network_mutation_ledger"]["resolution"] == "interrupted" assert state["network_provisioning_idempotency"]["status"] == "ready" assert state["semantic_topology_store"]["status"] == "empty" assert state["selected_device_id"] is None assert state["device_session"] is None def test_semantic_only_durable_restart_uses_lan_and_mqtt_identity_not_ble( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: first, _ = service_with_fake_runtime(tmp_path) topology_store = first._semantic_topology_store # noqa: SLF001 assert topology_store is not None topology_store.commit( transport_ref=DURABLE_K1_UUID, connection_mode="bridge", ipv4="192.168.68.50", compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, firmware_version="3.0.2", source="ble-read-only-status", observed_at_utc="2026-08-06T12:00:00Z", ) _seed_unresolved_network_mutation( first, operation_id="semantic-restart-post-dispatch-unknown", transport_ref=DURABLE_K1_UUID, intended_mode="bridge", ) restarted, _ = service_with_fake_runtime(tmp_path) association_probe = FakeHostWifiAssociationProbe("a" * 64) restarted._host_wifi_association_probe = association_probe # type: ignore[assignment] # noqa: SLF001 reads = 0 pin_calls: list[tuple[object, str]] = [] binding_validation_epochs: list[tuple[int, int]] = [] async def forbidden_status_read(*_: object, **__: object) -> dict[str, Any]: nonlocal reads reads += 1 raise AssertionError("resolved durable restart must not require BLE") monkeypatch.setattr(facade_module, "read_wifi_status_once", forbidden_status_read) network_writes: list[str] = [] async def forbidden_network_write(*_: object, **__: object) -> dict[str, Any]: network_writes.append("network-write") raise AssertionError("semantic observation must not write") monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_network_write) monkeypatch.setattr( facade_module, "pin_connected_device_handle", lambda handle, *, device_session_id: pin_calls.append((handle, device_session_id)), ) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) monkeypatch.setattr( facade_module, "_probe_control_endpoint_socket", lambda _target: facade_module.TcpReachabilityProbeResult(reachable=True), ) async def bootstrap_after_exact_path_validation( bound_service: XgridsK1CompatibilityService, *, parent_operation_id: str | None, connection_mode: facade_module.ConnectionMode, inspection_only: bool = False, ) -> None: supervisor = bound_service._connection_supervisor.snapshot() # noqa: SLF001 assert supervisor.intent is not None assert supervisor.device_network.target is not None assert supervisor.device_network.transport_ref is not None binding = ApplicationConnectionBinding( intent_id=supervisor.intent.intent_id, transport_ref=supervisor.device_network.transport_ref, host_path_epoch=supervisor.host_path.epoch, target_ipv4=supervisor.device_network.target.ipv4, target_port=supervisor.device_network.target.port, connection_mode=connection_mode, ) epoch_before = supervisor.host_path.epoch bound_service._validate_application_connection_path(binding) # noqa: SLF001 epoch_after = bound_service._connection_supervisor.snapshot().host_path.epoch # noqa: SLF001 binding_validation_epochs.append((epoch_before, epoch_after)) await _synthetic_prestart_control_bootstrap( bound_service, parent_operation_id=parent_operation_id, connection_mode=connection_mode, inspection_only=inspection_only, ) restarted._bootstrap_prestart_control_ready_owned = MethodType( # type: ignore[method-assign] # noqa: SLF001 bootstrap_after_exact_path_validation, restarted, ) before = restarted.state() assert before["devices"] == [] assert before["selected_device_id"] is None assert before["connection_attempt"] is None assert before["network_mutation_ledger"]["status"] == "resolved" assert before["network_mutation_ledger"]["resolution"] == "interrupted" assert before["semantic_topology_store"]["record"]["revision"] == 1 assert ( before["connection_policy"]["actions"]["observe-configured-device-network"][ "requires_live_gatt_validation" ] is False ) assert ( before["connection_policy"]["actions"]["observe-configured-device-network"]["allowed"] is True ) assert before["connection_policy"]["recommended_action"] == ( "observe-configured-device-network" ) assert before["connection_policy"]["actions"]["scan-ble"]["allowed"] is True state = asyncio.run( restarted.verify_connection( ConnectionVerifyRequest( device_id=DURABLE_K1_UUID, source="durable-configured-state", compatibility_attestation=ATTESTATION, ) ) ) assert reads == 0 assert network_writes == [] assert pin_calls == [] assert state["semantic_topology_store"]["record"]["revision"] == 1 assert state["connection_verification"]["endpoint_validation"] == ( "durable-semantic-topology+mqtt-tcp-connect" ) assert state["connection_verification"]["lease_state"] == "reachable" assert state["connection_supervisor"]["observed"]["device_network"]["source"] == ( "durable-semantic-topology" ) assert state["connection_supervisor"]["observed"]["device_identity"]["state"] == "verified" assert state["connection_supervisor"]["authority"]["control_allowed"] is True assert state["connection_supervisor"]["authority"]["acquisition_start_allowed"] is True assert binding_validation_epochs == [(1, 1)] assert association_probe.interfaces == ["test0", "test0", "test0"] assert state["connection_supervisor"]["observed"]["host_path"]["fingerprint"] != ( "test-route:192.168.68.50" ) def test_semantic_durable_verify_refreshes_stale_dhcp_over_exact_read_only_ble( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: first, _ = service_with_fake_runtime(tmp_path) topology_store = first._semantic_topology_store # noqa: SLF001 assert topology_store is not None topology_store.commit( transport_ref=DURABLE_K1_UUID, connection_mode="bridge", ipv4="192.168.68.50", compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, firmware_version="3.0.2", source="ble-read-only-status", observed_at_utc="2026-08-06T12:00:00Z", ) restarted, _ = service_with_fake_runtime(tmp_path) association_probe = FakeHostWifiAssociationProbe("a" * 64) restarted._host_wifi_association_probe = association_probe # type: ignore[assignment] # noqa: SLF001 capture = _durable_status_capture() status_reads: list[tuple[str, bool, str | None]] = [] pin_calls: list[tuple[object, str]] = [] network_writes: list[str] = [] async def read_current_dhcp_status( device_id: str, *, captured_device: object | None = None, recovery_device_session_id: str | None = None, allow_known_device_retrieval: bool = False, on_gatt_validated: Callable[[object], None] | None = None, **_: object, ) -> dict[str, Any]: status_reads.append( (device_id, allow_known_device_retrieval, recovery_device_session_id) ) assert captured_device is None assert allow_known_device_retrieval is True assert on_gatt_validated is not None on_gatt_validated(capture) return _wifi_status_read("192.168.68.51", device_id=device_id) async def forbidden_network_write(*_: object, **__: object) -> dict[str, Any]: network_writes.append("network-write") raise AssertionError("stale DHCP recovery must not write to K1") monkeypatch.setattr(facade_module, "read_wifi_status_once", read_current_dhcp_status) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_network_write) monkeypatch.setattr( facade_module, "pin_connected_device_handle", lambda handle, *, device_session_id: pin_calls.append((handle, device_session_id)), ) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) monkeypatch.setattr(facade_module, "_host_route_class", lambda _target: "direct-or-routed") monkeypatch.setattr(facade_module, "_control_endpoint_reachable", lambda _target: True) monkeypatch.setattr( facade_module, "_probe_configured_endpoint_host_only", lambda target, **_kwargs: facade_module._ConfiguredEndpointHostObservation( # noqa: SLF001 path=_direct_host_path(target), reachable=False, reason_code="tcp-connection-timeout", ), ) async def bootstrap_after_refresh( bound_service: XgridsK1CompatibilityService, *, parent_operation_id: str | None, connection_mode: facade_module.ConnectionMode, inspection_only: bool = False, ) -> None: await _synthetic_prestart_control_bootstrap( bound_service, parent_operation_id=parent_operation_id, connection_mode=connection_mode, inspection_only=inspection_only, ) restarted._bootstrap_prestart_control_ready_owned = MethodType( # type: ignore[method-assign] # noqa: SLF001 bootstrap_after_refresh, restarted, ) state = asyncio.run( restarted.verify_connection( ConnectionVerifyRequest( device_id=DURABLE_K1_UUID, source="durable-configured-state", compatibility_attestation=ATTESTATION, ) ) ) assert status_reads == [(DURABLE_K1_UUID, True, None)] assert network_writes == [] assert len(pin_calls) == 1 assert pin_calls[0][0] is capture assert state["k1_ip"] == "192.168.68.51" assert state["semantic_topology_store"]["record"]["revision"] == 2 assert state["semantic_topology_store"]["record"]["ipv4"] == "192.168.68.51" assert state["connection_verification"]["endpoint_validation"] == ( "ble-wifi-status-read+mqtt-tcp-connect" ) assert state["connection_verification"]["address_source"] == "ble-wifi-status-read" assert state["connection_verification"]["address_changed"] is True assert state["connection_verification"]["write_performed"] is False assert state["connection_supervisor"]["observed"]["device_identity"]["state"] == ( "verified" ) assert state["connection_supervisor"]["authority"]["control_allowed"] is True def test_semantic_durable_verify_rejects_association_change_during_tcp_probe( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: first, _ = service_with_fake_runtime(tmp_path) topology_store = first._semantic_topology_store # noqa: SLF001 assert topology_store is not None topology_store.commit( transport_ref=DURABLE_K1_UUID, connection_mode="bridge", ipv4="192.168.68.50", compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, firmware_version="3.0.2", source="ble-read-only-status", observed_at_utc="2026-08-06T12:00:00Z", ) restarted, _ = service_with_fake_runtime(tmp_path) association_probe = FakeHostWifiAssociationProbe("a" * 64, "b" * 64) restarted._host_wifi_association_probe = association_probe # type: ignore[assignment] # noqa: SLF001 device_edges: list[str] = [] async def forbidden_device_edge(*_: object, **__: object) -> dict[str, Any]: device_edges.append("device") raise AssertionError("association race must fail before BLE or device write") async def forbidden_bootstrap(*_: object, **__: object) -> None: device_edges.append("mqtt-bootstrap") raise AssertionError("association race must fail before DeviceInfo bootstrap") monkeypatch.setattr(facade_module, "read_wifi_status_once", forbidden_device_edge) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_device_edge) monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) monkeypatch.setattr( facade_module, "_probe_control_endpoint_socket", lambda _target: facade_module.TcpReachabilityProbeResult(reachable=True), ) restarted._bootstrap_prestart_control_ready_owned = forbidden_bootstrap # type: ignore[method-assign] # noqa: SLF001 with pytest.raises(facade_module.ConnectionVerificationError) as raised: asyncio.run( restarted.verify_connection( ConnectionVerifyRequest( device_id=DURABLE_K1_UUID, source="durable-configured-state", compatibility_attestation=ATTESTATION, ) ) ) assert raised.value.reason_code == "connection-verify-mqtt-unreachable" assert device_edges == [] assert association_probe.interfaces == ["test0", "test0"] state = restarted.state() assert state["selected_device_id"] is None assert state["active_connection_mode"] is None assert state["connection_supervisor"]["intent"] is None assert state["connection_supervisor"]["observed"]["endpoint"]["target"] is None assert state["semantic_topology_store"]["record"]["revision"] == 1 @pytest.mark.parametrize("observed_session_state", ["ready", "scanning"]) def test_public_physical_recovery_refreshes_stale_dhcp_then_classifies_without_writes( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, observed_session_state: str, ) -> None: original, _ = service_with_fake_runtime(tmp_path) stop_operation_id, compatibility_revision = ( _persist_resolved_unclassified_stop_for_restart(original) ) topology_store = original._semantic_topology_store # noqa: SLF001 assert topology_store is not None topology_store.commit( transport_ref="test-ble-transport", connection_mode="bridge", ipv4="192.168.68.52", compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, firmware_version="3.0.2", source="ble-read-only-status", observed_at_utc="2026-08-12T13:28:19.000Z", ) restarted, runtime = service_with_fake_runtime(tmp_path) association_probe = FakeHostWifiAssociationProbe("a" * 64) restarted._host_wifi_association_probe = association_probe # type: ignore[assignment] # noqa: SLF001 capture = _durable_status_capture(device_id="test-ble-transport") host_probes: list[str] = [] status_reads: list[tuple[str, bool, bool, float | None]] = [] command_edges: list[str] = [] def stale_host_probe( target: str, **_: object, ) -> facade_module._ConfiguredEndpointHostObservation: # noqa: SLF001 host_probes.append(target) return facade_module._ConfiguredEndpointHostObservation( # noqa: SLF001 path=_direct_host_path(target), reachable=False, reason_code="tcp-connection-timeout", ) async def read_current_dhcp_status( device_id: str, *, allow_known_device_retrieval: bool = False, rediscover: bool = False, exact_scan_timeout_seconds: float | None = None, on_gatt_validated: Callable[[object], None] | None = None, **_: object, ) -> dict[str, Any]: status_reads.append( ( device_id, allow_known_device_retrieval, rediscover, exact_scan_timeout_seconds, ) ) assert on_gatt_validated is not None on_gatt_validated(capture) return _wifi_status_read("192.168.68.51", device_id=device_id) async def forbidden_network_write(*_: object, **__: object) -> dict[str, Any]: command_edges.append("network-write") raise AssertionError("physical recovery must not write K1 network state") monkeypatch.setattr( facade_module, "_probe_configured_endpoint_host_only", stale_host_probe, ) monkeypatch.setattr(facade_module, "read_wifi_status_once", read_current_dhcp_status) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_network_write) monkeypatch.setattr(facade_module, "pin_connected_device_handle", lambda *_a, **_k: None) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) monkeypatch.setattr(facade_module, "_host_route_class", lambda _target: "direct-or-routed") monkeypatch.setattr(facade_module, "_control_endpoint_reachable", lambda _target: True) _install_real_coordinator_bootstrap( restarted, observed_session_state=observed_session_state, ) before = restarted.state() configured_recovery = before["connection_policy"]["actions"][ "observe-configured-device-network" ] assert configured_recovery["allowed"] is True assert configured_recovery["required_transport_ref"] == "test-ble-transport" assert configured_recovery["required_connection_mode"] == "bridge" assert configured_recovery["requires_live_gatt_validation"] is True verified = asyncio.run(restarted.verify_connection(ConnectionVerifyRequest())) after = restarted._physical_command_ledger.snapshot().record # noqa: SLF001 assert after is not None assert after.operation_id == stop_operation_id assert after.revision == compatibility_revision + 1 assert after.resolved_unclassified_stop_recovery_required is False assert after.reconciliations[-1].resolution == ( "physical-active-observed" if observed_session_state == "scanning" else "physical-standby-observed" ) assert host_probes == [] assert status_reads == [ ( "test-ble-transport", True, True, facade_module.CONNECTION_VERIFY_EXACT_UUID_SCAN_TIMEOUT_SECONDS, ) ] assert association_probe.timeout_seconds == [ facade_module.COMMAND_BOUND_ASSOCIATION_TIMEOUT_SECONDS, facade_module.COMMAND_BOUND_ASSOCIATION_TIMEOUT_SECONDS, ] assert command_edges == [] assert runtime.start_calls == [] assert runtime.stop_calls == 0 assert verified["k1_ip"] == "192.168.68.51" assert verified["semantic_topology_store"]["record"]["ipv4"] == "192.168.68.51" assert verified["last_operation"]["result"]["write_performed"] is False assert verified["last_operation"]["result"]["physical_reconciliation"][ "performed" ] is True def test_durable_restart_rejects_network_revision_race_before_commit_or_pin( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: operation_id = "durable-revision-race" first, _ = service_with_fake_runtime(tmp_path) _seed_unresolved_network_mutation( first, operation_id=operation_id, transport_ref=DURABLE_K1_UUID, ) restarted, _ = service_with_fake_runtime(tmp_path) captured = _durable_status_capture() pin_calls: list[tuple[object, str]] = [] async def read_while_revision_changes( device_id: str, *, on_gatt_validated: Callable[[object], None] | None = None, **_: object, ) -> dict[str, Any]: assert on_gatt_validated is not None on_gatt_validated(captured) current_ledger = restarted._network_mutation_ledger.snapshot() # noqa: SLF001 assert current_ledger.record is not None restarted._network_mutation_ledger.mark_observing( # noqa: SLF001 operation_id, expected_revision=current_ledger.record.revision, write_confirmed=False, observation=NetworkStatusEvidence( mode="WIFI_CLIENT", ipv4="192.168.68.50", status_code=1, reserved=0, ), ) return _wifi_status_read("192.168.68.50", device_id=device_id) monkeypatch.setattr(facade_module, "read_wifi_status_once", read_while_revision_changes) monkeypatch.setattr( facade_module, "provision_wifi_once", lambda *_args, **_kwargs: (_ for _ in ()).throw( AssertionError("revision race must not write") ), ) monkeypatch.setattr( facade_module, "pin_connected_device_handle", lambda handle, *, device_session_id: pin_calls.append((handle, device_session_id)), ) with pytest.raises(facade_module.ConnectionVerificationError) as raised: asyncio.run( restarted.verify_connection( ConnectionVerifyRequest( device_id=DURABLE_K1_UUID, source="durable-configured-state", compatibility_attestation=ATTESTATION, ) ) ) assert raised.value.reason_code == "connection-verify-candidate-not-fresh" assert pin_calls == [] state = restarted.state() assert state["network_mutation_ledger"]["status"] == "resolved" assert state["network_mutation_ledger"]["resolution"] == "interrupted" assert state["semantic_topology_store"]["status"] == "empty" assert state["selected_device_id"] is None assert state["device_session"] is None def test_provisioning_cannot_switch_device_during_active_acquisition( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_devices(service, [{"device_id": "k1-a"}]) service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) called = False async def should_not_run(*_: object, **__: object) -> dict[str, Any]: nonlocal called called = True raise AssertionError("provisioning boundary must not be reached") monkeypatch.setattr(facade_module, "provision_wifi_once", should_not_run) with pytest.raises(RuntimeError, match="активной acquisition-сессии"): asyncio.run( service.connect( _connect_request( device_id="k1-a", ssid="lab-network", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, ) ) ) assert called is False def test_sensor_catalog_exposes_two_browser_adapter_cameras_after_profile_attestation( tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) initial = service.state() initial_cameras = [ stream for stream in initial["sensor_catalog"]["streams"] if stream.get("semantic_channel_id") == "camera.preview.live" ] assert {stream["source_id"] for stream in initial_cameras} == { "sensor.camera.left", "sensor.camera.right", } assert all(stream["availability"] == "unverified" for stream in initial_cameras) state = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) cameras = [ stream for stream in state["sensor_catalog"]["streams"] if stream.get("semantic_channel_id") == "camera.preview.live" ] assert len(cameras) == 2 assert all(camera["availability"] == "available" for camera in cameras) assert all(camera["modality"] == "encoded-video" for camera in cameras) assert all(camera["decode_status"] == "rtsp-h264-observed-browser-remux" for camera in cameras) assert all(camera["activation"]["max_active"] == 1 for camera in cameras) assert all(camera["delivery"] is None for camera in cameras) assert state["connection_verification"]["network_reachability"] == "unknown" assert state["device_calibration"]["status"] == "unavailable" assert state["device_calibration"]["vehicle_extrinsics"] == ("host-domain-not-owned-by-plugin") def test_quick_to_bridge_requires_new_explicit_scan_instead_of_retained_session( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _seed_supervised_connection( service, target_ipv4=facade_module.AP_FALLBACK_IPV4, connection_mode="quick-connect", transport_ref="k1-a", logical_device_id="device-a", ) service._device_session_id = "quick-session-a" # noqa: SLF001 service._device_session_opened_at = "2026-08-06T12:00:00Z" # noqa: SLF001 supervisor_generation = service._connection_supervisor.snapshot().lease.generation # noqa: SLF001 service._connection_verification = { # noqa: SLF001 "status": "control-transport-lost", "lease_state": "disconnected", "lease_generation": supervisor_generation, "endpoint_validation": "terminal-mqtt-network-loop", "network_reachability": "unreachable", "reason_code": "connection_lease_control_transport_lost", "observed_at": "2026-08-06T12:01:00Z", } captured = facade_module.CapturedDiscoveredDevice( device=SimpleNamespace(address="k1-a"), # type: ignore[arg-type] macos_uuid="k1-a", owner_epoch=7, ) provision_calls: list[tuple[object | None, str | None]] = [] pin_calls: list[tuple[object, str]] = [] def recover(device_id: str, *, device_session_id: str) -> object | None: assert (device_id, device_session_id) == ("k1-a", "quick-session-a") return captured async def provision( *_args: object, captured_device: object | None = None, recovery_device_session_id: str | None = None, on_write_dispatch: Callable[[dict[str, Any], str], None] | None = None, **_kwargs: object, ) -> dict[str, Any]: provision_calls.append((captured_device, recovery_device_session_id)) _dispatch_test_network_write(on_write_dispatch) return { "started_at_utc": "2026-08-06T12:02:00Z", "completed_at_utc": "2026-08-06T12:02:01Z", "profile_id": "xgrids-k1-fw3-wifi-v1", "outcome": "lan_address_observed", "write_mode": "with_response", "baseline_status": {"mode": "WIFI_AP", "ipv4": "192.168.56.1"}, "observations": [{"status": _wifi_status_read("192.168.68.50")["status"]}], } monkeypatch.setattr(facade_module, "connected_device_capture", recover) monkeypatch.setattr( facade_module, "connected_device_recovery_snapshot", lambda *_args, **_kwargs: { "status": "retained", "scope": "owner-epoch-device-session", "advertised_now": False, "gatt_validated_recently": False, }, ) monkeypatch.setattr(facade_module, "provision_wifi_once", provision) monkeypatch.setattr( facade_module, "pin_connected_device_handle", lambda handle, *, device_session_id: pin_calls.append((handle, device_session_id)), ) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr(facade_module, "_host_route_class", lambda _target: "direct-or-routed") monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) monkeypatch.setattr( facade_module, "_control_endpoint_reachable", lambda _target: True, ) monkeypatch.setattr( facade_module, "_await_control_endpoint_reachable", _reachable_control_endpoint, ) with pytest.raises(facade_module.NetworkProvisioningConflict) as raised: asyncio.run( service.connect( _connect_request( device_id="k1-a", ssid="lab-router", password=SecretStr(PRIMARY_TEST_CREDENTIAL), connection_mode="bridge", compatibility_attestation=ATTESTATION, ) ) ) assert raised.value.reason_code == "network-provision-candidate-not-fresh" assert provision_calls == [] assert pin_calls == [] def test_quick_to_bridge_does_not_retrieve_old_handle_without_new_scan( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _seed_supervised_connection( service, target_ipv4=facade_module.AP_FALLBACK_IPV4, connection_mode="quick-connect", transport_ref="k1-a", logical_device_id="device-a", ) service._device_session_id = "quick-session-a" # noqa: SLF001 service._device_session_opened_at = "2026-08-06T12:00:00Z" # noqa: SLF001 captured = facade_module.CapturedDiscoveredDevice( device=SimpleNamespace(address="k1-a"), # type: ignore[arg-type] macos_uuid="k1-a", owner_epoch=7, source="retrieved-session", ) retained_lookups: list[tuple[str, str]] = [] provision_calls: list[tuple[object | None, str | None]] = [] def retained_lookup(device_id: str, *, device_session_id: str) -> object | None: retained_lookups.append((device_id, device_session_id)) # Facade obtains the exact validated object only after the low-level # operation resolved/retrieved it inside its BLE arbiter lease. return captured async def provision( *_args: object, captured_device: object | None = None, recovery_device_session_id: str | None = None, on_write_dispatch: Callable[[dict[str, Any], str], None] | None = None, **_kwargs: object, ) -> dict[str, Any]: provision_calls.append((captured_device, recovery_device_session_id)) _dispatch_test_network_write(on_write_dispatch) return { "started_at_utc": "2026-08-06T12:02:00Z", "completed_at_utc": "2026-08-06T12:02:01Z", "profile_id": "xgrids-k1-fw3-wifi-v1", "outcome": "lan_address_observed", "write_mode": "with_response", "baseline_status": {"mode": "WIFI_AP", "ipv4": "192.168.56.1"}, "observations": [{"status": _wifi_status_read("192.168.68.50")["status"]}], } monkeypatch.setattr(facade_module, "connected_device_capture", retained_lookup) monkeypatch.setattr( facade_module, "connected_device_recovery_snapshot", lambda *_args, **_kwargs: { "status": "retained", "scope": "owner-epoch-device-session", "advertised_now": False, "gatt_validated_recently": False, }, ) monkeypatch.setattr(facade_module, "provision_wifi_once", provision) monkeypatch.setattr(facade_module, "pin_connected_device_handle", lambda *_args, **_kw: None) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr(facade_module, "_host_route_class", lambda _target: "direct-or-routed") monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) monkeypatch.setattr(facade_module, "_control_endpoint_reachable", lambda _target: True) monkeypatch.setattr( facade_module, "_await_control_endpoint_reachable", _reachable_control_endpoint, ) with pytest.raises(facade_module.NetworkProvisioningConflict) as raised: asyncio.run( service.connect( _connect_request( device_id="k1-a", ssid="lab-router", password=SecretStr(PRIMARY_TEST_CREDENTIAL), connection_mode="bridge", compatibility_attestation=ATTESTATION, ) ) ) assert raised.value.reason_code == "network-provision-candidate-not-fresh" assert retained_lookups == [] assert provision_calls == [] def test_connection_policy_exposes_retained_recovery_without_inventing_presence( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) service._selected_device_id = "k1-a" # noqa: SLF001 service._connection_mode = "quick-connect" # noqa: SLF001 service._device_id = "device-a" # noqa: SLF001 service._device_session_id = "quick-session-a" # noqa: SLF001 service._device_session_opened_at = "2026-08-06T12:00:00Z" # noqa: SLF001 service._k1_ip = facade_module.AP_FALLBACK_IPV4 # noqa: SLF001 monkeypatch.setattr( facade_module, "connected_device_recovery_snapshot", lambda *_args, **_kwargs: { "status": "retained", "scope": "owner-epoch-device-session", "gatt_validated_recently": True, }, ) state = service.state() assert state["devices"] == [] assert state["current_device_recovery"]["handle_retained"] is True assert state["current_device_recovery"]["advertised_now"] is False policy = state["connection_policy"] assert policy["facts"]["retained_context_is_presence"] is False assert policy["actions"]["provision-fresh-device"]["allowed"] is False assert policy["actions"]["recover-current-device-network"] == { "allowed": True, "reason_codes": [], "target_source": "retained-current-process", "required_transport_ref": "k1-a", "requires_live_gatt_validation": True, "automatic_retry": False, } assert policy["recommended_action"] == "recover-current-device-network" def test_connection_policy_treats_open_durable_audit_as_nonblocking_context( tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service, device_id="k1-a") _seed_unresolved_network_mutation(service, transport_ref="k1-a") policy = service.state()["connection_policy"] assert policy["facts"]["physical_network_state"] == "unknown" assert policy["actions"]["provision-fresh-device"]["allowed"] is True assert policy["actions"]["recover-current-device-network"]["allowed"] is False assert policy["actions"]["observe-fresh-device-network"]["allowed"] is True assert policy["actions"]["observe-fresh-device-network"]["required_transport_ref"] == "k1-a" assert policy["recommended_action"] == "observe-fresh-device-network" def _project_connection_policy_for_test( service: XgridsK1CompatibilityService, *, idempotency: dict[str, object] | None = None, idempotency_available: bool = True, identity_pins: dict[str, object] | None = None, physical_command: dict[str, object] | None = None, ble_runtime: dict[str, object] | None = None, lifecycle_holders: tuple[str, ...] = (), current_device_recovery: dict[str, object] | None = None, acquisition_active: bool = False, acquisition_state: str | None = None, acquisition_cleanup_pending: bool = False, runtime_active: bool = False, application_control_session: dict[str, object] | None = None, ) -> dict[str, Any]: with service._lock: # noqa: SLF001 fresh_devices = service._fresh_ble_devices_locked() # noqa: SLF001 desired_connection_mode = service._desired_connection_mode # noqa: SLF001 configured_connection_mode = service._connection_mode # noqa: SLF001 supervisor = service._connection_supervisor.snapshot() # noqa: SLF001 active_connection_mode = ( configured_connection_mode if supervisor.authority.control_allowed else None ) return facade_module._connection_policy_projection( # noqa: SLF001 supervisor=supervisor, ledger=service._network_mutation_ledger.snapshot(), # noqa: SLF001 network_provisioning_idempotency=( idempotency if idempotency is not None else service._network_provisioning_idempotency_public_snapshot() # noqa: SLF001 ), network_provisioning_idempotency_available=idempotency_available, semantic_topology_store=service._semantic_topology_public_snapshot(), # noqa: SLF001 device_identity_pin_store=( identity_pins if identity_pins is not None else service._device_identity_pin_public_snapshot() # noqa: SLF001 ), physical_command=( physical_command if physical_command is not None else service._physical_command_coordinator.snapshot() # noqa: SLF001 ), ble_runtime=( ble_runtime if ble_runtime is not None else { "owner_epoch": 1, "owner_loop_bound": True, "active_operation_kind": None, "cleanup_pending": False, "poisoned": False, } ), lifecycle_process_lease_holders=lifecycle_holders, fresh_devices=fresh_devices, current_device_recovery=current_device_recovery, provisioning_active=False, acquisition_active=acquisition_active, acquisition_state=acquisition_state, acquisition_cleanup_pending=acquisition_cleanup_pending, runtime_active=runtime_active, application_control_session=( application_control_session if application_control_session is not None else {"state": "idle", "failure": None} ), desired_connection_mode=desired_connection_mode, active_connection_mode=active_connection_mode, ) @pytest.mark.parametrize( ("available", "status", "expected_reason"), [ (False, "corrupt", "network-provisioning-idempotency-unavailable"), (True, "corrupt", "network-provisioning-idempotency-corrupt"), ], ) def test_connection_policy_blocks_network_actions_when_idempotency_authority_is_untrusted( tmp_path: Path, available: bool, status: str, expected_reason: str, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service) policy = _project_connection_policy_for_test( service, idempotency={ "status": status, "revision": None, "reason_code": expected_reason, "active_operation_id": None, "active_action": None, "active_stage": None, "terminal_record_count": 0, "mutation_allowed": False, }, idempotency_available=available, ) assert policy["actions"]["provision-fresh-device"]["allowed"] is False assert expected_reason in policy["actions"]["provision-fresh-device"]["reason_codes"] assert policy["actions"]["observe-fresh-device-network"]["allowed"] is False assert expected_reason in policy["actions"]["observe-fresh-device-network"]["reason_codes"] assert policy["actions"]["scan-ble"]["allowed"] is True def test_connection_policy_blocks_cross_journal_mismatch_before_observation( tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service, device_id="k1-a") _seed_unresolved_network_mutation( service, transport_ref="k1-a", operation_id="network-ledger-operation", ) policy = _project_connection_policy_for_test( service, idempotency={ "status": "blocked", "revision": 3, "reason_code": "network-provisioning-idempotency-reconciliation-required", "active_operation_id": "different-idempotency-operation", "active_action": facade_module.ACTION_NETWORK_PROVISION, "active_stage": "unresolved", "terminal_record_count": 0, "mutation_allowed": False, }, ) decision = policy["actions"]["observe-fresh-device-network"] assert decision["allowed"] is False assert "network-provisioning-idempotency-operation-mismatch" in decision["reason_codes"] assert policy["facts"]["network_provisioning_active_operation_matches_ledger"] is False def test_connection_policy_blocks_identity_dependent_network_control_and_start( tmp_path: Path, ) -> None: verify_service, _ = service_with_fake_runtime(tmp_path / "verify") _set_scanned_k1(verify_service) _seed_supervised_connection(verify_service, with_control=False) corrupt_pins = { "schema_version": "missioncore.xgrids-k1-device-identity-pins/v1", "status": "corrupt", "revision": None, "pin_count": 0, "reason_code": "device-identity-pin-store-corrupt", } verify_policy = _project_connection_policy_for_test( verify_service, identity_pins=corrupt_pins, ) for action in ( "provision-fresh-device", "observe-fresh-device-network", "verify-control-device-info", ): assert verify_policy["actions"][action]["allowed"] is False assert ( "device-identity-pin-store-corrupt" in verify_policy["actions"][action]["reason_codes"] ) start_service, _ = service_with_fake_runtime(tmp_path / "start") _seed_supervised_connection(start_service) start_policy = _project_connection_policy_for_test( start_service, identity_pins=corrupt_pins, ) assert start_policy["actions"]["start-acquisition"]["allowed"] is False assert ( "device-identity-pin-store-corrupt" in start_policy["actions"]["start-acquisition"]["reason_codes"] ) def test_connection_policy_blocks_network_observation_when_topology_store_is_corrupt( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service) monkeypatch.setattr( service, "_semantic_topology_public_snapshot", lambda: { "schema_version": "missioncore.xgrids-k1-semantic-topology/v1", "status": "corrupt", "configured_offline_evidence": False, "live_connection_authority": False, "reason_code": "semantic-topology-store-corrupt", "record": None, }, ) policy = _project_connection_policy_for_test(service) assert policy["actions"]["observe-fresh-device-network"]["allowed"] is False assert ( "semantic-topology-store-corrupt" in policy["actions"]["observe-fresh-device-network"]["reason_codes"] ) @pytest.mark.parametrize( ("status", "expected_reason"), [ ("unresolved", "physical-command-reconciliation-required"), ("corrupt", "physical-command-ledger-corrupt"), ], ) def test_connection_policy_blocks_physical_start_and_stop_on_untrusted_ledger( tmp_path: Path, status: str, expected_reason: str, ) -> None: service, _ = service_with_fake_runtime(tmp_path) binding = _seed_supervised_connection(service) supervisor = service._connection_supervisor # noqa: SLF001 assert supervisor.observe_data_plane( intent_id=binding.intent_id, host_path_epoch=binding.host_path_epoch, state="healthy", session_id="data-session-a", ) physical_command = { "status": status, "reason_code": expected_reason, "requires_reconciliation": True, "automatic_replay_allowed": False, "normal_session_recovery_supported": False, "recovery_requirement": "explicit-read-only-reconciliation", "runtime_bound": False, "active_operation_id": None, "record": None, } policy = _project_connection_policy_for_test( service, physical_command=physical_command, ) for action in ("start-acquisition", "stop-acquisition"): assert policy["actions"][action]["allowed"] is False assert expected_reason in policy["actions"][action]["reason_codes"] def test_pending_reopened_physical_state_allows_only_read_only_recovery_or_retirement( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service, device_id="k1-a") physical = _pending_reopened_physical_snapshot() policy = _project_connection_policy_for_test( service, physical_command=physical, ) for action in ( "provision-fresh-device", "recover-current-device-network", "start-acquisition", "stop-acquisition", ): assert policy["actions"][action]["allowed"] is False assert ( "physical-command-reconciliation-required" in policy["actions"][action]["reason_codes"] ) read_only = policy["actions"]["observe-fresh-device-network"] assert read_only["allowed"] is True assert read_only["required_transport_ref"] == "k1-a" assert read_only["required_connection_mode"] == "bridge" # A scanning-shaped local snapshot is not STOP authority by itself. The # reopened durable row must remain fenced unless the exact adopted worker # explicitly exposes its STOP checkpoint. no_stop_checkpoint = _project_connection_policy_for_test( service, physical_command=physical, application_control_session={ "state": "scanning", "can_stop": False, "failure": None, }, ) assert no_stop_checkpoint["actions"]["stop-acquisition"]["allowed"] is False assert ( "physical-command-reconciliation-required" in no_stop_checkpoint["actions"]["stop-acquisition"]["reason_codes"] ) monkeypatch.setattr( service._physical_command_coordinator, # noqa: SLF001 "snapshot", lambda: physical, ) retirement = service._physical_operator_retirement_projection() # noqa: SLF001 assert retirement["allowed"] is True assert retirement["reason_codes"] == [] @pytest.mark.parametrize( ("ble_snapshot", "expected_reason"), [ ( { "owner_epoch": 4, "owner_loop_bound": False, "active_operation_kind": "scan", "cleanup_pending": True, "poisoned": False, }, "ble-runtime-cleanup-pending", ), ( { "owner_epoch": 5, "owner_loop_bound": False, "active_operation_kind": "status-read", "cleanup_pending": True, "poisoned": True, }, "ble-runtime-restart-required", ), ], ) def test_connection_policy_blocks_control_and_physical_edges_on_ble_quarantine( tmp_path: Path, ble_snapshot: dict[str, object], expected_reason: str, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _seed_supervised_connection(service) policy = _project_connection_policy_for_test( service, ble_runtime=ble_snapshot, ) assert policy["actions"]["start-acquisition"]["allowed"] is False assert expected_reason in policy["actions"]["start-acquisition"]["reason_codes"] def test_state_projects_ble_runtime_quarantine_into_composite_policy( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) poisoned = { "owner_epoch": 8, "owner_loop_bound": False, "active_operation_kind": "status-read", "cleanup_pending": True, "poisoned": True, } monkeypatch.setattr(facade_module, "ble_runtime_snapshot", lambda: poisoned) state = service.state() assert state["ble_runtime"] == poisoned assert state["connection_policy"]["facts"]["ble_runtime"] == { "active_operation_kind": "status-read", "cleanup_pending": True, "poisoned": True, } assert ( "ble-runtime-restart-required" in state["connection_policy"]["actions"]["scan-ble"]["reason_codes"] ) def test_connection_policy_blocks_physical_edges_while_network_owns_process_lease( tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) binding = _seed_supervised_connection(service) assert service._connection_supervisor.observe_data_plane( # noqa: SLF001 intent_id=binding.intent_id, host_path_epoch=binding.host_path_epoch, state="healthy", session_id="data-session-a", ) policy = _project_connection_policy_for_test( service, lifecycle_holders=("network",), ) for action in ("start-acquisition", "stop-acquisition"): assert policy["actions"][action]["allowed"] is False assert ( "k1-lifecycle-process-lease-network-owned" in policy["actions"][action]["reason_codes"] ) def test_connection_policy_keeps_host_tcp_probe_independent_of_other_failures( tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _seed_supervised_connection( service, with_control=False, endpoint_reachable=False, ) policy = _project_connection_policy_for_test( service, idempotency={ "status": "corrupt", "active_operation_id": None, }, idempotency_available=False, identity_pins={"status": "corrupt"}, physical_command={ "status": "corrupt", "requires_reconciliation": True, }, ble_runtime={ "owner_epoch": 9, "owner_loop_bound": False, "active_operation_kind": "scan", "cleanup_pending": True, "poisoned": True, }, lifecycle_holders=("network",), ) assert policy["actions"]["probe-endpoint"]["allowed"] is True assert policy["actions"]["verify-control-device-info"]["allowed"] is False assert policy["actions"]["start-acquisition"]["allowed"] is False def test_connection_policy_data_loss_preserves_exact_stop_and_falls_back_to_local_only( tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) binding = _seed_supervised_connection(service) supervisor = service._connection_supervisor # noqa: SLF001 assert supervisor.observe_data_plane( intent_id=binding.intent_id, host_path_epoch=binding.host_path_epoch, state="healthy", session_id="data-session-a", ) assert supervisor.observe_data_plane( intent_id=binding.intent_id, host_path_epoch=binding.host_path_epoch, state="lost", session_id="data-session-a", reason_code="test-data-loss", ) healthy_control = _project_connection_policy_for_test( service, acquisition_active=True, runtime_active=True, ) assert healthy_control["actions"]["acknowledge-data-loss"]["allowed"] is False assert healthy_control["actions"]["stop-acquisition"]["allowed"] is True assert healthy_control["actions"]["stop-local-receiver"]["allowed"] is True assert healthy_control["actions"]["stop-local-receiver"]["physical_command_allowed"] is False assert healthy_control["actions"]["stop-local-receiver"]["physical_outcome"] == ("unknown") assert healthy_control["recommended_action"] == "stop-acquisition" assert supervisor.observe_control_loss( intent_id=binding.intent_id, host_path_epoch=binding.host_path_epoch, control_session_id="test-control-test-ble-transport", reason_code="test-control-loss", ) control_lost = _project_connection_policy_for_test( service, acquisition_active=True, runtime_active=True, ) assert control_lost["actions"]["stop-acquisition"]["allowed"] is False assert ( "physical-control-authority-unavailable" in control_lost["actions"]["stop-acquisition"]["reason_codes"] ) assert control_lost["actions"]["stop-local-receiver"]["allowed"] is True assert control_lost["actions"]["stop-local-receiver"]["execution_mode"] == ("capture-only") assert control_lost["actions"]["stop-local-receiver"]["physical_command_allowed"] is False assert control_lost["recommended_action"] == "stop-local-receiver" @pytest.mark.parametrize( ("acquisition_active", "cleanup_pending", "runtime_active", "expected_allowed"), [ (True, False, False, True), (False, True, False, True), (False, False, True, True), (False, False, False, False), ], ) def test_connection_policy_local_receiver_cleanup_uses_independent_local_liveness( tmp_path: Path, acquisition_active: bool, cleanup_pending: bool, runtime_active: bool, expected_allowed: bool, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _seed_supervised_connection(service) policy = _project_connection_policy_for_test( service, acquisition_active=acquisition_active, acquisition_cleanup_pending=cleanup_pending, runtime_active=runtime_active, ) local_cleanup = policy["actions"]["stop-local-receiver"] assert local_cleanup["allowed"] is expected_allowed assert local_cleanup["execution_mode"] == "capture-only" assert local_cleanup["physical_command_allowed"] is False assert local_cleanup["physical_outcome"] == "unknown" if expected_allowed: assert local_cleanup["reason_codes"] == [] else: assert local_cleanup["reason_codes"] == ["local-acquisition-receiver-not-active"] # Local cleanup eligibility never broadens the separately gated physical STOP. assert policy["actions"]["stop-acquisition"]["allowed"] is False def test_connection_policy_current_target_allows_host_probe_not_ble_refresh( tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) binding = _seed_supervised_connection(service) assert service._connection_supervisor.observe_control_loss( # noqa: SLF001 intent_id=binding.intent_id, host_path_epoch=binding.host_path_epoch, control_session_id="test-control-test-ble-transport", reason_code="test-control-loss", ) policy = _project_connection_policy_for_test( service, current_device_recovery=None, ) assert service._connection_supervisor.snapshot().last_known is not None # noqa: SLF001 assert policy["actions"]["inspect-configured-endpoint"]["allowed"] is True assert ( policy["actions"]["inspect-configured-endpoint"]["requires_live_gatt_validation"] is False ) assert policy["actions"]["inspect-configured-endpoint"]["target_source"] == ( "configured-topology" ) assert policy["actions"]["inspect-configured-endpoint"]["required_transport_ref"] is None assert policy["actions"]["observe-fresh-device-network"]["allowed"] is False assert ( "fresh-ble-candidate-required" in policy["actions"]["observe-fresh-device-network"]["reason_codes"] ) def test_configured_endpoint_probe_uses_durable_topology_after_restart_without_ble( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: first, _ = service_with_fake_runtime(tmp_path) topology_store = first._semantic_topology_store # noqa: SLF001 assert topology_store is not None topology_store.commit( transport_ref="durable-k1-transport", connection_mode="bridge", ipv4="192.168.1.20", compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, firmware_version="3.0.2", source="ble-read-only-status", observed_at_utc="2026-08-06T12:00:00Z", ) restarted, _ = service_with_fake_runtime(tmp_path) ble_calls: list[str] = [] async def forbidden_ble(*_: object, **__: object) -> dict[str, Any]: ble_calls.append("ble") raise AssertionError("configured endpoint probe must not enter BLE") def forbidden_ble_lease(*_: object, **__: object) -> object: ble_calls.append("ble-lease") raise AssertionError("configured endpoint probe must not borrow the BLE lease") def forbidden_authoritative_probe(*_: object, **__: object) -> object: raise AssertionError("configured endpoint probe must not update the supervisor") monkeypatch.setattr(facade_module, "read_wifi_status_once", forbidden_ble) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_ble) monkeypatch.setattr( facade_module, "borrow_ble_runtime_process_lease", forbidden_ble_lease, ) monkeypatch.setattr(restarted, "_probe_control_endpoint", forbidden_authoritative_probe) monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) monkeypatch.setattr( facade_module, "_probe_control_endpoint_socket", lambda target: facade_module.TcpReachabilityProbeResult( reachable=target == "192.168.1.20", reason_code=(None if target == "192.168.1.20" else "tcp-endpoint-unreachable"), ), ) before = restarted.state() assert before["selected_device_id"] is None assert before["connection_policy"]["actions"]["inspect-configured-endpoint"]["allowed"] is True assert ( before["connection_policy"]["actions"]["inspect-configured-endpoint"]["target_source"] == "configured-topology" ) assert ( before["connection_policy"]["actions"]["inspect-configured-endpoint"][ "required_transport_ref" ] is None ) assert ( before["connection_policy"]["actions"]["observe-fresh-device-network"]["allowed"] is False ) state = asyncio.run( restarted.probe_configured_endpoint( ConfiguredEndpointProbeRequest( operation_id="op-00000000-0000-4000-8000-000000000651", ) ) ) assert ble_calls == [] assert state["selected_device_id"] is None assert state["connection_verification"]["status"] == "not-probed" assert state["configured_endpoint_probe"] == { "schema_version": "missioncore.xgrids-k1-configured-endpoint-probe/v1", "status": "reachable", "target_source": "durable-semantic-topology", "connection_mode": "bridge", "endpoint": "192.168.1.20", "transport_ref": "durable-k1-transport", "intent_id": None, "semantic_revision": 1, "host_route_available": True, "host_route_class": "direct", "tcp_reachable": True, "identity_validation": "not-performed", "control_authority_granted": False, "ble_operation_performed": False, "network_mutation_performed": False, "automatic_retry": False, "observed_at": state["configured_endpoint_probe"]["observed_at"], "reason_code": None, } assert state["connection_supervisor"]["authority"]["control_allowed"] is False assert state["last_operation"]["action"] == "connection.endpoint-probe" assert state["last_operation"]["status"] == "succeeded" assert state["last_operation"]["result"]["identity_validation"] == "not-performed" assert state["last_operation"]["result"]["network_mutation_performed"] is False def test_configured_endpoint_probe_reports_unreachable_without_promoting_authority( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) topology_store = service._semantic_topology_store # noqa: SLF001 assert topology_store is not None topology_store.commit( transport_ref="durable-k1-transport", connection_mode="quick-connect", ipv4="192.168.56.1", compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, firmware_version="3.0.2", source="ble-read-only-status", observed_at_utc="2026-08-06T12:00:00Z", ) monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) monkeypatch.setattr( facade_module, "_probe_control_endpoint_socket", lambda _target: facade_module.TcpReachabilityProbeResult( reachable=False, reason_code="tcp-endpoint-unreachable", ), ) state = asyncio.run(service.probe_configured_endpoint()) probe = state["configured_endpoint_probe"] assert probe["status"] == "endpoint-unreachable" assert probe["host_route_available"] is True assert probe["tcp_reachable"] is False assert probe["reason_code"] == "tcp-endpoint-unreachable" assert probe["control_authority_granted"] is False assert state["connection_supervisor"]["authority"]["control_allowed"] is False def test_configured_endpoint_probe_prefers_current_supervisor_target( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) topology_store = service._semantic_topology_store # noqa: SLF001 assert topology_store is not None topology_store.commit( transport_ref="older-durable-transport", connection_mode="bridge", ipv4="192.168.1.99", compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, firmware_version="3.0.2", source="ble-read-only-status", observed_at_utc="2026-08-06T12:00:00Z", ) _seed_supervised_connection( service, target_ipv4="192.168.1.20", with_control=False, ) probed_targets: list[str] = [] monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) monkeypatch.setattr( facade_module, "_probe_control_endpoint_socket", lambda target: ( probed_targets.append(target) or facade_module.TcpReachabilityProbeResult(reachable=True) ), ) state = asyncio.run(service.probe_configured_endpoint()) assert probed_targets == ["192.168.1.20"] assert state["configured_endpoint_probe"]["target_source"] == "current-supervisor" assert state["configured_endpoint_probe"]["endpoint"] == "192.168.1.20" assert state["configured_endpoint_probe"]["transport_ref"] == "test-ble-transport" assert state["configured_endpoint_probe"]["intent_id"] is not None assert state["configured_endpoint_probe"]["semantic_revision"] is None assert state["configured_endpoint_probe"]["identity_validation"] == "not-performed" def test_configured_endpoint_probe_requires_current_or_durable_target( tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) with pytest.raises( facade_module.ConfiguredEndpointProbeError, match="Нет сохранённого endpoint", ) as raised: asyncio.run(service.probe_configured_endpoint()) assert raised.value.reason_code == "configured-endpoint-unavailable" operation = service.state()["last_operation"] assert operation["action"] == "connection.endpoint-probe" assert operation["status"] == "failed" assert operation["error"]["side_effect_status"] == "none" assert operation["error"]["safe_to_retry"] is True def test_configured_endpoint_probe_maps_untrusted_store_to_action_scoped_error( tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) service._semantic_topology_store = None # noqa: SLF001 with pytest.raises(facade_module.ConfiguredEndpointProbeError) as raised: asyncio.run(service.probe_configured_endpoint()) assert raised.value.reason_code == "configured-endpoint-topology-corrupt" operation = service.state()["last_operation"] assert operation["action"] == "connection.endpoint-probe" assert operation["status"] == "failed" assert operation["error"]["side_effect_status"] == "none" @pytest.mark.parametrize( ( "previous_mode", "previous_session_id", "previous_ipv4", "requested_mode", "requested_ssid", "requested_password", "requested_attestation", ), [ pytest.param( "quick-connect", "quick-session-a", facade_module.AP_FALLBACK_IPV4, "bridge", "lab-router", SecretStr(PRIMARY_TEST_CREDENTIAL), ATTESTATION, id="quick-to-bridge", ), pytest.param( "bridge", "bridge-session-a", "192.168.68.50", "quick-connect", None, None, QUICK_CONNECT_ATTESTATION, id="bridge-to-quick-connect", ), ], ) def test_fresh_cross_mode_prewrite_failure_leaves_clean_unselected_state( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, previous_mode: str, previous_session_id: str, previous_ipv4: str, requested_mode: str, requested_ssid: str | None, requested_password: SecretStr | None, requested_attestation: CompatibilityAttestationRequest, ) -> None: service, _ = service_with_fake_runtime(tmp_path) service._selected_device_id = "k1-a" # noqa: SLF001 service._connection_mode = previous_mode # type: ignore[assignment] # noqa: SLF001 service._device_id = "device-a" # noqa: SLF001 service._device_session_id = previous_session_id # noqa: SLF001 service._device_session_opened_at = "2026-08-06T12:00:00Z" # noqa: SLF001 service._device_session_discovery_generation = 0 # noqa: SLF001 service._k1_ip = previous_ipv4 # noqa: SLF001 mode_revision = _select_connection_mode(service, requested_mode) service._ble_discovery_generation += 1 # noqa: SLF001 _set_scanned_k1(service, device_id="k1-a") captured = facade_module.CapturedDiscoveredDevice( device=SimpleNamespace(address="k1-a"), # type: ignore[arg-type] macos_uuid="k1-a", owner_epoch=7, scan_generation=service._ble_discovery_generation, # noqa: SLF001 ) prewrite_attempts: list[tuple[str, object | None]] = [] def prewrite_failure(captured_device: object | None) -> RuntimeError: prewrite_attempts.append((requested_mode, captured_device)) error = RuntimeError("powered off after fresh advertisement") error.operation_stage = "connect" # type: ignore[attr-defined] error.device_write_attempted = False # type: ignore[attr-defined] error.device_write_confirmed = False # type: ignore[attr-defined] return error async def bridge_powered_off_before_write( *_args: object, captured_device: object | None = None, **_kwargs: object, ) -> dict[str, Any]: raise prewrite_failure(captured_device) @asynccontextmanager async def quick_powered_off_before_write( *_args: object, captured_device: object | None = None, **_kwargs: object, ) -> AsyncIterator[dict[str, Any]]: raise prewrite_failure(captured_device) yield {} monkeypatch.setattr( facade_module, "_capture_network_intent_device", lambda _device_id: captured, ) monkeypatch.setattr( facade_module, "connected_device_capture", lambda *_args, **_kwargs: None, ) if requested_mode == "quick-connect": monkeypatch.setattr( facade_module, "ensure_wifi_profile_from_credential_source", lambda *_args, **_kwargs: { "schema_version": 1, "adapter": "macOS Keychain", "available": True, "profile_enrolled": True, "credential_source": "exact-firmware-profile", }, ) monkeypatch.setattr( facade_module, "device_ap_activation_session", quick_powered_off_before_write, ) monkeypatch.setattr( facade_module, "provision_wifi_once", lambda *_args, **_kwargs: (_ for _ in ()).throw( AssertionError("Quick Connect must not use the Bridge provisioning write") ), ) else: monkeypatch.setattr( facade_module, "provision_wifi_once", bridge_powered_off_before_write, ) monkeypatch.setattr( facade_module, "device_ap_activation_session", lambda *_args, **_kwargs: (_ for _ in ()).throw( AssertionError("Bridge must not use the Quick Connect AP write") ), ) monkeypatch.setattr( facade_module, "pin_connected_device_handle", lambda *_args, **_kwargs: (_ for _ in ()).throw( AssertionError("a failed pre-write recovery must not promote a new session") ), ) with pytest.raises(RuntimeError, match="powered off after fresh advertisement"): asyncio.run( service.connect( _connect_request( device_id="k1-a", ssid=requested_ssid, password=requested_password, connection_mode=requested_mode, compatibility_attestation=requested_attestation, expected_mode_revision=mode_revision, expected_discovery_generation=( service._ble_discovery_generation # noqa: SLF001 ), ) ) ) assert prewrite_attempts == [(requested_mode, captured)] assert service._selected_device_id is None # noqa: SLF001 assert service._connection_mode is None # noqa: SLF001 assert service._device_id == "device-a" # noqa: SLF001 assert service._device_session_id is None # noqa: SLF001 assert service._k1_ip is None # noqa: SLF001 state = service.state() assert state["current_device_recovery"] is None operation = next(item for item in state["operations"] if item["action"] == "network.provision") assert operation["error"]["safe_to_retry"] is True assert operation["error"]["side_effect_status"] == "none" assert operation["error"]["operation_stage"] == "connect" assert state["network_mutation_ledger"]["status"] == "empty" assert state["connection_policy"]["actions"]["provision-fresh-device"]["allowed"] is True def test_same_uuid_rediscovery_is_candidate_only_and_never_resurrects_session( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) service._selected_device_id = "k1-a" # noqa: SLF001 service._connection_mode = "bridge" # noqa: SLF001 service._device_id = "device-a" # noqa: SLF001 service._device_session_id = "ended-session-a" # noqa: SLF001 service._device_session_opened_at = "2026-08-06T12:00:00Z" # noqa: SLF001 service._device_session_discovery_generation = 0 # noqa: SLF001 service._k1_ip = "192.168.68.50" # noqa: SLF001 invalidations: list[tuple[str, str]] = [] monkeypatch.setattr( facade_module, "invalidate_connected_device_session", lambda device_id, *, device_session_id: ( invalidations.append((device_id, device_session_id)) or True ), ) service._retire_ephemeral_device_binding_for_new_intent() # noqa: SLF001 assert invalidations == [("k1-a", "ended-session-a")] discovery_calls: list[float] = [] gatt_or_session_edges: list[str] = [] async def rediscover_same_uuid( duration_seconds: float, *, on_admitted: Callable[[], None] | None = None, ) -> dict[str, Any]: discovery_calls.append(duration_seconds) assert on_admitted is not None on_admitted() return _ble_scan_result("k1-a") def forbidden_edge(*_args: object, **_kwargs: object) -> None: gatt_or_session_edges.append("unexpected") raise AssertionError("rediscovery must remain candidate-only until explicit Connect") monkeypatch.setattr(facade_module, "scan", rediscover_same_uuid) monkeypatch.setattr(facade_module, "_capture_network_intent_device", forbidden_edge) monkeypatch.setattr(facade_module, "connected_device_capture", forbidden_edge) monkeypatch.setattr(facade_module, "pin_connected_device_handle", forbidden_edge) monkeypatch.setattr(facade_module, "read_wifi_status_once", forbidden_edge) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_edge) monkeypatch.setattr(facade_module, "device_ap_activation_session", forbidden_edge) rediscovered = asyncio.run(service.scan_ble(BleScanRequest(duration_seconds=1.0))) assert discovery_calls == [1.0] assert gatt_or_session_edges == [] assert rediscovered["devices"] == [ { "device_id": "k1-a", "name": "XGR-K1", "rssi": -44, "address": None, "connectable": None, "likely_k1": True, } ] assert rediscovered["selected_device_id"] is None assert rediscovered["ble_discovery_generation"] == 1 assert rediscovered["device_session"] is None assert rediscovered["current_device_recovery"] is None assert rediscovered["connection_mode"] is None assert rediscovered["k1_ip"] is None assert rediscovered["connection_policy"]["actions"]["provision-fresh-device"]["allowed"] is True def test_quick_to_bridge_recovery_rejects_nonterminal_control_before_retirement( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) service._selected_device_id = "k1-a" # noqa: SLF001 service._connection_mode = "quick-connect" # noqa: SLF001 service._device_session_id = "quick-session-a" # noqa: SLF001 service._k1_ip = facade_module.AP_FALLBACK_IPV4 # noqa: SLF001 _set_scanned_k1(service, device_id="k1-a") captured = facade_module.CapturedDiscoveredDevice( device=SimpleNamespace(address="k1-a"), # type: ignore[arg-type] macos_uuid="k1-a", owner_epoch=7, ) class BusyControlSession: def snapshot(self) -> dict[str, object]: return {"state": "scanning", "failure": None} def retire_for_network_change(self, **_: object) -> dict[str, object]: raise AssertionError("recovery admission must fail before retirement") service._application_control_session = BusyControlSession() # type: ignore[assignment] # noqa: SLF001 monkeypatch.setattr( facade_module, "_capture_network_intent_device", lambda *_args, **_kwargs: captured, ) monkeypatch.setattr( facade_module, "connected_device_capture", lambda *_args, **_kwargs: captured, ) monkeypatch.setattr( facade_module, "connected_device_recovery_snapshot", lambda *_args, **_kwargs: { "status": "retained", "scope": "owner-epoch-device-session", "advertised_now": False, "gatt_validated_recently": False, }, ) monkeypatch.setattr( facade_module, "provision_wifi_once", lambda *_args, **_kwargs: (_ for _ in ()).throw( AssertionError("rejected recovery must not reach BLE") ), ) with pytest.raises(facade_module.NetworkProvisioningConflict) as raised: asyncio.run( service.connect( _connect_request( device_id="k1-a", ssid="lab-router", password=SecretStr(PRIMARY_TEST_CREDENTIAL), connection_mode="bridge", compatibility_attestation=ATTESTATION, ) ) ) assert raised.value.reason_code == "network-provision-recovery-control-not-admissible" assert service._connection_mode == "quick-connect" # noqa: SLF001 assert service._device_session_id == "quick-session-a" # noqa: SLF001 @pytest.mark.parametrize( "failure_reason", ["mqtt_network_loop_failed", "application-connection-binding-lost"], ) def test_terminal_control_loss_retires_ephemeral_device_session_without_retry( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, failure_reason: str, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _seed_supervised_connection( service, target_ipv4=facade_module.AP_FALLBACK_IPV4, connection_mode="quick-connect", transport_ref="k1-a", logical_device_id="device-a", ) service._device_session_id = "quick-session-a" # noqa: SLF001 service._device_session_opened_at = "2026-08-06T12:00:00Z" # noqa: SLF001 supervisor_generation = service._connection_supervisor.snapshot().lease.generation # noqa: SLF001 service._connection_verification = { # noqa: SLF001 "status": "reachable", "lease_state": "reachable", "lease_generation": supervisor_generation, "endpoint_validation": "provisioning-status+mqtt-tcp-connect", "network_reachability": "reachable", "write_performed": True, "observed_at": "2026-08-06T12:00:00Z", } class FailedControlSession: retire_calls = 0 retired = False def snapshot(self) -> dict[str, object]: if self.retired: return {"state": "idle", "can_open": True, "failure": None} return { "state": "failed", "failure": { "reason_code": failure_reason, "failed_phase": "maintain-open", }, } def retire_for_network_change(self, **_: object) -> dict[str, object]: self.retire_calls += 1 if self.retire_calls == 1: raise RuntimeError("control worker is still retiring") self.retired = True return {"state": "idle", "can_open": True} service._application_control_session = FailedControlSession() # type: ignore[assignment] # noqa: SLF001 invalidations: list[bool] = [] monkeypatch.setattr( facade_module, "invalidate_connected_device_session", lambda *_args, **_kwargs: invalidations.append(True) or True, ) state = service.state() assert invalidations == [True] assert state["k1_ip"] is None assert state["connection_mode"] is None assert state["device_session"] is None assert state["current_device_recovery"] is None assert service._selected_device_id is None # noqa: SLF001 assert state["connection_supervisor"]["authority"]["control_allowed"] is False assert state["connection_supervisor"]["authority"]["acquisition_start_allowed"] is False _set_scanned_k1(service, device_id="k1-a") fresh = service.state() assert service._application_control_session.retire_calls == 2 # type: ignore[attr-defined] # noqa: SLF001 assert fresh["connection_policy"]["actions"]["provision-fresh-device"]["allowed"] is True def test_configured_unverified_endpoint_loss_retires_ephemeral_session( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _seed_supervised_connection( service, target_ipv4="192.168.68.50", connection_mode="bridge", transport_ref="k1-a", logical_device_id="device-a", with_control=False, ) assert service._connection_supervisor.snapshot().last_known is None # noqa: SLF001 invalidations: list[bool] = [] monkeypatch.setattr( facade_module, "invalidate_connected_device_session", lambda *_args, **_kwargs: invalidations.append(True) or True, ) supervisor = service._connection_supervisor # noqa: SLF001 snapshot = supervisor.snapshot() assert snapshot.intent is not None assert snapshot.endpoint.target is not None for attempt in range(3): accepted = supervisor.observe_endpoint( target=snapshot.endpoint.target, intent_id=snapshot.intent.intent_id, host_path_epoch=snapshot.host_path.epoch, reachable=False, reason_code="k1-control-port-unreachable", ) assert accepted is True state = service.state() if attempt < 2: assert state["device_session"] is not None assert invalidations == [True] assert state["device_session"] is None assert state["connection_mode"] is None assert state["k1_ip"] is None _set_scanned_k1(service, device_id="k1-a") fresh = service.state() assert fresh["connection_policy"]["actions"]["provision-fresh-device"]["allowed"] is True def test_endpoint_loss_preserves_same_generation_fresh_candidate_for_reprovision( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _seed_supervised_connection( service, target_ipv4="192.168.68.50", connection_mode="bridge", transport_ref="k1-a", logical_device_id="device-a", with_control=False, ) _set_scanned_k1(service, device_id="k1-a") discovery_generation = service._ble_discovery_generation # noqa: SLF001 invalidations: list[tuple[str, str]] = [] monkeypatch.setattr( facade_module, "invalidate_connected_device_session", lambda device_id, *, device_session_id: ( invalidations.append((device_id, device_session_id)) or True ), ) supervisor = service._connection_supervisor # noqa: SLF001 snapshot = supervisor.snapshot() assert snapshot.intent is not None assert snapshot.endpoint.target is not None for _ in range(3): accepted = supervisor.observe_endpoint( target=snapshot.endpoint.target, intent_id=snapshot.intent.intent_id, host_path_epoch=snapshot.host_path.epoch, reachable=False, reason_code="k1-control-port-unreachable", ) assert accepted is True state = service.state() assert invalidations == [("k1-a", "test-session-k1-a")] assert state["device_session"] is None assert state["selected_device_id"] is None assert state["k1_ip"] is None assert service._ble_discovery_generation == discovery_generation # noqa: SLF001 assert [item["device_id"] for item in state["devices"]] == ["k1-a"] assert state["connection_policy"]["actions"]["provision-fresh-device"]["allowed"] is True assert "свежий Bluetooth-кандидат можно настроить заново" in state["message"] def test_three_proven_host_path_losses_retire_session_and_require_new_scan( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _seed_supervised_connection( service, target_ipv4="192.168.68.50", connection_mode="bridge", transport_ref="k1-a", logical_device_id="device-a", ) invalidations: list[bool] = [] monkeypatch.setattr( facade_module, "invalidate_connected_device_session", lambda *_args, **_kwargs: invalidations.append(True) or True, ) lost_path = HostPathProbeResult( available=False, fingerprint=None, interface=None, source_ipv4=None, route_class="unavailable", reason_code="router-link-lost", ) service._connection_supervisor.observe_host_path(lost_path) # noqa: SLF001 first = service.state() assert first["device_session"] is not None assert first["connection_mode"] == "bridge" assert invalidations == [] # Unrelated supervisor revisions must not count as additional host-path # failures while the same negative observation remains current. supervisor = service._connection_supervisor # noqa: SLF001 current_intent = supervisor.snapshot().intent assert current_intent is not None for _ in range(2): supervisor.set_intent( intent_id=current_intent.intent_id, requested_mode=current_intent.requested_mode, expected_device_id=current_intent.expected_device_id, ) unchanged = service.state() assert unchanged["device_session"] is not None assert invalidations == [] service._connection_supervisor.observe_host_path(lost_path) # noqa: SLF001 second = service.state() assert second["device_session"] is not None assert invalidations == [] service._connection_supervisor.observe_host_path(lost_path) # noqa: SLF001 third = service.state() assert invalidations == [True] assert third["device_session"] is None assert third["connection_mode"] is None assert third["k1_ip"] is None assert service._selected_device_id is None # noqa: SLF001 assert service._connection_monitor_target() is None # noqa: SLF001 assert third["connection_policy"]["actions"]["provision-fresh-device"]["allowed"] is False _set_scanned_k1(service, device_id="k1-a") fresh = service.state() assert fresh["connection_policy"]["actions"]["provision-fresh-device"]["allowed"] is True @pytest.mark.parametrize("plane", ["host", "endpoint"]) def test_positive_transport_edge_resets_loss_streak_between_state_polls( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, plane: str, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _seed_supervised_connection( service, target_ipv4="192.168.68.50", connection_mode="bridge", transport_ref="k1-a", logical_device_id="device-a", with_control=False, ) invalidations: list[bool] = [] monkeypatch.setattr( facade_module, "invalidate_connected_device_session", lambda *_args, **_kwargs: invalidations.append(True) or True, ) supervisor = service._connection_supervisor # noqa: SLF001 def observe(reachable: bool) -> None: snapshot = supervisor.snapshot() assert snapshot.intent is not None assert snapshot.device_network.target is not None if plane == "host": supervisor.observe_host_path( _direct_host_path("192.168.68.50") if reachable else HostPathProbeResult( available=False, fingerprint=None, interface=None, source_ipv4=None, route_class="unavailable", reason_code="router-link-lost", ) ) else: accepted = supervisor.observe_endpoint( target=snapshot.device_network.target, intent_id=snapshot.intent.intent_id, host_path_epoch=snapshot.host_path.epoch, reachable=reachable, reason_code=None if reachable else "k1-control-port-unreachable", ) assert accepted is True observe(False) assert service.state()["device_session"] is not None observe(True) # The UI does not poll state() on this recovery edge. observe(False) assert service.state()["device_session"] is not None observe(False) assert service.state()["device_session"] is not None assert invalidations == [] observe(False) assert service.state()["device_session"] is None assert invalidations == [True] @pytest.mark.parametrize("plane", ["host", "endpoint"]) def test_positive_edge_between_loss_confirmation_and_teardown_cancels_retirement( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, plane: str, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _seed_supervised_connection( service, target_ipv4="192.168.68.50", connection_mode="bridge", transport_ref="k1-a", logical_device_id="device-a", with_control=False, ) supervisor = service._connection_supervisor # noqa: SLF001 def observe(reachable: bool) -> None: snapshot = supervisor.snapshot() assert snapshot.intent is not None assert snapshot.device_network.target is not None if plane == "host": supervisor.observe_host_path( _direct_host_path("192.168.68.50") if reachable else HostPathProbeResult( available=False, fingerprint=None, interface=None, source_ipv4=None, route_class="unavailable", reason_code="router-link-lost", ) ) else: accepted = supervisor.observe_endpoint( target=snapshot.device_network.target, intent_id=snapshot.intent.intent_id, host_path_epoch=snapshot.host_path.epoch, reachable=reachable, reason_code=None if reachable else "k1-control-port-unreachable", ) assert accepted is True for _ in range(3): observe(False) original_snapshot = supervisor.snapshot snapshot_calls = 0 def snapshot_with_recovery_edge() -> Any: nonlocal snapshot_calls snapshot_calls += 1 if snapshot_calls == 2: before_recovery = original_snapshot() assert before_recovery.intent is not None assert before_recovery.device_network.target is not None if plane == "host": supervisor.observe_host_path(_direct_host_path("192.168.68.50")) else: accepted = supervisor.observe_endpoint( target=before_recovery.device_network.target, intent_id=before_recovery.intent.intent_id, host_path_epoch=before_recovery.host_path.epoch, reachable=True, ) assert accepted is True return original_snapshot() monkeypatch.setattr(supervisor, "snapshot", snapshot_with_recovery_edge) invalidations: list[bool] = [] monkeypatch.setattr( facade_module, "invalidate_connected_device_session", lambda *_args, **_kwargs: invalidations.append(True) or True, ) service._retire_ephemeral_connection_binding_on_proven_loss( # noqa: SLF001 service._application_control_session.snapshot() # noqa: SLF001 ) assert snapshot_calls == 2 assert service._device_session_id is not None # noqa: SLF001 assert service._selected_device_id == "k1-a" # noqa: SLF001 assert invalidations == [] def test_old_loss_teardown_preserves_candidate_from_new_scan_generation( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _seed_supervised_connection( service, target_ipv4="192.168.68.50", connection_mode="bridge", transport_ref="k1-a", logical_device_id="device-a", ) service._device_session_discovery_generation = 4 # noqa: SLF001 service._ble_discovery_generation = 4 # noqa: SLF001 invalidations: list[tuple[str, str]] = [] monkeypatch.setattr( facade_module, "invalidate_connected_device_session", lambda device_id, *, device_session_id: ( invalidations.append((device_id, device_session_id)) or True ), ) lost_path = HostPathProbeResult( available=False, fingerprint=None, interface=None, source_ipv4=None, route_class="unavailable", reason_code="router-link-lost", ) service._connection_supervisor.observe_host_path(lost_path) # noqa: SLF001 service.state() # A new explicit scan generation completes while old-loss confirmation is # still pending. Its selected candidate belongs to the next operator # intent and must not be erased by teardown of the old device-session. service._ble_discovery_generation = 5 # noqa: SLF001 _set_scanned_k1(service, device_id="k1-a") service._connection_supervisor.observe_host_path(lost_path) # noqa: SLF001 service.state() service._connection_supervisor.observe_host_path(lost_path) # noqa: SLF001 state = service.state() assert invalidations == [("k1-a", "test-session-k1-a")] assert state["device_session"] is None assert [item["device_id"] for item in state["devices"]] == ["k1-a"] assert state["connection_policy"]["actions"]["provision-fresh-device"]["allowed"] is True def test_connection_mode_and_discovery_cas_reject_stale_connect_before_io( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service, device_id="k1-a") initial = service.state() assert initial["desired_connection_mode"] == "bridge" assert initial["desired_connection_mode_revision"] == 0 selected = service.select_connection_mode( DesiredConnectionModeRequest( connection_mode="quick-connect", expected_revision=0, ) ) assert selected["desired_connection_mode"] == "quick-connect" assert selected["desired_connection_mode_revision"] == 1 assert selected["configured_connection_mode"] is None assert selected["active_connection_mode"] is None assert selected["ble_discovery_generation"] == 0 with pytest.raises(facade_module.NetworkProvisioningConflict) as stale_select: service.select_connection_mode( DesiredConnectionModeRequest( connection_mode="direct-connect", expected_revision=0, ) ) assert stale_select.value.reason_code == "connection-mode-draft-revision-conflict" io_calls: list[str] = [] def forbidden_preflight(*_: object, **__: object) -> dict[str, Any]: io_calls.append("host-preflight") raise AssertionError("stale mode/generation must fail before host or device I/O") async def forbidden_provision(*_: object, **__: object) -> dict[str, Any]: io_calls.append("ble-write") raise AssertionError("stale mode/generation must fail before BLE") monkeypatch.setattr( facade_module, "ensure_wifi_profile_from_credential_source", forbidden_preflight, ) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_provision) with pytest.raises(facade_module.NetworkProvisioningConflict) as stale_mode: asyncio.run( service.connect( _connect_request( device_id="k1-a", connection_mode="quick-connect", compatibility_attestation=QUICK_CONNECT_ATTESTATION, expected_mode_revision=0, ) ) ) assert stale_mode.value.reason_code == "connection-mode-draft-revision-conflict" with pytest.raises(facade_module.NetworkProvisioningConflict) as stale_scan: asyncio.run( service.connect( _connect_request( device_id="k1-a", connection_mode="quick-connect", compatibility_attestation=QUICK_CONNECT_ATTESTATION, expected_mode_revision=1, expected_discovery_generation=1, ) ) ) assert stale_scan.value.reason_code == "network-provision-discovery-generation-conflict" assert io_calls == [] assert service.state()["operations"] == [] def test_pending_mode_scan_retires_prestart_control_without_physical_edge( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _select_connection_mode(service, "quick-connect") binding = _seed_supervised_connection( service, target_ipv4=facade_module.AP_FALLBACK_IPV4, connection_mode="quick-connect", transport_ref="k1-a", logical_device_id="device-a", ) control = FakeInteractiveControlSession(initial_state="idle") control.open(connection_binding=binding) control.verified_control = _verified_control_for_binding( binding, logical_device_id="device-a", ) close_calls: list[tuple[int | None, int | None]] = [] original_close_prestart = control.close_prestart def counted_close_prestart( _self: FakeInteractiveControlSession, *, expected_session_generation: int | None = None, expected_state_revision: int | None = None, ) -> dict[str, object]: close_calls.append((expected_session_generation, expected_state_revision)) return original_close_prestart( expected_session_generation=expected_session_generation, expected_state_revision=expected_state_revision, ) control.close_prestart = MethodType(counted_close_prestart, control) # type: ignore[method-assign] service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 service._acquire_application_control_process_lease() # noqa: SLF001 ready = service.state() assert ready["active_connection_mode"] == "quick-connect" assert ready["connection_lifecycle"]["connection_ready"] is True expected_close_checkpoint = ( ready["application_control_session"]["session_generation"], ready["application_control_session"]["state_revision"], ) switched = service.select_connection_mode( DesiredConnectionModeRequest( connection_mode="bridge", expected_revision=ready["desired_connection_mode_revision"], ) ) assert switched["connection_lifecycle"]["mode_change"] == { "state": "switch-selected", "from": "quick-connect", "to": "bridge", } assert switched["connection_policy"]["actions"]["scan-ble"]["allowed"] is True assert switched["connection_policy"]["actions"]["start-acquisition"]["allowed"] is False assert ( "connection-mode-switch-pending" in switched["connection_policy"]["actions"]["start-acquisition"]["reason_codes"] ) device_edges: list[str] = [] async def fake_scan( _duration_seconds: float, *, on_admitted: Callable[[], None] | None = None, ) -> dict[str, Any]: assert control.snapshot()["state"] == "idle" assert service._connection_supervisor.snapshot().authority.control_allowed is False # noqa: SLF001 assert service._selected_device_id is None # noqa: SLF001 assert on_admitted is not None on_admitted() return _ble_scan_result("bridge-candidate") async def forbidden_device_write(*_: object, **__: object) -> dict[str, Any]: device_edges.append("network-write") raise AssertionError("mode selection/scan must not write device network state") monkeypatch.setattr(facade_module, "scan", fake_scan) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_device_write) monkeypatch.setattr( service._physical_command_coordinator, # noqa: SLF001 "prepare", lambda *_args, **_kwargs: device_edges.append("physical-command"), ) scanned = asyncio.run(service.scan_ble(1.0)) assert close_calls == [expected_close_checkpoint] assert device_edges == [] assert scanned["desired_connection_mode"] == "bridge" assert scanned["configured_connection_mode"] is None assert scanned["active_connection_mode"] is None assert scanned["connection_lifecycle"]["connection_ready"] is False assert [item["device_id"] for item in scanned["devices"]] == ["bridge-candidate"] repeated = service.state() assert repeated["active_connection_mode"] is None assert repeated["selected_device_id"] is None def test_pending_reopened_physical_state_blocks_connect_and_mode_scan_before_device_io( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: device_edges: list[str] = [] async def forbidden_device_write(*_: object, **__: object) -> dict[str, Any]: device_edges.append("network-write") raise AssertionError("pending physical reopen must fail before GATT/Wi-Fi") async def forbidden_scan(*_: object, **__: object) -> dict[str, Any]: device_edges.append("ble-scan") raise AssertionError("unsafe mode transition must fail before BLE scan") monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_device_write) monkeypatch.setattr(facade_module, "scan", forbidden_scan) connect_service, _ = service_with_fake_runtime(tmp_path / "connect") _set_scanned_k1(connect_service, device_id="k1-a") pending_bridge = _pending_reopened_physical_snapshot() monkeypatch.setattr( connect_service._physical_command_coordinator, # noqa: SLF001 "snapshot", lambda: pending_bridge, ) connect_topology_before = ( connect_service._selected_device_id, # noqa: SLF001 connect_service._k1_ip, # noqa: SLF001 connect_service._connection_mode, # noqa: SLF001 connect_service._connection_supervisor.snapshot(), # noqa: SLF001 ) with pytest.raises(facade_module.NetworkProvisioningConflict) as blocked_connect: asyncio.run( connect_service.connect( _connect_request( device_id="k1-a", ssid="synthetic-network", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, ) ) ) assert blocked_connect.value.reason_code == "physical-command-reconciliation-required" assert ( connect_service._selected_device_id, # noqa: SLF001 connect_service._k1_ip, # noqa: SLF001 connect_service._connection_mode, # noqa: SLF001 connect_service._connection_supervisor.snapshot(), # noqa: SLF001 ) == connect_topology_before mode_service, _ = service_with_fake_runtime(tmp_path / "mode") _seed_supervised_connection( mode_service, transport_ref="k1-a", connection_mode="bridge", ) pending_mode = _pending_reopened_physical_snapshot() monkeypatch.setattr( mode_service._physical_command_coordinator, # noqa: SLF001 "snapshot", lambda: pending_mode, ) with mode_service._lock: # noqa: SLF001 mode_service._desired_connection_mode = "quick-connect" # noqa: SLF001 mode_service._desired_connection_mode_revision += 1 # noqa: SLF001 mode_topology_before = ( mode_service._selected_device_id, # noqa: SLF001 mode_service._k1_ip, # noqa: SLF001 mode_service._connection_mode, # noqa: SLF001 mode_service._connection_supervisor.snapshot(), # noqa: SLF001 ) with pytest.raises(facade_module.BleDiscoveryUnavailable) as blocked_scan: asyncio.run(mode_service.scan_ble(1.0)) assert blocked_scan.value.reason_code == "connection-mode-switch-physical-state-unsafe" assert ( mode_service._selected_device_id, # noqa: SLF001 mode_service._k1_ip, # noqa: SLF001 mode_service._connection_mode, # noqa: SLF001 mode_service._connection_supervisor.snapshot(), # noqa: SLF001 ) == mode_topology_before assert device_edges == [] def test_state_polling_auto_retires_terminal_prestart_control_once( tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) class FailedPrestartControl: def __init__(self) -> None: self.retire_calls = 0 self.retired = False def snapshot(self) -> dict[str, object]: if self.retired: return {"state": "idle", "can_open": True, "failure": None} return { "state": "failed", "can_open": True, "failure": { "reason_code": "mqtt-device-info-timeout", "modeling_command_attempted": False, "safe_to_retry": True, }, } def retire_for_network_change(self, **_: object) -> dict[str, object]: self.retire_calls += 1 self.retired = True return self.snapshot() control = FailedPrestartControl() service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 service._acquire_application_control_process_lease() # noqa: SLF001 first = service.state() second = service.state() assert control.retire_calls == 1 assert first["application_control_session"]["state"] == "idle" assert second["application_control_session"]["state"] == "idle" assert first["connection_policy"]["actions"]["scan-ble"]["allowed"] is True assert service._application_control_process_lease_holders == set() # noqa: SLF001 def _install_authoritative_ready_bridge_control( service: XgridsK1CompatibilityService, *, transport_ref: str = "k1-a", ) -> tuple[FakeInteractiveControlSession, ApplicationConnectionBinding, dict[str, Any]]: binding = _seed_supervised_connection( service, connection_mode="bridge", transport_ref=transport_ref, logical_device_id="device-a", ) control = FakeInteractiveControlSession(initial_state="idle") control.open(connection_binding=binding) control.verified_control = _verified_control_for_binding( binding, logical_device_id="device-a", control_session_id=f"test-control-{transport_ref}", control_proof_revision=2, ) service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 service._reconcile_connection_supervisor( # noqa: SLF001 control.snapshot(), service.runtime.snapshot(), ) service._acquire_application_control_process_lease() # noqa: SLF001 state = service.state() assert state["active_connection_mode"] == "bridge" assert state["connection_lifecycle"]["active_binding_key"] is not None return control, binding, state def _reconfiguration_request( state: dict[str, Any], intent: str, ) -> PrepareConnectionReconfigurationRequest: reconfiguration = state["connection_reconfiguration"] lifecycle = state["connection_lifecycle"] return PrepareConnectionReconfigurationRequest( intent=intent, # type: ignore[arg-type] expected_reconfiguration_revision=reconfiguration["revision"], expected_reconfiguration_intent_id=reconfiguration["intent_id"], expected_desired_mode_revision=state["desired_connection_mode_revision"], expected_active_binding_key=lifecycle["active_binding_key"], ) def _seed_durable_bridge_topology( service: XgridsK1CompatibilityService, *, transport_ref: str, ipv4: str, ) -> None: store = service._semantic_topology_store # noqa: SLF001 assert store is not None snapshot = store.snapshot() store.commit( transport_ref=transport_ref, connection_mode="bridge", ipv4=ipv4, compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, firmware_version="3.0.2", source="ble-read-only-status", observed_at_utc="2026-08-10T12:00:00Z", predecessor_revision=(snapshot.record.revision if snapshot.record is not None else 0), ) def _install_successful_bridge_verify_transport( monkeypatch: pytest.MonkeyPatch, *, device_id: str, ipv4: str, writes: list[str], ) -> None: async def existing_network_status(*_: object, **__: object) -> dict[str, Any]: return { **_wifi_status_read(ipv4), "device_macos_uuid": device_id, } async def forbidden_network_write(*_: object, **__: object) -> dict[str, Any]: writes.append("network-write") raise AssertionError("read-only Verify must not provision Wi-Fi") monkeypatch.setattr(facade_module, "read_wifi_status_once", existing_network_status) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_network_write) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr( facade_module, "_host_route_class", lambda _target: "direct-or-routed", ) monkeypatch.setattr(facade_module, "_control_endpoint_reachable", lambda _target: True) monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) def test_read_only_monitor_holder_does_not_flap_reconfiguration_policy( tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _control, _binding, ready = _install_authoritative_ready_bridge_control(service) ready_binding_key = ready["connection_lifecycle"]["active_binding_key"] ready_host_epoch = ready["connection_supervisor"]["observed"]["host_path"]["epoch"] assert ready["connection_policy"]["actions"]["prepare-select-device"]["allowed"] is True assert ready["connection_policy"]["actions"]["prepare-change-network"]["allowed"] is True service._acquire_k1_lifecycle_process_lease("monitor") # noqa: SLF001 try: during_probe = service.state() finally: service._release_k1_lifecycle_process_lease("monitor") # noqa: SLF001 assert "monitor" in during_probe["k1_lifecycle_process_lease"]["holders"] assert during_probe["connection_lifecycle"]["active_binding_key"] == ready_binding_key assert ( during_probe["connection_supervisor"]["observed"]["host_path"]["epoch"] == ready_host_epoch ) for action in ("prepare-select-device", "prepare-change-network"): decision = during_probe["connection_policy"]["actions"][action] assert decision["allowed"] is True assert "k1-lifecycle-process-lease-network-owned" not in decision["reason_codes"] def test_monitor_transient_wifi_observer_failures_retain_verified_control_and_refresh_tcp( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _control, binding, _ready = _install_authoritative_ready_bridge_control(service) initial = service._connection_supervisor.snapshot() # noqa: SLF001 assert initial.authority.control_allowed is True tcp_calls: list[str] = [] def association_observation( reason_code: str, token: str, ) -> HostWifiAssociationIdentityResult: return { "schema_version": 1, "adapter": "unavailable", "wifi_interface": None, "association_state": "unavailable", "evidence_quality": "unavailable", "continuity_proven": False, "continuity_token": token, "reason_code": reason_code, } association_calls = 0 def alternating_unproven_association( _interface_name: str | None, *, timeout_seconds: float = 30.0, ) -> HostWifiAssociationIdentityResult: nonlocal association_calls assert timeout_seconds == (facade_module.CONNECTION_MONITOR_ASSOCIATION_TIMEOUT_SECONDS) association_calls += 1 return ( association_observation("host-wifi-operation-timeout", "a" * 64) if association_calls % 2 else association_observation("association-identity-unavailable", "b" * 64) ) monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) monkeypatch.setattr( service._host_wifi_association_probe, # noqa: SLF001 "observe", alternating_unproven_association, ) monkeypatch.setattr( facade_module, "_probe_control_endpoint_socket", lambda target: ( tcp_calls.append(target) or facade_module.TcpReachabilityProbeResult(reachable=True) ), ) async def three_mixed_cycles() -> tuple[ facade_module.ConnectionSupervisorSnapshot, facade_module.ConnectionSupervisorSnapshot, facade_module.ConnectionSupervisorSnapshot, ]: first = await service._connection_monitor.poll_once() # noqa: SLF001 second = await service._connection_monitor.poll_once() # noqa: SLF001 third = await service._connection_monitor.poll_once() # noqa: SLF001 return first, second, third retained_cycles = asyncio.run(three_mixed_cycles()) assert association_calls == 6 assert tcp_calls == [binding.target_ipv4] * 3 for retained in retained_cycles: assert retained.revision > initial.revision assert retained.host_path.available is True assert retained.host_path.epoch == initial.host_path.epoch assert retained.host_path.fingerprint == initial.host_path.fingerprint assert retained.endpoint.tcp_state == "reachable" assert retained.endpoint.host_path_epoch == initial.host_path.epoch assert retained.device_identity.state == "verified" assert retained.control_plane.state == "healthy" assert retained.authority.control_allowed is True assert retained.lease.state == "reachable" assert retained.lease.generation == initial.lease.generation assert service._connection_monitor_contact_gate.locked() is False # noqa: SLF001 assert service._application_control_process_lease_holders == {"control"} # noqa: SLF001 def privacy_limited_association( _interface_name: str | None, *, timeout_seconds: float = 30.0, ) -> HostWifiAssociationIdentityResult: assert timeout_seconds == (facade_module.CONNECTION_MONITOR_ASSOCIATION_TIMEOUT_SECONDS) return association_observation("association-identity-unavailable", "b" * 64) monkeypatch.setattr( service._host_wifi_association_probe, # noqa: SLF001 "observe", privacy_limited_association, ) privacy_path = service._sample_host_path( # noqa: SLF001 binding.target_ipv4, association_timeout_seconds=(facade_module.CONNECTION_MONITOR_ASSOCIATION_TIMEOUT_SECONDS), fail_closed_unproven_association=True, ) assert privacy_path.available is True assert privacy_path.reason_code is None assert privacy_path.observation_failure_class == "association-observer" assert privacy_path.fingerprint == initial.host_path.fingerprint @pytest.mark.parametrize( ("reason_code", "expected_failure_class"), [ ("host-wifi-operation-timeout", "association-observer"), ("wifi-interface-inactive", "route"), ], ) def test_monitor_debounces_only_technical_association_timeout( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, reason_code: str, expected_failure_class: str, ) -> None: service, _ = service_with_fake_runtime(tmp_path) monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) def unavailable_association( _interface_name: str | None, *, timeout_seconds: float = 30.0, ) -> HostWifiAssociationIdentityResult: assert timeout_seconds == 3.0 return { "schema_version": 1, "adapter": "CoreWLAN", "wifi_interface": True, "association_state": "unavailable", "evidence_quality": "unavailable", "continuity_proven": False, "continuity_token": "a" * 64, "reason_code": reason_code, } monkeypatch.setattr( service._host_wifi_association_probe, # noqa: SLF001 "observe", unavailable_association, ) path = service._sample_host_path( # noqa: SLF001 "192.168.68.51", association_timeout_seconds=3.0, fail_closed_unproven_association=True, ) assert path.available is False assert path.reason_code == reason_code assert path.observation_failure_class == expected_failure_class assert path.kernel_route_fingerprint == "test-route:192.168.68.51" def test_monitor_association_sample_over_two_seconds_survives_four_full_cycles( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _control, binding, _ready = _install_authoritative_ready_bridge_control(service) host_samples: list[str] = [] tcp_samples: list[str] = [] def slow_first_host_sample( target: str, *, association_timeout_seconds: float = 30.0, fail_closed_unproven_association: bool = False, ) -> HostPathProbeResult: assert association_timeout_seconds == 3.0 assert association_timeout_seconds == ( facade_module.CONNECTION_MONITOR_ASSOCIATION_TIMEOUT_SECONDS ) assert fail_closed_unproven_association is True host_samples.append(target) if len(host_samples) % 2 == 1: # Reproduce the field boundary that exceeded the former 2 s # xcrun/CoreWLAN deadline without making the test depend on macOS. time.sleep(2.05) return _direct_host_path(target) monkeypatch.setattr(service, "_sample_host_path", slow_first_host_sample) monkeypatch.setattr( facade_module, "_probe_control_endpoint_socket", lambda target: ( tcp_samples.append(target) or facade_module.TcpReachabilityProbeResult(reachable=True) ), ) async def four_cycles() -> tuple[list[Any], list[float], list[dict[str, Any]]]: snapshots: list[Any] = [] elapsed_cycles: list[float] = [] public_states: list[dict[str, Any]] = [] for _ in range(4): started = time.monotonic() snapshots.append( await service._connection_monitor.poll_once() # noqa: SLF001 ) elapsed_cycles.append(time.monotonic() - started) public_states.append(service.state()) return snapshots, elapsed_cycles, public_states refreshed_cycles, elapsed_cycles, public_states = asyncio.run(four_cycles()) assert all( 2.0 < elapsed < DEFAULT_TRANSPORT_OBSERVATION_TTL_SECONDS for elapsed in elapsed_cycles ) assert facade_module.CONNECTION_MONITOR_HOST_CONTACT_BOUND_SECONDS == 5.0 assert ( facade_module.CONNECTION_MONITOR_HOST_CONTACT_BOUND_SECONDS < facade_module.CONNECTION_MONITOR_QUIESCE_TIMEOUT_SECONDS ) assert facade_module.CONNECTION_MONITOR_FULL_PASS_BOUND_SECONDS == 11.5 assert ( 2 * (facade_module.CONNECTION_MONITOR_FULL_PASS_BOUND_SECONDS + 1.0) < DEFAULT_TRANSPORT_OBSERVATION_TTL_SECONDS ) assert host_samples == [binding.target_ipv4, binding.target_ipv4] * 4 assert tcp_samples == [binding.target_ipv4] * 4 initial_epoch = refreshed_cycles[0].host_path.epoch initial_lease_generation = refreshed_cycles[0].lease.generation initial_selected = public_states[0]["selected_device_id"] initial_session = public_states[0]["device_session"]["device_session_id"] for refreshed, public in zip(refreshed_cycles, public_states, strict=True): assert refreshed.host_path.available is True assert refreshed.host_path.epoch == initial_epoch assert refreshed.endpoint.tcp_state == "reachable" assert refreshed.lease.state == "reachable" assert refreshed.lease.generation == initial_lease_generation assert refreshed.authority.control_allowed is True assert public["selected_device_id"] == initial_selected assert public["device_session"]["device_session_id"] == initial_session assert public["application_control_session"]["state"] == "connection-ready" def test_monitor_refreshes_verified_binding_across_timeout_positive_timeout_cycles( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) control, binding, ready = _install_authoritative_ready_bridge_control(service) baseline_supervisor = service._connection_supervisor.snapshot() # noqa: SLF001 baseline_path = baseline_supervisor.host_path assert baseline_path.kernel_route_fingerprint is not None selected_device_id = ready["selected_device_id"] device_session_id = ready["device_session"]["device_session_id"] active_binding_key = ready["connection_lifecycle"]["active_binding_key"] tcp_samples: list[str] = [] probe_mode = {"technical_failure": True} def sample_host(target: str, **_: object) -> HostPathProbeResult: if not probe_mode["technical_failure"]: return _direct_host_path(target) return HostPathProbeResult( available=False, fingerprint=None, interface=baseline_path.interface, source_ipv4=baseline_path.source_ipv4, route_class="unavailable", reason_code="host-wifi-operation-timeout", observation_failure_class="association-observer", kernel_route_fingerprint=baseline_path.kernel_route_fingerprint, ) monkeypatch.setattr(service, "_sample_host_path", sample_host) monkeypatch.setattr( facade_module, "_probe_control_endpoint_socket", lambda target: ( tcp_samples.append(target) or facade_module.TcpReachabilityProbeResult(reachable=True) ), ) async def scenario() -> tuple[list[Any], list[dict[str, Any]]]: snapshots: list[Any] = [] states: list[dict[str, Any]] = [] for _ in range(2): snapshots.append( await service._connection_monitor.poll_once() # noqa: SLF001 ) states.append(service.state()) probe_mode["technical_failure"] = False snapshots.append(await service._connection_monitor.poll_once()) # noqa: SLF001 states.append(service.state()) probe_mode["technical_failure"] = True for _ in range(5): snapshots.append( await service._connection_monitor.poll_once() # noqa: SLF001 ) states.append(service.state()) return snapshots, states monitor_states, public_states = asyncio.run(scenario()) assert len(monitor_states) == 8 assert tcp_samples == [binding.target_ipv4] * 8 previous_revision = baseline_supervisor.revision for retained, public in zip(monitor_states, public_states, strict=True): assert retained.revision > previous_revision previous_revision = retained.revision assert retained.host_path.available is True assert retained.host_path.epoch == baseline_path.epoch assert retained.host_path.fingerprint == baseline_path.fingerprint assert retained.host_path.reason_code is None assert retained.host_path_negative_streak == 0 assert retained.endpoint.tcp_state == "reachable" assert retained.endpoint.host_path_epoch == baseline_path.epoch assert retained.device_identity.state == "verified" assert retained.control_plane.state == "healthy" assert retained.lease.state == "reachable" assert retained.lease.generation == baseline_supervisor.lease.generation assert retained.authority.control_allowed is True assert public["selected_device_id"] == selected_device_id assert public["device_session"]["device_session_id"] == device_session_id assert public["connection_lifecycle"]["active_binding_key"] == active_binding_key assert public["application_control_session"]["state"] == "connection-ready" assert public["k1_lifecycle_process_lease"]["holders"] == ["control"] assert monitor_states[-1].host_path.observed_at != baseline_path.observed_at assert control.state == "connection-ready" def test_command_preflight_retains_exact_route_when_only_association_observer_times_out( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _control, binding, _ready = _install_authoritative_ready_bridge_control(service) baseline = service._connection_supervisor.snapshot() # noqa: SLF001 association_calls = 0 def timed_out_association( _interface_name: str | None, *, timeout_seconds: float = 30.0, ) -> HostWifiAssociationIdentityResult: nonlocal association_calls assert timeout_seconds == facade_module.COMMAND_BOUND_ASSOCIATION_TIMEOUT_SECONDS association_calls += 1 return { "schema_version": 1, "adapter": "CoreWLAN", "wifi_interface": True, "association_state": "unavailable", "evidence_quality": "unavailable", "continuity_proven": False, "continuity_token": f"{association_calls:064x}", "reason_code": "host-wifi-operation-timeout", } monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) monkeypatch.setattr( service._host_wifi_association_probe, # noqa: SLF001 "observe", timed_out_association, ) for _ in range(5): service._validate_application_connection_path(binding) # noqa: SLF001 retained = service._connection_supervisor.snapshot() # noqa: SLF001 assert retained.host_path.available is True assert retained.host_path.epoch == baseline.host_path.epoch assert retained.host_path.fingerprint == baseline.host_path.fingerprint assert retained.endpoint.tcp_state == "reachable" assert retained.device_identity.state == "verified" assert retained.control_plane.state == "healthy" assert retained.lease.state == "reachable" assert retained.authority.control_allowed is True assert association_calls == 5 def test_command_prepare_allows_contended_probe_plus_own_helper_within_eight_seconds( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: harness = DeterministicContendedAssociationProbe( lock_wait_seconds=3.0, helper_required_seconds=3.2, ) probe = harness.build(monkeypatch, tmp_path) service, _ = service_with_fake_runtime(tmp_path) service._host_wifi_association_probe = probe # type: ignore[assignment] # noqa: SLF001 supervisor = service._connection_supervisor # noqa: SLF001 supervisor._monotonic_clock = lambda: harness.monotonic # noqa: SLF001 supervisor._suspend_aware_clock = lambda: harness.wall # noqa: SLF001 # The helper crosses this deliberately narrow regression TTL. A fresh # exact same route/association result is itself the replacement sample and # must refresh the original epoch before any snapshot reduction runs. supervisor._observation_ttl_seconds = 5.0 # noqa: SLF001 control, binding, _ready = _install_binding_validating_ready_control( service, host_path=_association_bound_direct_host_path("192.168.1.20"), ) target = EndpointTarget(binding.target_ipv4, binding.target_port) harness.on_first_lock_acquired = lambda: supervisor.observe_endpoint( target=target, intent_id=binding.intent_id, host_path_epoch=binding.host_path_epoch, reachable=True, ) control.state = "workspace-ready" control.state_revision += 1 monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) prepared = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host=binding.target_ipv4, compatibility_attestation=ATTESTATION, expected_control_session_generation=control.session_generation, expected_control_state_revision=control.state_revision, ) ) assert facade_module.CONNECTION_MONITOR_ASSOCIATION_TIMEOUT_SECONDS == 3.0 assert facade_module.COMMAND_BOUND_ASSOCIATION_TIMEOUT_SECONDS == 8.0 assert facade_module.CONNECTION_VERIFY_HARD_TIMEOUT_SECONDS == 125.0 assert prepared["acquisition"]["state"] == "prepared" assert prepared["application_control_session"]["state"] == "project-ready" assert supervisor.snapshot().host_path.epoch == binding.host_path_epoch assert supervisor.snapshot().authority.control_allowed is True assert control.validation_calls == 2 assert harness.lock_timeouts == [8.0, 8.0] assert harness.helper_timeouts == [pytest.approx(5.0)] assert harness.monotonic == pytest.approx(106.2) def test_privacy_limited_monitor_keeps_prestart_authority_through_three_minutes( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) monotonic_now = [100.0] suspend_aware_now = [1_000.0] supervisor = service._connection_supervisor # noqa: SLF001 supervisor._monotonic_clock = lambda: monotonic_now[0] # noqa: SLF001 supervisor._suspend_aware_clock = lambda: suspend_aware_now[0] # noqa: SLF001 control, binding, _ready = _install_binding_validating_ready_control( service, host_path=_association_bound_direct_host_path("192.168.1.20"), ) timeouts: list[float] = [] tcp_calls: list[str] = [] def privacy_limited_association( _interface_name: str | None, *, timeout_seconds: float, ) -> HostWifiAssociationIdentityResult: timeouts.append(timeout_seconds) return { "schema_version": 1, "adapter": "CoreWLAN", "wifi_interface": True, "association_state": "unavailable", "evidence_quality": "unavailable", "continuity_proven": False, "continuity_token": "d" * 64, "reason_code": "association-identity-unavailable", } monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) monkeypatch.setattr( service._host_wifi_association_probe, # noqa: SLF001 "observe", privacy_limited_association, ) monkeypatch.setattr( facade_module, "_probe_control_endpoint_socket", lambda target: ( tcp_calls.append(target) or facade_module.TcpReachabilityProbeResult(reachable=True) ), ) async def monitor_for_three_minutes() -> None: for proof_revision in range(3, 33): observed = await service._connection_monitor.poll_once() # noqa: SLF001 assert observed.host_path.epoch == binding.host_path_epoch assert observed.authority.control_allowed is True assert control.verified_control is not None control.verified_control = { **control.verified_control, "control_proof_revision": proof_revision, } service._reconcile_connection_supervisor( # noqa: SLF001 control.snapshot(), service.runtime.snapshot(), ) monotonic_now[0] += 6.1 suspend_aware_now[0] += 6.1 asyncio.run(monitor_for_three_minutes()) assert monotonic_now[0] > 280.0 control.state = "workspace-ready" control.state_revision += 1 prepared = service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host=binding.target_ipv4, compatibility_attestation=ATTESTATION, expected_control_session_generation=control.session_generation, expected_control_state_revision=control.state_revision, ) ) final = supervisor.snapshot() assert prepared["acquisition"]["state"] == "prepared" assert final.host_path.epoch == binding.host_path_epoch assert final.host_path.fingerprint == ( _association_bound_direct_host_path(binding.target_ipv4).fingerprint ) assert final.endpoint.tcp_state == "reachable" assert final.device_identity.state == "verified" assert final.control_plane.state == "healthy" assert final.authority.control_allowed is True assert tcp_calls == [binding.target_ipv4] * 30 assert timeouts.count(facade_module.CONNECTION_MONITOR_ASSOCIATION_TIMEOUT_SECONDS) == 60 assert timeouts.count(facade_module.COMMAND_BOUND_ASSOCIATION_TIMEOUT_SECONDS) == 2 def test_command_timeout_after_stale_epoch_fails_before_local_or_physical_mutation( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) supervisor = service._connection_supervisor # noqa: SLF001 def expire_current_epoch() -> None: stale = supervisor.snapshot() assert stale.host_path.reason_code == "host-path-observation-stale" harness = DeterministicContendedAssociationProbe( lock_wait_seconds=3.0, helper_required_seconds=6.0, on_first_lock_acquired=expire_current_epoch, ) probe = harness.build(monkeypatch, tmp_path) service._host_wifi_association_probe = probe # type: ignore[assignment] # noqa: SLF001 supervisor._monotonic_clock = lambda: harness.monotonic # noqa: SLF001 supervisor._suspend_aware_clock = lambda: harness.wall # noqa: SLF001 supervisor._observation_ttl_seconds = 2.0 # noqa: SLF001 control, binding, _ready = _install_binding_validating_ready_control( service, host_path=_association_bound_direct_host_path("192.168.1.20"), ) control.state = "workspace-ready" control.state_revision += 1 monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) operations_before = service._operations.snapshot() # noqa: SLF001 physical_before = service._physical_command_ledger.snapshot() # noqa: SLF001 with pytest.raises(ApplicationConnectionBindingLost): service.prepare_acquisition( _prepare_request( project_name=PROJECT_NAME, host=binding.target_ipv4, compatibility_attestation=ATTESTATION, expected_control_session_generation=control.session_generation, expected_control_state_revision=control.state_revision, ) ) stale = supervisor.snapshot() assert harness.lock_timeouts == [8.0] assert harness.helper_timeouts == [pytest.approx(5.0)] assert harness.monotonic == pytest.approx(108.0) assert stale.host_path.epoch == binding.host_path_epoch + 1 assert stale.host_path.reason_code == "host-path-observation-stale" assert service._acquisition is None # noqa: SLF001 assert service._operations.snapshot() == operations_before # noqa: SLF001 assert service._physical_command_ledger.snapshot() == physical_before # noqa: SLF001 def test_command_privacy_bridge_never_retains_a_proven_association_change( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _control, binding, _ready = _install_binding_validating_ready_control( service, host_path=_association_bound_direct_host_path("192.168.1.20"), ) baseline = service._connection_supervisor.snapshot() # noqa: SLF001 monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) monkeypatch.setattr( service._host_wifi_association_probe, # noqa: SLF001 "observe", lambda *_args, **_kwargs: { **DeterministicContendedAssociationProbe.proven_observation(), "continuity_token": "b" * 64, }, ) with pytest.raises(ApplicationConnectionBindingLost): service._validate_application_connection_path(binding) # noqa: SLF001 changed = service._connection_supervisor.snapshot() # noqa: SLF001 assert changed.host_path.epoch == baseline.host_path.epoch + 1 assert changed.host_path.kernel_route_fingerprint == ( baseline.host_path.kernel_route_fingerprint ) assert changed.host_path.fingerprint != baseline.host_path.fingerprint assert changed.authority.control_allowed is False @pytest.mark.parametrize( "broken_fact", [ "configured-unverified", "identity-stale", "identity-intent", "identity-mode", "identity-epoch", "control-lost", "control-session", "control-epoch", "lease-lost", "lease-intent", "lease-mode", "lease-target", "lease-epoch", "authority-denied", ], ) def test_command_privacy_bridge_requires_exact_verified_control_chain( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, broken_fact: str, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _control, binding, _ready = _install_binding_validating_ready_control( service, host_path=_association_bound_direct_host_path("192.168.1.20"), ) supervisor = service._connection_supervisor # noqa: SLF001 baseline = supervisor.snapshot() candidate = baseline if broken_fact == "configured-unverified": candidate = replace( baseline, device_identity=replace(baseline.device_identity, state="unverified"), control_plane=replace(baseline.control_plane, state="idle", session_id=None), lease=replace(baseline.lease, state="configured-unverified"), authority=replace( baseline.authority, control_allowed=False, acquisition_start_allowed=False, ), ) elif broken_fact.startswith("identity-"): identity_changes: dict[str, object] = { "identity-stale": {"state": "stale"}, "identity-intent": {"intent_id": "other-intent"}, "identity-mode": {"connection_mode": "quick-connect"}, "identity-epoch": {"host_path_epoch": binding.host_path_epoch + 1}, }[broken_fact] candidate = replace( baseline, device_identity=replace(baseline.device_identity, **identity_changes), ) elif broken_fact.startswith("control-"): control_changes: dict[str, object] = { "control-lost": {"state": "lost"}, "control-session": {"session_id": " "}, "control-epoch": {"host_path_epoch": binding.host_path_epoch + 1}, }[broken_fact] candidate = replace( baseline, control_plane=replace(baseline.control_plane, **control_changes), ) elif broken_fact.startswith("lease-"): lease_changes: dict[str, object] = { "lease-lost": {"state": "lost"}, "lease-intent": {"intent_id": "other-intent"}, "lease-mode": {"connection_mode": "quick-connect"}, "lease-target": { "target": EndpointTarget("192.168.1.21", binding.target_port) }, "lease-epoch": {"host_path_epoch": binding.host_path_epoch + 1}, }[broken_fact] candidate = replace( baseline, lease=replace(baseline.lease, **lease_changes), ) else: assert broken_fact == "authority-denied" candidate = replace( baseline, authority=replace( baseline.authority, control_allowed=False, acquisition_start_allowed=False, ), ) monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) monkeypatch.setattr( service._host_wifi_association_probe, # noqa: SLF001 "observe", lambda *_args, **_kwargs: { "schema_version": 1, "adapter": "CoreWLAN", "wifi_interface": True, "association_state": "unavailable", "evidence_quality": "unavailable", "continuity_proven": False, "continuity_token": "d" * 64, "reason_code": "association-identity-unavailable", }, ) monkeypatch.setattr( supervisor, "association_timeout_retention_candidate", lambda *, expected_target: ( candidate if expected_target == EndpointTarget(binding.target_ipv4, binding.target_port) else None ), ) sampled = service._sample_host_path(binding.target_ipv4) # noqa: SLF001 assert sampled.available is True assert sampled.reason_code == "association-identity-unavailable" assert sampled.fingerprint != baseline.host_path.fingerprint @pytest.mark.parametrize("changed_raw_fact", ["kernel-route", "interface", "source-ipv4"]) def test_command_privacy_bridge_never_retains_a_raw_route_change( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, changed_raw_fact: str, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _control, binding, _ready = _install_binding_validating_ready_control( service, host_path=_association_bound_direct_host_path("192.168.1.20"), ) supervisor = service._connection_supervisor # noqa: SLF001 baseline = supervisor.snapshot() assert baseline.host_path.kernel_route_fingerprint is not None changed_path = HostPathProbeResult( available=True, fingerprint=( "changed-kernel-route" if changed_raw_fact == "kernel-route" else baseline.host_path.kernel_route_fingerprint ), interface=( "changed0" if changed_raw_fact == "interface" else baseline.host_path.interface ), source_ipv4=( "192.168.99.2" if changed_raw_fact == "source-ipv4" else baseline.host_path.source_ipv4 ), route_class="direct", kernel_route_fingerprint=( "changed-kernel-route" if changed_raw_fact == "kernel-route" else baseline.host_path.kernel_route_fingerprint ), ) monkeypatch.setattr(facade_module, "_inspect_host_path", lambda _target: changed_path) monkeypatch.setattr( service._host_wifi_association_probe, # noqa: SLF001 "observe", lambda *_args, **_kwargs: { "schema_version": 1, "adapter": "CoreWLAN", "wifi_interface": True, "association_state": "unavailable", "evidence_quality": "unavailable", "continuity_proven": False, "continuity_token": "d" * 64, "reason_code": "association-identity-unavailable", }, ) with pytest.raises(ApplicationConnectionBindingLost): service._validate_application_connection_path(binding) # noqa: SLF001 changed = supervisor.snapshot() assert changed.host_path.epoch == binding.host_path_epoch + 1 assert changed.authority.control_allowed is False def test_command_timeout_crossing_host_ttl_refreshes_same_route_without_epoch_loss( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) monotonic_now = [100.0] suspend_aware_now = [1_000.0] supervisor = service._connection_supervisor # noqa: SLF001 supervisor._monotonic_clock = lambda: monotonic_now[0] # noqa: SLF001 supervisor._suspend_aware_clock = lambda: suspend_aware_now[0] # noqa: SLF001 supervisor._observation_ttl_seconds = 5.0 # noqa: SLF001 _control, binding, _ready = _install_authoritative_ready_bridge_control(service) baseline = supervisor.snapshot() target = EndpointTarget(binding.target_ipv4, binding.target_port) monotonic_now[0] += 4.0 suspend_aware_now[0] += 4.0 assert supervisor.observe_endpoint( target=target, intent_id=binding.intent_id, host_path_epoch=binding.host_path_epoch, reachable=True, ) monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) def timeout_after_crossing_host_ttl( _interface_name: str | None, *, timeout_seconds: float, ) -> HostWifiAssociationIdentityResult: assert timeout_seconds == facade_module.COMMAND_BOUND_ASSOCIATION_TIMEOUT_SECONDS monotonic_now[0] += 2.0 suspend_aware_now[0] += 2.0 return { "schema_version": 1, "adapter": "CoreWLAN", "wifi_interface": True, "association_state": "unavailable", "evidence_quality": "unavailable", "continuity_proven": False, "continuity_token": "f" * 64, "reason_code": "host-wifi-operation-timeout", } monkeypatch.setattr( service._host_wifi_association_probe, # noqa: SLF001 "observe", timeout_after_crossing_host_ttl, ) service._validate_application_connection_path(binding) # noqa: SLF001 retained = supervisor.snapshot() assert retained.host_path.epoch == baseline.host_path.epoch assert retained.host_path.fingerprint == baseline.host_path.fingerprint assert retained.host_path.available is True assert retained.endpoint.tcp_state == "reachable" assert retained.device_identity.state == "verified" assert retained.control_plane.state == "healthy" assert retained.lease.state == "reachable" assert retained.authority.control_allowed is True def test_configured_unverified_monitor_keeps_same_route_without_promoting_authority( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) binding = _seed_supervised_connection(service, with_control=False) baseline = service._connection_supervisor.snapshot() # noqa: SLF001 association_calls = 0 tcp_calls: list[str] = [] def timed_out_association( _interface_name: str | None, *, timeout_seconds: float = 30.0, ) -> HostWifiAssociationIdentityResult: nonlocal association_calls assert timeout_seconds == facade_module.CONNECTION_MONITOR_ASSOCIATION_TIMEOUT_SECONDS association_calls += 1 return { "schema_version": 1, "adapter": "CoreWLAN", "wifi_interface": True, "association_state": "unavailable", "evidence_quality": "unavailable", "continuity_proven": False, "continuity_token": f"{association_calls:064x}", "reason_code": "host-wifi-operation-timeout", } monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) monkeypatch.setattr( service._host_wifi_association_probe, # noqa: SLF001 "observe", timed_out_association, ) monkeypatch.setattr( facade_module, "_probe_control_endpoint_socket", lambda target: ( tcp_calls.append(target) or facade_module.TcpReachabilityProbeResult(reachable=True) ), ) async def poll_five_times() -> list[facade_module.ConnectionSupervisorSnapshot]: return [ await service._connection_monitor.poll_once() # noqa: SLF001 for _ in range(5) ] snapshots = asyncio.run(poll_five_times()) assert association_calls == 10 assert tcp_calls == [binding.target_ipv4] * 5 for retained in snapshots: assert retained.host_path.available is True assert retained.host_path.epoch == baseline.host_path.epoch assert retained.host_path.fingerprint == baseline.host_path.fingerprint assert retained.endpoint.tcp_state == "reachable" assert retained.device_identity.state == "unverified" assert retained.control_plane.state != "healthy" assert retained.lease.state == "configured-unverified" assert retained.authority.control_allowed is False assert retained.authority.acquisition_start_allowed is False assert "verify-control-device-info" in retained.allowed_actions def test_association_timeout_cannot_hide_a_real_kernel_route_change( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _control, binding, _ready = _install_authoritative_ready_bridge_control(service) baseline = service._connection_supervisor.snapshot() # noqa: SLF001 changed_path = HostPathProbeResult( available=True, fingerprint="changed-kernel-route", interface=baseline.host_path.interface, source_ipv4=baseline.host_path.source_ipv4, route_class="direct", kernel_route_fingerprint="changed-kernel-route", ) monkeypatch.setattr(facade_module, "_inspect_host_path", lambda _target: changed_path) monkeypatch.setattr( service._host_wifi_association_probe, # noqa: SLF001 "observe", lambda *_args, **_kwargs: { "schema_version": 1, "adapter": "CoreWLAN", "wifi_interface": True, "association_state": "unavailable", "evidence_quality": "unavailable", "continuity_proven": False, "continuity_token": "f" * 64, "reason_code": "host-wifi-operation-timeout", }, ) with pytest.raises(ApplicationConnectionBindingLost): service._validate_application_connection_path(binding) # noqa: SLF001 changed = service._connection_supervisor.snapshot() # noqa: SLF001 assert changed.host_path.epoch == baseline.host_path.epoch + 1 assert changed.host_path.kernel_route_fingerprint == "changed-kernel-route" assert changed.authority.control_allowed is False assert changed.lease.state != "reachable" def test_command_preflight_drops_stale_sample_after_concurrent_route_change( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _control, binding, _ready = _install_authoritative_ready_bridge_control(service) baseline = service._connection_supervisor.snapshot() # noqa: SLF001 changed_path = HostPathProbeResult( available=True, fingerprint="changed-combined-route", interface="changed0", source_ipv4="192.168.99.2", route_class="direct", kernel_route_fingerprint="changed-kernel-route", ) stale_path = HostPathProbeResult( available=True, fingerprint=baseline.host_path.fingerprint, interface=baseline.host_path.interface, source_ipv4=baseline.host_path.source_ipv4, route_class="direct", kernel_route_fingerprint=baseline.host_path.kernel_route_fingerprint, ) def sample_after_newer_route_wins( _target: str, *, association_timeout_seconds: float, ) -> HostPathProbeResult: assert ( association_timeout_seconds == facade_module.COMMAND_BOUND_ASSOCIATION_TIMEOUT_SECONDS ) observed_epoch = service._connection_supervisor.observe_host_path( # noqa: SLF001 changed_path ) assert observed_epoch == baseline.host_path.epoch + 1 return stale_path monkeypatch.setattr(service, "_sample_host_path", sample_after_newer_route_wins) with pytest.raises(ApplicationConnectionBindingLost): service._validate_application_connection_path(binding) # noqa: SLF001 current = service._connection_supervisor.snapshot() # noqa: SLF001 assert current.host_path.epoch == baseline.host_path.epoch + 1 assert current.host_path.fingerprint == "changed-combined-route" assert current.host_path.kernel_route_fingerprint == "changed-kernel-route" assert current.host_path.interface == "changed0" assert current.host_path.source_ipv4 == "192.168.99.2" assert current.authority.control_allowed is False @pytest.mark.parametrize( "changed_route_fact", ["fingerprint", "interface", "source-ipv4"], ) def test_monitor_does_not_debounce_real_route_change_hidden_by_observer_failure( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, changed_route_fact: str, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _control, _binding, _ready = _install_authoritative_ready_bridge_control(service) baseline = service._connection_supervisor.snapshot() # noqa: SLF001 baseline_path = baseline.host_path assert baseline_path.kernel_route_fingerprint is not None changed = HostPathProbeResult( available=False, fingerprint=None, interface=("changed0" if changed_route_fact == "interface" else baseline_path.interface), source_ipv4=( "192.168.99.2" if changed_route_fact == "source-ipv4" else baseline_path.source_ipv4 ), route_class="unavailable", reason_code="host-wifi-operation-timeout", observation_failure_class="association-observer", kernel_route_fingerprint=( "changed-kernel-route" if changed_route_fact == "fingerprint" else baseline_path.kernel_route_fingerprint ), ) monkeypatch.setattr(service, "_sample_host_path", lambda *_args, **_kwargs: changed) tcp_samples: list[str] = [] monkeypatch.setattr( facade_module, "_probe_control_endpoint_socket", lambda target: ( tcp_samples.append(target) or facade_module.TcpReachabilityProbeResult(reachable=True) ), ) observed = asyncio.run(service._connection_monitor.poll_once()) # noqa: SLF001 assert observed.revision > baseline.revision assert observed.host_path.available is False assert observed.host_path.reason_code == "host-wifi-operation-timeout" assert observed.authority.control_allowed is False assert observed.lease.state != "reachable" assert tcp_samples == [] def test_read_only_monitor_runs_alongside_steady_control_holder( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _control, binding, _ready = _install_authoritative_ready_bridge_control(service) initial = service._connection_supervisor.snapshot() # noqa: SLF001 host_samples: list[str] = [] tcp_samples: list[str] = [] def sample_host( target: str, *, association_timeout_seconds: float = 30.0, fail_closed_unproven_association: bool = False, ) -> HostPathProbeResult: assert association_timeout_seconds == ( facade_module.CONNECTION_MONITOR_ASSOCIATION_TIMEOUT_SECONDS ) assert fail_closed_unproven_association is True host_samples.append(target) return _direct_host_path(target) def sample_tcp(target: str) -> facade_module.TcpReachabilityProbeResult: tcp_samples.append(target) return facade_module.TcpReachabilityProbeResult(reachable=True) monkeypatch.setattr(service, "_sample_host_path", sample_host) monkeypatch.setattr(facade_module, "_probe_control_endpoint_socket", sample_tcp) refreshed = asyncio.run(service._connection_monitor.poll_once()) # noqa: SLF001 assert host_samples == [binding.target_ipv4, binding.target_ipv4] assert tcp_samples == [binding.target_ipv4] assert refreshed.revision > initial.revision assert refreshed.host_path.epoch == initial.host_path.epoch assert refreshed.endpoint.tcp_state == "reachable" assert service._application_control_process_lease_holders == {"control"} # noqa: SLF001 def test_read_only_monitor_keeps_ready_from_exact_durable_target_after_ephemeral_cleanup( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _control, binding, _ready = _install_authoritative_ready_bridge_control( service, transport_ref="F89438FA-55ED-85AD-EED7-734AC84746D8", ) _seed_durable_bridge_topology( service, # CoreBluetooth UUID spelling is not durable identity. The monitor # compares its physical key case-insensitively while retaining the # exact supervisor spelling for current-process evidence. transport_ref=binding.transport_ref.lower(), ipv4=binding.target_ipv4, ) service._retire_ephemeral_device_binding_for_new_intent() # noqa: SLF001 host_samples: list[str] = [] tcp_samples: list[str] = [] def sample_host( target: str, **_: object, ) -> HostPathProbeResult: host_samples.append(target) return _direct_host_path(target) def sample_tcp(target: str) -> facade_module.TcpReachabilityProbeResult: tcp_samples.append(target) return facade_module.TcpReachabilityProbeResult(reachable=True) monkeypatch.setattr(service, "_sample_host_path", sample_host) monkeypatch.setattr(facade_module, "_probe_control_endpoint_socket", sample_tcp) refreshed = asyncio.run(service._connection_monitor.poll_once()) # noqa: SLF001 assert service._selected_device_id is None # noqa: SLF001 assert service._device_session_id is None # noqa: SLF001 assert host_samples == [binding.target_ipv4, binding.target_ipv4] assert tcp_samples == [binding.target_ipv4] assert refreshed.host_path.available is True assert refreshed.endpoint.tcp_state == "reachable" assert refreshed.device_identity.state == "verified" assert refreshed.control_plane.state == "healthy" assert refreshed.lease.state == "reachable" assert refreshed.authority.control_allowed is True assert refreshed.authority.acquisition_start_allowed is True def test_read_only_monitor_durable_target_still_downgrades_on_real_route_loss( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _control, binding, _ready = _install_authoritative_ready_bridge_control(service) _seed_durable_bridge_topology( service, transport_ref=binding.transport_ref, ipv4=binding.target_ipv4, ) service._retire_ephemeral_device_binding_for_new_intent() # noqa: SLF001 tcp_samples: list[str] = [] monkeypatch.setattr( service, "_sample_host_path", lambda _target, **_kwargs: HostPathProbeResult( available=False, fingerprint=None, interface=None, source_ipv4=None, route_class="unavailable", reason_code="router-link-lost", ), ) monkeypatch.setattr( facade_module, "_probe_control_endpoint_socket", lambda target: ( tcp_samples.append(target) or facade_module.TcpReachabilityProbeResult(reachable=True) ), ) lost = asyncio.run(service._connection_monitor.poll_once()) # noqa: SLF001 assert tcp_samples == [] assert lost.host_path.available is False assert lost.host_path.reason_code == "router-link-lost" assert lost.endpoint.tcp_state == "unknown" assert lost.lease.state == "configured-unverified" assert lost.authority.control_allowed is False assert lost.authority.acquisition_start_allowed is False @pytest.mark.parametrize( "invalid_context", [ "selected-without-session", "session-without-selected", "semantic-empty", "semantic-store-missing", "semantic-store-corrupt", "semantic-ref-mismatch", "semantic-mode-mismatch", "semantic-ip-mismatch", "semantic-profile-mismatch", "physically-retired", ], ) def test_read_only_monitor_durable_fallback_rejects_inexact_or_unsafe_context( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, invalid_context: str, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _control, binding, _ready = _install_authoritative_ready_bridge_control(service) store = service._semantic_topology_store # noqa: SLF001 assert store is not None contexts_with_exact_semantic = { "selected-without-session", "session-without-selected", "semantic-store-missing", "semantic-store-corrupt", "physically-retired", } if invalid_context in contexts_with_exact_semantic: _seed_durable_bridge_topology( service, transport_ref=binding.transport_ref, ipv4=binding.target_ipv4, ) elif invalid_context.startswith("semantic-") and invalid_context != "semantic-empty": snapshot = store.snapshot() store.commit( transport_ref=( "different-k1" if invalid_context == "semantic-ref-mismatch" else binding.transport_ref ), connection_mode=( "direct-connect" if invalid_context == "semantic-mode-mismatch" else "bridge" ), ipv4=( "192.168.68.77" if invalid_context == "semantic-ip-mismatch" else binding.target_ipv4 ), compatibility_profile_id=( "different.compatibility.profile" if invalid_context == "semantic-profile-mismatch" else XGRIDS_K1_COMPATIBILITY_PROFILE_ID ), firmware_version="3.0.2", source="ble-read-only-status", observed_at_utc="2026-08-11T08:00:00Z", predecessor_revision=(snapshot.record.revision if snapshot.record is not None else 0), ) service._retire_ephemeral_device_binding_for_new_intent() # noqa: SLF001 if invalid_context == "selected-without-session": with service._lock: # noqa: SLF001 service._selected_device_id = binding.transport_ref # noqa: SLF001 elif invalid_context == "session-without-selected": with service._lock: # noqa: SLF001 service._device_session_id = "orphaned-session" # noqa: SLF001 elif invalid_context == "semantic-store-missing": service._semantic_topology_store = None # noqa: SLF001 elif invalid_context == "semantic-store-corrupt": def corrupt_snapshot() -> object: raise facade_module.SemanticTopologyStoreCorrupt("synthetic corrupt store") monkeypatch.setattr(store, "snapshot", corrupt_snapshot) elif invalid_context == "physically-retired": monkeypatch.setattr( service, "_retired_physical_transport_refs", lambda: {binding.transport_ref.casefold()}, ) host_samples: list[str] = [] tcp_samples: list[str] = [] monkeypatch.setattr( service, "_sample_host_path", lambda target, **_kwargs: host_samples.append(target) or _direct_host_path(target), ) monkeypatch.setattr( facade_module, "_probe_control_endpoint_socket", lambda target: ( tcp_samples.append(target) or facade_module.TcpReachabilityProbeResult(reachable=True) ), ) assert service._connection_monitor_target() is None # noqa: SLF001 rejected = asyncio.run(service._connection_monitor.poll_once()) # noqa: SLF001 assert host_samples == [] assert tcp_samples == [] assert rejected.host_path.available is False assert rejected.host_path.reason_code == "endpoint-target-unconfigured" assert rejected.endpoint.tcp_state == "unknown" assert rejected.lease.state == "configured-unverified" assert rejected.authority.control_allowed is False assert rejected.authority.acquisition_start_allowed is False @pytest.mark.parametrize( "durable_store_change", ["missing", "corrupt", "replaced"], ) def test_monitor_revalidates_durable_sourced_supervisor_even_with_ephemeral_binding( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, durable_store_change: str, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _control, binding, _ready = _install_authoritative_ready_bridge_control(service) _seed_durable_bridge_topology( service, transport_ref=binding.transport_ref, ipv4=binding.target_ipv4, ) supervisor = service._connection_supervisor # noqa: SLF001 current = supervisor.snapshot() assert current.intent is not None assert current.device_network.target is not None assert supervisor.observe_device_network_applied( intent_id=current.intent.intent_id, transport_ref=binding.transport_ref, connection_mode="bridge", target=current.device_network.target, source="durable-semantic-topology", ) assert service._connection_monitor_target() == current.device_network.target # noqa: SLF001 store = service._semantic_topology_store # noqa: SLF001 assert store is not None if durable_store_change == "missing": service._semantic_topology_store = None # noqa: SLF001 elif durable_store_change == "corrupt": def corrupt_snapshot() -> object: raise facade_module.SemanticTopologyStoreCorrupt("synthetic corrupt store") monkeypatch.setattr(store, "snapshot", corrupt_snapshot) else: semantic = store.snapshot() assert semantic.record is not None store.commit( transport_ref=binding.transport_ref, connection_mode="bridge", ipv4="192.168.68.77", compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, firmware_version="3.0.2", source="ble-read-only-status", observed_at_utc="2026-08-11T08:30:00Z", predecessor_revision=semantic.record.revision, ) host_samples: list[str] = [] monkeypatch.setattr( service, "_sample_host_path", lambda target, **_kwargs: host_samples.append(target) or _direct_host_path(target), ) assert service._connection_monitor_target() is None # noqa: SLF001 rejected = asyncio.run(service._connection_monitor.poll_once()) # noqa: SLF001 assert host_samples == [] assert rejected.host_path.available is False assert rejected.host_path.reason_code == "endpoint-target-unconfigured" assert rejected.authority.control_allowed is False def test_monitor_network_admission_race_is_dropped_without_negative_evidence( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _control, _binding, _ready = _install_authoritative_ready_bridge_control(service) initial = service._connection_supervisor.snapshot() # noqa: SLF001 original_acquire = service._acquire_k1_lifecycle_process_lease # noqa: SLF001 network_injected = False host_io: list[str] = [] def raced_acquire(holder: Any) -> None: nonlocal network_injected if holder == "monitor" and not network_injected: original_acquire("network") network_injected = True original_acquire(holder) monkeypatch.setattr(service, "_acquire_k1_lifecycle_process_lease", raced_acquire) monkeypatch.setattr( service, "_sample_host_path", lambda *_args, **_kwargs: host_io.append("host") or _direct_host_path("10.0.0.1"), ) try: after_race = asyncio.run(service._connection_monitor.poll_once()) # noqa: SLF001 finally: if network_injected: service._release_k1_lifecycle_process_lease("network") # noqa: SLF001 assert network_injected is True assert host_io == [] assert after_race.revision == initial.revision assert after_race.host_path == initial.host_path assert after_race.endpoint == initial.endpoint assert service._application_control_process_lease_holders == {"control"} # noqa: SLF001 def test_explicit_reconfiguration_waits_for_monitor_and_drops_stale_probe( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) control, binding, ready = _install_authoritative_ready_bridge_control(service) request = _reconfiguration_request(ready, "select-device") initial_supervisor = service._connection_supervisor.snapshot() # noqa: SLF001 probe_entered = threading.Event() release_probe = threading.Event() device_edges: list[str] = [] def blocked_host_path( target: str, *, association_timeout_seconds: float = 30.0, fail_closed_unproven_association: bool = False, ) -> HostPathProbeResult: assert association_timeout_seconds == ( facade_module.CONNECTION_MONITOR_ASSOCIATION_TIMEOUT_SECONDS ) assert fail_closed_unproven_association is True probe_entered.set() assert release_probe.wait(timeout=5.0) assert target == binding.target_ipv4 # If this superseded result were admitted after the operator won the # transition, it would rotate the host epoch and revoke the old proof. return _direct_host_path("192.168.56.20") async def forbidden_device_io(*_args: object, **_kwargs: object) -> object: device_edges.append("ble-or-network") raise AssertionError("local reconfiguration must not perform device I/O") monkeypatch.setattr(service, "_sample_host_path", blocked_host_path) monkeypatch.setattr(facade_module, "read_wifi_status_once", forbidden_device_io) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_device_io) monkeypatch.setattr( service._physical_command_coordinator, # noqa: SLF001 "prepare", lambda *_args, **_kwargs: device_edges.append("physical-command"), ) async def scenario() -> tuple[dict[str, Any], dict[str, Any]]: monitor_task = asyncio.create_task( service._connection_monitor.poll_once() # noqa: SLF001 ) assert await asyncio.to_thread(probe_entered.wait, 5.0) during_probe = await asyncio.to_thread(service.state) assert "monitor" in during_probe["k1_lifecycle_process_lease"]["holders"] for action in ("prepare-select-device", "prepare-change-network"): assert during_probe["connection_policy"]["actions"][action]["allowed"] is True prepare_task = asyncio.create_task(service.prepare_connection_reconfiguration(request)) for _ in range(100): if service._k1_lifecycle_transition_gate.locked(): # noqa: SLF001 break await asyncio.sleep(0.001) assert service._k1_lifecycle_transition_gate.locked() # noqa: SLF001 await asyncio.sleep(0.01) assert prepare_task.done() is False release_probe.set() monitor_state = await monitor_task prepared = await prepare_task return monitor_state, prepared monitor_state, prepared = asyncio.run(scenario()) assert monitor_state.host_path.epoch == initial_supervisor.host_path.epoch assert prepared["connection_reconfiguration"]["intent"] == "select-device" assert prepared["connection_reconfiguration"]["status"] == "awaiting-fresh-scan" assert prepared["connection_supervisor"]["observed"]["host_path"]["epoch"] == ( initial_supervisor.host_path.epoch ) assert "monitor" not in service._application_control_process_lease_holders # noqa: SLF001 assert control.stop_calls == 0 assert control.start_projects == [] assert runtime.start_calls == [] assert runtime.stop_calls == 0 assert device_edges == [] assert binding.target_ipv4 == "192.168.1.20" def test_cancelled_monitor_keeps_contact_owned_until_operator_can_commit( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) control, binding, ready = _install_authoritative_ready_bridge_control(service) request = _reconfiguration_request(ready, "select-device") initial = service._connection_supervisor.snapshot() # noqa: SLF001 probe_entered = threading.Event() release_probe = threading.Event() device_edges: list[str] = [] def blocked_host_path( target: str, *, association_timeout_seconds: float = 30.0, fail_closed_unproven_association: bool = False, ) -> HostPathProbeResult: assert association_timeout_seconds == ( facade_module.CONNECTION_MONITOR_ASSOCIATION_TIMEOUT_SECONDS ) assert fail_closed_unproven_association is True probe_entered.set() assert release_probe.wait(timeout=5.0) assert target == binding.target_ipv4 return _direct_host_path("192.168.56.20") async def forbidden_device_io(*_args: object, **_kwargs: object) -> object: device_edges.append("ble-or-network") raise AssertionError("cancelled monitor handoff must not perform device I/O") monkeypatch.setattr(service, "_sample_host_path", blocked_host_path) monkeypatch.setattr(facade_module, "read_wifi_status_once", forbidden_device_io) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_device_io) async def scenario() -> tuple[dict[str, Any], bool]: monitor_task = asyncio.create_task( service._connection_monitor.poll_once() # noqa: SLF001 ) assert await asyncio.to_thread(probe_entered.wait, 5.0) monitor_task.cancel() prepare_task = asyncio.create_task(service.prepare_connection_reconfiguration(request)) for _ in range(100): if service._k1_lifecycle_transition_gate.locked(): # noqa: SLF001 break await asyncio.sleep(0.001) assert service._k1_lifecycle_transition_gate.locked() # noqa: SLF001 await asyncio.sleep(0.01) assert prepare_task.done() is False assert "network" not in service._application_control_process_lease_holders # noqa: SLF001 release_probe.set() with pytest.raises(asyncio.CancelledError): await monitor_task prepared = await prepare_task return prepared, service._connection_monitor_contact_gate.locked() # noqa: SLF001 prepared, contact_locked = asyncio.run(scenario()) assert contact_locked is False assert service._k1_lifecycle_transition_gate.locked() is False # noqa: SLF001 assert service._connection_reconfiguration_gate.locked() is False # noqa: SLF001 assert prepared["connection_reconfiguration"]["status"] == "awaiting-fresh-scan" assert prepared["connection_supervisor"]["observed"]["host_path"]["epoch"] == ( initial.host_path.epoch ) assert "monitor" not in service._application_control_process_lease_holders # noqa: SLF001 assert control.stop_calls == 0 assert control.start_projects == [] assert runtime.start_calls == [] assert device_edges == [] def test_monitor_quiescence_timeout_releases_operator_gates_and_drops_late_result( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) control, binding, ready = _install_authoritative_ready_bridge_control(service) request = _reconfiguration_request(ready, "select-device") initial = service._connection_supervisor.snapshot() # noqa: SLF001 probe_entered = threading.Event() release_probe = threading.Event() device_edges: list[str] = [] def blocked_host_path( target: str, *, association_timeout_seconds: float = 30.0, fail_closed_unproven_association: bool = False, ) -> HostPathProbeResult: assert association_timeout_seconds == ( facade_module.CONNECTION_MONITOR_ASSOCIATION_TIMEOUT_SECONDS ) assert fail_closed_unproven_association is True probe_entered.set() assert release_probe.wait(timeout=5.0) assert target == binding.target_ipv4 return _direct_host_path("192.168.56.20") async def forbidden_device_io(*_args: object, **_kwargs: object) -> object: device_edges.append("ble-or-network") raise AssertionError("quiescence timeout must not perform device I/O") monkeypatch.setattr( facade_module, "CONNECTION_MONITOR_QUIESCE_TIMEOUT_SECONDS", 0.01, ) monkeypatch.setattr(service, "_sample_host_path", blocked_host_path) monkeypatch.setattr(facade_module, "read_wifi_status_once", forbidden_device_io) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_device_io) async def scenario() -> None: monitor_task = asyncio.create_task( service._connection_monitor.poll_once() # noqa: SLF001 ) assert await asyncio.to_thread(probe_entered.wait, 5.0) with pytest.raises(facade_module.NetworkProvisioningConflict) as conflict: await service.prepare_connection_reconfiguration(request) assert conflict.value.reason_code == "connection-reconfiguration-lifecycle-busy" assert service._k1_lifecycle_transition_gate.locked() is False # noqa: SLF001 assert service._connection_reconfiguration_gate.locked() is False # noqa: SLF001 assert "network" not in service._application_control_process_lease_holders # noqa: SLF001 monitor_task.cancel() release_probe.set() with pytest.raises(asyncio.CancelledError): await monitor_task asyncio.run(scenario()) after = service._connection_supervisor.snapshot() # noqa: SLF001 assert after.revision == initial.revision assert after.host_path == initial.host_path assert service._connection_monitor_contact_gate.locked() is False # noqa: SLF001 assert service._connection_reconfiguration_intent is None # noqa: SLF001 assert service._application_control_process_lease_holders == {"control"} # noqa: SLF001 assert control.stop_calls == 0 assert control.start_projects == [] assert runtime.start_calls == [] assert device_edges == [] def test_same_mode_scan_waits_for_monitor_instead_of_returning_busy( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _runtime = service_with_fake_runtime(tmp_path) _control, binding, ready = _install_authoritative_ready_bridge_control(service) initial_epoch = ready["connection_supervisor"]["observed"]["host_path"]["epoch"] probe_entered = threading.Event() release_probe = threading.Event() scan_calls: list[float] = [] tcp_calls: list[str] = [] def blocked_host_path( target: str, *, association_timeout_seconds: float = 30.0, fail_closed_unproven_association: bool = False, ) -> HostPathProbeResult: assert association_timeout_seconds == ( facade_module.CONNECTION_MONITOR_ASSOCIATION_TIMEOUT_SECONDS ) assert fail_closed_unproven_association is True probe_entered.set() assert release_probe.wait(timeout=5.0) assert target == binding.target_ipv4 return _direct_host_path("192.168.56.20") async def fake_scan( duration_seconds: float, *, on_admitted: Callable[[], None] | None = None, ) -> dict[str, Any]: scan_calls.append(duration_seconds) assert on_admitted is not None on_admitted() return _ble_scan_result("fresh-k1") def forbidden_tcp(target: str) -> facade_module.TcpReachabilityProbeResult: tcp_calls.append(target) raise AssertionError("operator lifecycle gate must supersede the next monitor contact") monkeypatch.setattr(service, "_sample_host_path", blocked_host_path) monkeypatch.setattr(facade_module, "_probe_control_endpoint_socket", forbidden_tcp) monkeypatch.setattr(facade_module, "scan", fake_scan) async def scenario() -> tuple[dict[str, Any], int]: monitor_task = asyncio.create_task( service._connection_monitor.poll_once() # noqa: SLF001 ) assert await asyncio.to_thread(probe_entered.wait, 5.0) scan_task = asyncio.create_task(service.scan_ble(0.1)) for _ in range(100): if service._k1_lifecycle_transition_gate.locked(): # noqa: SLF001 break await asyncio.sleep(0.001) assert service._k1_lifecycle_transition_gate.locked() # noqa: SLF001 await asyncio.sleep(0.01) assert scan_task.done() is False assert scan_calls == [] assert "network" not in service._application_control_process_lease_holders # noqa: SLF001 release_probe.set() monitor_state = await monitor_task scanned = await scan_task return scanned, monitor_state.host_path.epoch scanned, monitor_epoch = asyncio.run(scenario()) assert scan_calls == [0.1] assert [item["device_id"] for item in scanned["devices"]] == ["fresh-k1"] assert monitor_epoch == initial_epoch assert scanned["connection_supervisor"]["observed"]["host_path"]["epoch"] == (initial_epoch) assert service._connection_monitor_contact_gate.locked() is False # noqa: SLF001 assert "monitor" not in service._application_control_process_lease_holders # noqa: SLF001 assert tcp_calls == [] def test_select_device_handoff_is_local_cancel_invalidates_candidates_and_stale_tabs( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) control, _binding, ready = _install_authoritative_ready_bridge_control(service) initial_request = _reconfiguration_request(ready, "select-device") semantic_before = ready["semantic_topology_store"] identity_before = ready["device_identity_pin_store"] device_edges: list[str] = [] async def forbidden_network_write(*_: object, **__: object) -> dict[str, Any]: device_edges.append("network-write") raise AssertionError("local reconfiguration handoff must not write K1") monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_network_write) monkeypatch.setattr( service._physical_command_coordinator, # noqa: SLF001 "prepare", lambda *_args, **_kwargs: device_edges.append("physical-command"), ) prepared = asyncio.run(service.prepare_connection_reconfiguration(initial_request)) assert prepared["connection_reconfiguration"]["intent"] == "select-device" assert prepared["connection_reconfiguration"]["status"] == "awaiting-fresh-scan" assert prepared["connection_reconfiguration"]["required_connection_mode"] == "bridge" assert prepared["connection_lifecycle"]["active_binding"] is None assert prepared["selected_device_id"] is None assert ( prepared["connection_policy"]["actions"]["prepare-select-device"][ "required_connection_mode" ] == "bridge" ) assert prepared["semantic_topology_store"] == semantic_before assert prepared["device_identity_pin_store"] == identity_before assert control.state == "idle" assert control.start_projects == [] assert control.stop_calls == 0 assert runtime.start_calls == [] assert runtime.stop_calls == 0 assert service._application_control_process_lease_holders == set() # noqa: SLF001 assert device_edges == [] # The losing tab cannot repeat the original handoff after the stable # operator-only revision/intent id advanced. with pytest.raises(facade_module.NetworkProvisioningConflict) as stale_prepare: asyncio.run(service.prepare_connection_reconfiguration(initial_request)) assert stale_prepare.value.reason_code == "connection-reconfiguration-revision-conflict" minimum_generation = prepared["connection_reconfiguration"]["minimum_discovery_generation"] service._ble_discovery_generation = minimum_generation # noqa: SLF001 _set_scanned_k1(service, device_id="k1-b") fresh = service.state() assert fresh["connection_reconfiguration"]["status"] == "fresh-scan-completed" assert [item["device_id"] for item in fresh["devices"]] == ["k1-b"] stale_connect_request = _connect_request( device_id="k1-b", ssid="lab-router", password=SecretStr(PRIMARY_TEST_CREDENTIAL), connection_mode="bridge", compatibility_attestation=ATTESTATION, expected_mode_revision=fresh["desired_connection_mode_revision"], expected_discovery_generation=fresh["ble_discovery_generation"], expected_reconfiguration_revision=fresh["connection_reconfiguration"]["revision"], expected_reconfiguration_intent_id=fresh["connection_reconfiguration"]["intent_id"], ) stale_verify_request = ConnectionVerifyRequest( device_id="k1-b", source="fresh-scan", compatibility_attestation=ATTESTATION, expected_discovery_generation=fresh["ble_discovery_generation"], expected_reconfiguration_revision=fresh["connection_reconfiguration"]["revision"], expected_reconfiguration_intent_id=fresh["connection_reconfiguration"]["intent_id"], ) quick_verify_request = ConnectionVerifyRequest( device_id="k1-b", source="fresh-scan", compatibility_attestation=QUICK_CONNECT_ATTESTATION, expected_discovery_generation=fresh["ble_discovery_generation"], expected_reconfiguration_revision=fresh["connection_reconfiguration"]["revision"], expected_reconfiguration_intent_id=fresh["connection_reconfiguration"]["intent_id"], ) with pytest.raises(facade_module.NetworkProvisioningConflict) as quick_isolated: asyncio.run(service.verify_connection(quick_verify_request)) assert quick_isolated.value.reason_code == "connection-reconfiguration-target-mismatch" cancel_request = _reconfiguration_request(fresh, "cancel") cancelled = asyncio.run(service.prepare_connection_reconfiguration(cancel_request)) assert cancelled["connection_reconfiguration"]["status"] == "idle" assert cancelled["connection_reconfiguration"]["intent_id"] is None assert cancelled["devices"] == [] assert cancelled["ble_discovery_generation"] > minimum_generation assert cancelled["semantic_topology_store"] == semantic_before assert cancelled["device_identity_pin_store"] == identity_before assert device_edges == [] password_reads: list[str] = [] process_lease_calls: list[str] = [] def forbidden_password_read(_secret: SecretStr) -> str: password_reads.append("unwrapped") raise AssertionError("stale Connect must fail before password unwrap") def forbidden_process_lease(holder: str) -> None: process_lease_calls.append(holder) raise AssertionError("stale mutation must fail before process lease") monkeypatch.setattr(SecretStr, "get_secret_value", forbidden_password_read) monkeypatch.setattr( service, "_acquire_k1_lifecycle_process_lease", forbidden_process_lease, ) with pytest.raises(facade_module.NetworkProvisioningConflict) as stale_connect: asyncio.run(service.connect(stale_connect_request)) assert stale_connect.value.reason_code == "connection-reconfiguration-revision-conflict" with pytest.raises(facade_module.NetworkProvisioningConflict) as stale_verify: asyncio.run(service.verify_connection(stale_verify_request)) assert stale_verify.value.reason_code == "connection-reconfiguration-revision-conflict" assert password_reads == [] assert process_lease_calls == [] assert service._operations.snapshot() == [] # noqa: SLF001 with pytest.raises(facade_module.NetworkProvisioningConflict) as stale_cancel: asyncio.run(service.prepare_connection_reconfiguration(cancel_request)) assert stale_cancel.value.reason_code == "connection-reconfiguration-revision-conflict" def test_change_network_requires_authoritative_binding_before_any_local_teardown( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) control, _binding, ready = _install_authoritative_ready_bridge_control(service) supervisor = service._connection_supervisor # noqa: SLF001 supervisor_state = supervisor.snapshot() assert supervisor_state.intent is not None assert supervisor_state.device_network.target is not None assert supervisor.observe_endpoint( target=supervisor_state.device_network.target, intent_id=supervisor_state.intent.intent_id, host_path_epoch=supervisor_state.host_path.epoch, reachable=False, reason_code="tcp-endpoint-unreachable", ) degraded = service.state() assert degraded["selected_device_id"] == "k1-a" assert degraded["connection_lifecycle"]["active_binding"] is None assert control.state == "connection-ready" decision = degraded["connection_policy"]["actions"]["prepare-change-network"] assert decision["allowed"] is False assert "connection-reconfiguration-current-device-unavailable" in decision["reason_codes"] process_lease_calls: list[str] = [] original_acquire = service._acquire_k1_lifecycle_process_lease # noqa: SLF001 def counted_acquire(holder: str) -> None: process_lease_calls.append(holder) original_acquire(holder) monkeypatch.setattr(service, "_acquire_k1_lifecycle_process_lease", counted_acquire) before_control_revision = control.state_revision with pytest.raises(facade_module.NetworkProvisioningConflict) as unavailable: asyncio.run( service.prepare_connection_reconfiguration( _reconfiguration_request(degraded, "change-network") ) ) assert unavailable.value.reason_code == ( "connection-reconfiguration-current-device-unavailable" ) assert process_lease_calls == [] assert control.state == "connection-ready" assert control.state_revision == before_control_revision assert service._selected_device_id == "k1-a" # noqa: SLF001 assert service._connection_reconfiguration_intent is None # noqa: SLF001 assert service._application_control_process_lease_holders == {"control"} # noqa: SLF001 def test_bridge_reconfiguration_policy_rejects_quick_and_unresolved_physical_state( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: quick_service, _ = service_with_fake_runtime(tmp_path / "quick") _select_connection_mode(quick_service, "quick-connect") quick_binding = _seed_supervised_connection( quick_service, target_ipv4=facade_module.AP_FALLBACK_IPV4, connection_mode="quick-connect", transport_ref="k1-quick", logical_device_id="device-quick", ) quick_control = FakeInteractiveControlSession(initial_state="idle") quick_control.open(connection_binding=quick_binding) quick_control.verified_control = _verified_control_for_binding( quick_binding, logical_device_id="device-quick", control_session_id="test-control-k1-quick", control_proof_revision=2, ) quick_service._application_control_session = quick_control # type: ignore[assignment] # noqa: SLF001 quick_service._reconcile_connection_supervisor( # noqa: SLF001 quick_control.snapshot(), quick_service.runtime.snapshot(), ) quick_service._acquire_application_control_process_lease() # noqa: SLF001 quick_state = quick_service.state() quick_decision = quick_state["connection_policy"]["actions"]["prepare-select-device"] assert quick_decision["allowed"] is False assert "connection-reconfiguration-bridge-only" in quick_decision["reason_codes"] with pytest.raises(facade_module.NetworkProvisioningConflict) as quick_rejected: asyncio.run( quick_service.prepare_connection_reconfiguration( _reconfiguration_request(quick_state, "select-device") ) ) assert quick_rejected.value.reason_code == "connection-reconfiguration-bridge-only" assert quick_control.state == "connection-ready" bridge_service, _ = service_with_fake_runtime(tmp_path / "physical") bridge_control, _binding, _ready = _install_authoritative_ready_bridge_control(bridge_service) monkeypatch.setattr( bridge_service._physical_command_coordinator, # noqa: SLF001 "snapshot", lambda: { "status": "unresolved", "requires_reconciliation": True, "record": None, }, ) unsafe = bridge_service.state() unsafe_decision = unsafe["connection_policy"]["actions"]["prepare-select-device"] assert unsafe_decision["allowed"] is False assert "physical-command-reconciliation-required" in unsafe_decision["reason_codes"] with pytest.raises(facade_module.NetworkProvisioningConflict) as physical_rejected: asyncio.run( bridge_service.prepare_connection_reconfiguration( _reconfiguration_request(unsafe, "select-device") ) ) assert physical_rejected.value.reason_code == ("physical-command-reconciliation-required") assert bridge_control.state == "connection-ready" assert bridge_service._connection_reconfiguration_intent is None # noqa: SLF001 def test_change_network_handoff_pins_exact_active_bridge_transport_without_write( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) control, _binding, ready = _install_authoritative_ready_bridge_control(service) decision = ready["connection_policy"]["actions"]["prepare-change-network"] assert decision["allowed"] is True assert decision["required_transport_ref"] == "k1-a" assert decision["required_connection_mode"] == "bridge" device_edges: list[str] = [] async def forbidden_write(*_: object, **__: object) -> dict[str, Any]: device_edges.append("network-write") raise AssertionError("Prepare must remain local-only") monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_write) monkeypatch.setattr( service._physical_command_coordinator, # noqa: SLF001 "prepare", lambda *_args, **_kwargs: device_edges.append("physical-command"), ) prepared = asyncio.run( service.prepare_connection_reconfiguration( _reconfiguration_request(ready, "change-network") ) ) reconfiguration = prepared["connection_reconfiguration"] assert reconfiguration["intent"] == "change-network" assert reconfiguration["required_transport_ref"] == "k1-a" assert reconfiguration["required_connection_mode"] == "bridge" minimum_generation = reconfiguration["minimum_discovery_generation"] service._ble_discovery_generation = minimum_generation # noqa: SLF001 _set_scanned_k1(service, device_id="k1-a") observed = service.state() assert observed["connection_reconfiguration"]["required_transport_observed"] is True provision = observed["connection_policy"]["actions"]["provision-fresh-device"] assert provision["required_transport_ref"] == "k1-a" assert provision["required_connection_mode"] == "bridge" wrong_target_request = _connect_request( device_id="k1-b", ssid="lab-router", password=SecretStr(PRIMARY_TEST_CREDENTIAL), connection_mode="bridge", compatibility_attestation=ATTESTATION, expected_mode_revision=observed["desired_connection_mode_revision"], expected_discovery_generation=observed["ble_discovery_generation"], expected_reconfiguration_revision=observed["connection_reconfiguration"]["revision"], expected_reconfiguration_intent_id=observed["connection_reconfiguration"]["intent_id"], ) password_reads: list[str] = [] def forbidden_password_read(_secret: SecretStr) -> str: password_reads.append("unwrapped") raise AssertionError("wrong pinned target must fail before password unwrap") monkeypatch.setattr(SecretStr, "get_secret_value", forbidden_password_read) with pytest.raises(facade_module.NetworkProvisioningConflict) as wrong_target: asyncio.run(service.connect(wrong_target_request)) assert wrong_target.value.reason_code == "connection-reconfiguration-target-mismatch" assert password_reads == [] assert service._operations.snapshot() == [] # noqa: SLF001 assert control.stop_calls == 0 assert runtime.start_calls == [] assert runtime.stop_calls == 0 assert device_edges == [] def test_select_device_fresh_verify_consumes_exact_reconfiguration_without_write( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _seed_durable_bridge_topology( service, transport_ref="k1-a", ipv4="10.255.254.20", ) service._pin_or_match_device_identity( # noqa: SLF001 transport_ref="k1-a", logical_device_id="device-a", compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, ) service._pin_or_match_device_identity( # noqa: SLF001 transport_ref="k1-new", logical_device_id="device-b", compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, ) semantic_before = service._semantic_topology_store.snapshot() # type: ignore[union-attr] # noqa: SLF001 assert semantic_before.record is not None assert semantic_before.record.transport_ref == "k1-a" initial = service.state() assert initial["connection_policy"]["actions"]["prepare-select-device"]["allowed"] is True prepared = asyncio.run( service.prepare_connection_reconfiguration( _reconfiguration_request(initial, "select-device") ) ) minimum_generation = prepared["connection_reconfiguration"]["minimum_discovery_generation"] service._ble_discovery_generation = minimum_generation # noqa: SLF001 _set_scanned_k1(service, device_id="k1-new") fresh = service.state() writes: list[str] = [] _install_successful_bridge_verify_transport( monkeypatch, device_id="k1-new", ipv4="10.255.254.77", writes=writes, ) original_bootstrap = service._bootstrap_prestart_control_ready_owned # noqa: SLF001 semantic_during_bootstrap: list[str] = [] async def assert_semantic_commit_is_deferred(**kwargs: object) -> None: before_device_info = service._semantic_topology_store.snapshot() # type: ignore[union-attr] # noqa: SLF001 assert before_device_info.record is not None semantic_during_bootstrap.append(before_device_info.record.transport_ref) await original_bootstrap(**kwargs) # type: ignore[arg-type] after_device_info = service._semantic_topology_store.snapshot() # type: ignore[union-attr] # noqa: SLF001 assert after_device_info.record is not None semantic_during_bootstrap.append(after_device_info.record.transport_ref) monkeypatch.setattr( service, "_bootstrap_prestart_control_ready_owned", assert_semantic_commit_is_deferred, ) verified = asyncio.run( service.verify_connection( ConnectionVerifyRequest( device_id="k1-new", source="fresh-scan", compatibility_attestation=ATTESTATION, expected_discovery_generation=fresh["ble_discovery_generation"], expected_reconfiguration_revision=fresh["connection_reconfiguration"]["revision"], expected_reconfiguration_intent_id=fresh["connection_reconfiguration"]["intent_id"], ) ) ) assert writes == [] assert verified["selected_device_id"] == "k1-new" assert verified["active_connection_mode"] == "bridge" assert verified["connection_reconfiguration"]["status"] == "idle" assert verified["connection_reconfiguration"]["intent_id"] is None assert semantic_during_bootstrap == ["k1-a", "k1-a"] semantic_after = service._semantic_topology_store.snapshot() # type: ignore[union-attr] # noqa: SLF001 assert semantic_after.record is not None assert semantic_after.record.transport_ref == "k1-new" assert semantic_after.record.revision == semantic_before.record.revision + 1 def test_select_device_identity_mismatch_preserves_a_and_cancel_restart_recovers_a( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _seed_durable_bridge_topology( service, transport_ref="k1-a", ipv4="10.255.254.20", ) service._pin_or_match_device_identity( # noqa: SLF001 transport_ref="k1-a", logical_device_id="device-a", compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, ) service._pin_or_match_device_identity( # noqa: SLF001 transport_ref="k1-b", logical_device_id="device-b", compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, ) topology_store = service._semantic_topology_store # noqa: SLF001 pin_store = service._device_identity_pin_store # noqa: SLF001 assert topology_store is not None assert pin_store is not None semantic_before = topology_store.snapshot() pins_before = pin_store.snapshot() prepared = asyncio.run( service.prepare_connection_reconfiguration( _reconfiguration_request(service.state(), "select-device") ) ) service._ble_discovery_generation = prepared["connection_reconfiguration"][ # noqa: SLF001 "minimum_discovery_generation" ] _set_scanned_k1(service, device_id="k1-b") fresh = service.state() writes: list[str] = [] _install_successful_bridge_verify_transport( monkeypatch, device_id="k1-b", ipv4="10.255.254.77", writes=writes, ) # Force the synthetic DeviceInfo proof to present a different logical ID # than B's immutable transport pin. The production reducer then rejects it. monkeypatch.setattr(service, "_expected_vendor_device_id", lambda _ref: None) with pytest.raises(facade_module.ConnectionVerificationError) as mismatch: asyncio.run( service.verify_connection( ConnectionVerifyRequest( device_id="k1-b", source="fresh-scan", compatibility_attestation=ATTESTATION, expected_discovery_generation=fresh["ble_discovery_generation"], expected_reconfiguration_revision=fresh["connection_reconfiguration"][ "revision" ], expected_reconfiguration_intent_id=fresh["connection_reconfiguration"][ "intent_id" ], ) ) ) assert mismatch.value.reason_code == "control-bootstrap-device-identity-unverified" assert writes == [] assert topology_store.snapshot() == semantic_before assert pin_store.snapshot() == pins_before failed = service.state() assert failed["connection_reconfiguration"]["intent"] == "select-device" assert failed["selected_device_id"] is None assert failed["device_session"] is None assert failed["connection_lifecycle"]["active_binding"] is None assert failed["application_control_session"]["state"] == "idle" assert [item["device_id"] for item in failed["devices"]] == ["k1-b"] supervisor = service._connection_supervisor.snapshot() # noqa: SLF001 assert supervisor.authority.control_allowed is False assert not ( supervisor.intent is not None and supervisor.device_network.intent_id == supervisor.intent.intent_id and supervisor.device_network.transport_ref == "k1-b" ) cancelled = asyncio.run( service.prepare_connection_reconfiguration(_reconfiguration_request(failed, "cancel")) ) assert cancelled["connection_reconfiguration"]["status"] == "idle" assert topology_store.snapshot() == semantic_before assert pin_store.snapshot() == pins_before restarted, _ = service_with_fake_runtime(tmp_path) restarted_state = restarted.state() restarted_record = restarted._semantic_topology_store.snapshot().record # type: ignore[union-attr] # noqa: SLF001 assert restarted_record is not None assert restarted_record.transport_ref == "k1-a" assert restarted_state["selected_device_id"] is None assert restarted._configured_endpoint_target().transport_ref == "k1-a" # noqa: SLF001 def test_cold_fresh_bridge_identity_mismatch_keeps_semantic_empty_after_restart( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) service._pin_or_match_device_identity( # noqa: SLF001 transport_ref="k1-b", logical_device_id="device-b", compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, ) topology_store = service._semantic_topology_store # noqa: SLF001 pin_store = service._device_identity_pin_store # noqa: SLF001 assert topology_store is not None assert pin_store is not None assert topology_store.snapshot().status == "empty" pins_before = pin_store.snapshot() _set_scanned_k1(service, device_id="k1-b") fresh = service.state() writes: list[str] = [] _install_successful_bridge_verify_transport( monkeypatch, device_id="k1-b", ipv4="10.255.254.77", writes=writes, ) monkeypatch.setattr(service, "_expected_vendor_device_id", lambda _ref: None) with pytest.raises(facade_module.ConnectionVerificationError) as mismatch: asyncio.run( service.verify_connection( ConnectionVerifyRequest( device_id="k1-b", source="fresh-scan", compatibility_attestation=ATTESTATION, expected_discovery_generation=fresh["ble_discovery_generation"], ) ) ) assert mismatch.value.reason_code == "control-bootstrap-device-identity-unverified" assert writes == [] assert topology_store.snapshot().status == "empty" assert pin_store.snapshot() == pins_before failed = service.state() assert failed["connection_reconfiguration"]["status"] == "idle" assert failed["selected_device_id"] is None assert failed["device_session"] is None assert failed["connection_lifecycle"]["active_binding"] is None assert failed["application_control_session"]["state"] == "idle" assert [item["device_id"] for item in failed["devices"]] == ["k1-b"] restarted, _ = service_with_fake_runtime(tmp_path) restarted_state = restarted.state() assert restarted_state["semantic_topology_store"]["status"] == "empty" assert restarted_state["selected_device_id"] is None def test_cold_fresh_bridge_commits_semantic_only_after_device_info_pin( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) topology_store = service._semantic_topology_store # noqa: SLF001 assert topology_store is not None assert topology_store.snapshot().status == "empty" _set_scanned_k1(service, device_id="k1-cold") fresh = service.state() writes: list[str] = [] _install_successful_bridge_verify_transport( monkeypatch, device_id="k1-cold", ipv4="10.255.254.88", writes=writes, ) original_bootstrap = service._bootstrap_prestart_control_ready_owned # noqa: SLF001 semantic_status_during_bootstrap: list[str] = [] async def assert_cold_commit_is_deferred(**kwargs: object) -> None: semantic_status_during_bootstrap.append(topology_store.snapshot().status) await original_bootstrap(**kwargs) # type: ignore[arg-type] semantic_status_during_bootstrap.append(topology_store.snapshot().status) monkeypatch.setattr( service, "_bootstrap_prestart_control_ready_owned", assert_cold_commit_is_deferred, ) verified = asyncio.run( service.verify_connection( ConnectionVerifyRequest( device_id="k1-cold", source="fresh-scan", compatibility_attestation=ATTESTATION, expected_discovery_generation=fresh["ble_discovery_generation"], ) ) ) assert writes == [] assert semantic_status_during_bootstrap == ["empty", "empty"] record = topology_store.snapshot().record assert record is not None assert record.transport_ref == "k1-cold" assert record.ipv4 == "10.255.254.88" assert record.revision == 1 assert verified["selected_device_id"] == "k1-cold" assert verified["connection_reconfiguration"]["status"] == "idle" assert verified["device_identity_pin_store"]["pin_count"] == 1 def test_select_device_cancel_during_device_info_discards_only_provisional_b( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _seed_durable_bridge_topology( service, transport_ref="k1-a", ipv4="10.255.254.20", ) topology_store = service._semantic_topology_store # noqa: SLF001 assert topology_store is not None semantic_before = topology_store.snapshot() prepared = asyncio.run( service.prepare_connection_reconfiguration( _reconfiguration_request(service.state(), "select-device") ) ) service._ble_discovery_generation = prepared["connection_reconfiguration"][ # noqa: SLF001 "minimum_discovery_generation" ] _set_scanned_k1(service, device_id="k1-b") fresh = service.state() writes: list[str] = [] _install_successful_bridge_verify_transport( monkeypatch, device_id="k1-b", ipv4="10.255.254.77", writes=writes, ) async def scenario() -> None: bootstrap_entered = asyncio.Event() async def paused_device_info(**_: object) -> None: bootstrap_entered.set() await asyncio.Event().wait() monkeypatch.setattr( service, "_bootstrap_prestart_control_ready_owned", paused_device_info, ) verify_task = asyncio.create_task( service.verify_connection( ConnectionVerifyRequest( device_id="k1-b", source="fresh-scan", compatibility_attestation=ATTESTATION, expected_discovery_generation=fresh["ble_discovery_generation"], expected_reconfiguration_revision=fresh["connection_reconfiguration"][ "revision" ], expected_reconfiguration_intent_id=fresh["connection_reconfiguration"][ "intent_id" ], ) ) ) await asyncio.wait_for(bootstrap_entered.wait(), timeout=1.0) projected = service.state() assert projected["selected_device_id"] == "k1-b" assert topology_store.snapshot() == semantic_before verify_task.cancel() with pytest.raises(asyncio.CancelledError): await verify_task asyncio.run(scenario()) assert writes == [] assert topology_store.snapshot() == semantic_before cancelled = service.state() assert cancelled["connection_reconfiguration"]["intent"] == "select-device" assert cancelled["selected_device_id"] is None assert cancelled["device_session"] is None assert cancelled["connection_lifecycle"]["active_binding"] is None assert [item["device_id"] for item in cancelled["devices"]] == ["k1-b"] assert cancelled["last_operation"]["status"] == "cancelled" def test_reconfiguration_aborts_only_purely_local_prepare_without_start_or_stop( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) control, _binding, _ready = _install_authoritative_ready_bridge_control(service) control.state = "workspace-ready" control.state_revision = 1 service._reconcile_connection_supervisor( # noqa: SLF001 control.snapshot(), service.runtime.snapshot(), ) prepared_acquisition = service.prepare_acquisition( _prepare_request( project_name="TEST001", host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) assert prepared_acquisition["acquisition"]["state"] == "prepared" assert control.state == "project-ready" device_edges: list[str] = [] monkeypatch.setattr( service._physical_command_coordinator, # noqa: SLF001 "prepare", lambda *_args, **_kwargs: device_edges.append("physical-command"), ) handed_off = asyncio.run( service.prepare_connection_reconfiguration( _reconfiguration_request(prepared_acquisition, "select-device") ) ) assert handed_off["acquisition"]["state"] == "aborted" assert handed_off["acquisition"]["result"] == { "receiver_started": False, "device_command_attempted": False, "reason_code": "superseded-by-connection-reconfiguration", } assert control.start_projects == [] assert control.stop_calls == 0 assert runtime.start_calls == [] assert runtime.stop_calls == 0 assert device_edges == [] def test_orphaned_prestart_control_retires_on_host_epoch_loss_but_not_transient_tcp( tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) control, _binding, _ready = _install_authoritative_ready_bridge_control(service) supervisor = service._connection_supervisor # noqa: SLF001 before = supervisor.snapshot() changed_path = HostPathProbeResult( available=True, fingerprint="test-route:changed-after-sleep", interface="test0", source_ipv4="192.168.1.2", route_class="direct", ) new_epoch = supervisor.observe_host_path(changed_path) assert new_epoch != before.host_path.epoch assert supervisor.snapshot().control_plane.reason_code == "host-path-epoch-changed" retired = service.state() assert control.state == "idle" assert service._application_control_process_lease_holders == set() # noqa: SLF001 assert retired["connection_policy"]["actions"]["scan-ble"]["allowed"] is True transient_service, _ = service_with_fake_runtime(tmp_path / "transient") transient_control, _binding, _ready = _install_authoritative_ready_bridge_control( transient_service ) transient_supervisor = transient_service._connection_supervisor # noqa: SLF001 transient = transient_supervisor.snapshot() assert transient.intent is not None assert transient.device_network.target is not None assert transient_supervisor.observe_endpoint( target=transient.device_network.target, intent_id=transient.intent.intent_id, host_path_epoch=transient.host_path.epoch, reachable=False, reason_code="tcp-endpoint-unreachable", ) one_negative = transient_service.state() assert transient_control.state == "connection-ready" assert transient_service._application_control_process_lease_holders == { # noqa: SLF001 "control" } assert one_negative["connection_policy"]["actions"]["scan-ble"]["allowed"] is False def test_default_transport_observation_ttl_outlives_one_slow_healthy_monitor_cycle( tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) monotonic_now = [100.0] suspend_aware_now = [1_000.0] supervisor = service._connection_supervisor # noqa: SLF001 supervisor._monotonic_clock = lambda: monotonic_now[0] # noqa: SLF001 supervisor._suspend_aware_clock = lambda: suspend_aware_now[0] # noqa: SLF001 control, _binding, _ready = _install_authoritative_ready_bridge_control(service) # One production pass can consume 11.5 seconds plus its one-second # interval. Observer silence through the former 15-second boundary must # not tear down a verified pre-START owner or fabricate an epoch change. monotonic_now[0] += 10.0 suspend_aware_now[0] += 10.0 delayed = service.state() assert control.state == "connection-ready" assert delayed["active_connection_mode"] == "bridge" assert delayed["connection_lifecycle"]["active_binding_key"] is not None assert supervisor.snapshot().authority.control_allowed is True # The fallback now tolerates two complete bounded monitor passes. monotonic_now[0] += 5.01 suspend_aware_now[0] += 5.01 former_boundary = service.state() assert control.state == "connection-ready" assert former_boundary["active_connection_mode"] == "bridge" assert supervisor.snapshot().authority.control_allowed is True # Complete silence beyond 30 seconds still fails closed. Existing explicit # negative and fingerprint-change tests cover the faster loss paths. monotonic_now[0] += 15.0 suspend_aware_now[0] += 15.0 expired = service.state() assert control.state == "idle" assert expired["active_connection_mode"] is None assert supervisor.snapshot().authority.control_allowed is False def test_orphan_retirement_waits_for_inflight_lifecycle_transition(tmp_path: Path) -> None: service, _ = service_with_fake_runtime(tmp_path) control, _binding, _ready = _install_authoritative_ready_bridge_control(service) supervisor = service._connection_supervisor # noqa: SLF001 supervisor.observe_host_path( HostPathProbeResult( available=True, fingerprint="test-route:bootstrap-race", interface="test0", source_ipv4="192.168.1.2", route_class="direct", ) ) assert service._k1_lifecycle_transition_gate.acquire(blocking=False) # noqa: SLF001 try: service.state() assert control.state == "connection-ready" finally: service._k1_lifecycle_transition_gate.release() # noqa: SLF001 service.state() assert control.state == "idle" def test_mode_select_winner_fences_connect_before_password_or_durable_admission( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) _set_scanned_k1(service, device_id="k1-a") selection_entered = threading.Event() release_selection = threading.Event() selection_failures: list[BaseException] = [] selection_results: list[dict[str, Any]] = [] original_runtime_snapshot = runtime.snapshot paused = False def paused_snapshot() -> dict[str, object]: nonlocal paused if threading.current_thread().name == "reconfigure-mode-winner" and not paused: paused = True selection_entered.set() assert release_selection.wait(2.0) return original_runtime_snapshot() monkeypatch.setattr(runtime, "snapshot", paused_snapshot) def run_selection() -> None: try: selection_results.append( service.select_connection_mode( DesiredConnectionModeRequest( connection_mode="quick-connect", expected_revision=0, ) ) ) except BaseException as exc: # pragma: no cover - assertion aid selection_failures.append(exc) selection_thread = threading.Thread( target=run_selection, name="reconfigure-mode-winner", daemon=True, ) selection_thread.start() assert selection_entered.wait(2.0) password_reads: list[str] = [] losing_request = _connect_request( device_id="k1-a", ssid="lab-router", password=SecretStr(PRIMARY_TEST_CREDENTIAL), connection_mode="bridge", expected_mode_revision=0, expected_discovery_generation=0, compatibility_attestation=ATTESTATION, ) def forbidden_password_read(_secret: SecretStr) -> str: password_reads.append("unwrapped") raise AssertionError("losing Connect must fail before password unwrap") monkeypatch.setattr(SecretStr, "get_secret_value", forbidden_password_read) try: with pytest.raises(facade_module.NetworkProvisioningConflict) as losing_connect: asyncio.run(service.connect(losing_request)) finally: release_selection.set() selection_thread.join(timeout=3.0) assert losing_connect.value.reason_code == "connection-reconfiguration-lifecycle-busy" assert password_reads == [] assert selection_thread.is_alive() is False assert selection_failures == [] assert selection_results[0]["desired_connection_mode"] == "quick-connect" assert service._operations.snapshot() == [] # noqa: SLF001 assert service._network_provisioning_idempotency_journal.snapshot().records == () # noqa: SLF001 def test_bridge_host_association_is_one_shot_and_connection_finishes_ready( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service, device_id="k1-a") writes = 0 associations: list[tuple[str, str]] = [] route_classes = iter(["default-route", "direct-or-routed"]) async def successful_write( *_: object, on_write_dispatch: Callable[[dict[str, Any], str], None] | None = None, **__: object, ) -> dict[str, Any]: nonlocal writes writes += 1 _dispatch_test_network_write(on_write_dispatch) return { "started_at_utc": "2026-08-09T10:00:00Z", "completed_at_utc": "2026-08-09T10:00:01Z", "profile_id": "xgrids-k1-fw3-wifi-v1", "outcome": "lan_address_observed", "write_mode": "with_response", "observations": [ {"status": _wifi_status_read("192.168.68.50", device_id="k1-a")["status"]} ], } monkeypatch.setattr(facade_module, "provision_wifi_once", successful_write) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr(facade_module, "_host_route_class", lambda _target: next(route_classes)) monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) monkeypatch.setattr( facade_module, "associate_with_ephemeral_wifi_credentials_once", lambda _helper, ssid, password, **_kwargs: ( associations.append((ssid, password)) or { "adapter": "CoreWLAN", "outcome": "associated", "already_associated": False, "scan_attempt_count": 1, "scan_elapsed_ms": 25, } ), ) monkeypatch.setattr( facade_module, "_await_control_endpoint_reachable", _reachable_control_endpoint, ) monkeypatch.setattr(facade_module, "_control_endpoint_reachable", lambda _target: True) state = asyncio.run( service.connect( _connect_request( device_id="k1-a", ssid="lab-router", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, allow_host_wifi_switch=True, ) ) ) assert writes == 1 assert associations == [("lab-router", PRIMARY_TEST_CREDENTIAL)] assert state["connection_lifecycle"]["connection_ready"] is True assert state["connection_lifecycle"]["active_mode"] == "bridge" operation = next(item for item in state["operations"] if item["action"] == "network.provision") assert operation["result"]["host_route_class"] is None assert operation["result"]["control_endpoint_reachable"] is None assert operation["result"]["host_wifi_switch_authorized"] is True assert operation["result"]["host_wifi_association_performed"] is True assert PRIMARY_TEST_CREDENTIAL not in str(state) def test_bridge_host_wifi_switch_defaults_to_denied_and_does_not_replay_network_write( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service, device_id="k1-a") writes = 0 association_calls: list[str] = [] async def successful_write( *_: object, on_write_dispatch: Callable[[dict[str, Any], str], None] | None = None, **__: object, ) -> dict[str, Any]: nonlocal writes writes += 1 _dispatch_test_network_write(on_write_dispatch) return { "started_at_utc": "2026-08-09T10:30:00Z", "completed_at_utc": "2026-08-09T10:30:01Z", "profile_id": "xgrids-k1-fw3-wifi-v1", "outcome": "lan_address_observed", "write_mode": "with_response", "observations": [ {"status": _wifi_status_read("192.168.68.50", device_id="k1-a")["status"]} ], } def forbidden_host_association(*_: object, **__: object) -> dict[str, Any]: association_calls.append("attempted") raise AssertionError("Bridge must not switch host Wi-Fi without explicit opt-in") monkeypatch.setattr(facade_module, "provision_wifi_once", successful_write) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr(facade_module, "_host_route_class", lambda _target: "tunnel") monkeypatch.setattr(facade_module, "_inspect_host_path", _tunnel_host_path) monkeypatch.setattr( facade_module, "associate_with_ephemeral_wifi_credentials_once", forbidden_host_association, ) request = _connect_request( device_id="k1-a", ssid="lab-router", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, idempotency_key="bridge-host-switch-default-deny", ) assert request.allow_host_wifi_switch is False first = asyncio.run(service.connect(request)) replay = asyncio.run(service.connect(request)) assert writes == 1 assert association_calls == [] operation = next(item for item in first["operations"] if item["action"] == "network.provision") assert operation["status"] == "succeeded" assert operation["result"]["phase"] == "network_applied" assert operation["result"]["host_wifi_switch_authorized"] is False assert operation["result"]["host_wifi_association_performed"] is False assert operation["result"]["host_wifi_association_outcome"] == "not-authorized" assert first["connection_attempt"]["phase"] == "network_applied" assert first["connection_attempt"]["control_state"] == "unknown" assert first["connection_attempt"]["safe_next_action"] == "wait-for-current-attempt" assert replay["connection_attempt"]["phase"] == "network_applied" assert replay["connection_attempt"]["control_state"] == "unknown" assert replay["connection_attempt"]["safe_next_action"] == "verify-control-read-only" assert PRIMARY_TEST_CREDENTIAL not in str(first) def test_applied_network_bootstrap_failure_recovers_by_verify_without_rewrite( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service, device_id="k1-a") writes = 0 bootstrap_attempts = 0 async def successful_write( *_: object, on_write_dispatch: Callable[[dict[str, Any], str], None] | None = None, **__: object, ) -> dict[str, Any]: nonlocal writes writes += 1 _dispatch_test_network_write(on_write_dispatch) return { "started_at_utc": "2026-08-09T11:00:00Z", "completed_at_utc": "2026-08-09T11:00:01Z", "profile_id": "xgrids-k1-fw3-wifi-v1", "outcome": "lan_address_observed", "write_mode": "with_response", "observations": [ {"status": _wifi_status_read("192.168.68.50", device_id="k1-a")["status"]} ], } async def failed_bootstrap( bound_service: XgridsK1CompatibilityService, *, parent_operation_id: str | None, connection_mode: facade_module.ConnectionMode, inspection_only: bool = False, ) -> None: nonlocal bootstrap_attempts assert inspection_only is True bootstrap_attempts += 1 operation, _ = bound_service._operations.begin( # noqa: SLF001 facade_module.ACTION_CONNECTION_CONTROL_BOOTSTRAP, context={ "connection_mode": connection_mode, "parent_operation_id": parent_operation_id, "automatic_retry": False, }, ) bound_service._operations.transition( # noqa: SLF001 operation.operation_id, "running", stage_code="mqtt-device-info", message_code="connection.control_bootstrap.running", ) failure = facade_module.ConnectionVerificationError( "synthetic DeviceInfo timeout", reason_code="control-bootstrap-timeout", ) bound_service._operations.transition( # noqa: SLF001 operation.operation_id, "failed", stage_code="device-info-failed", message_code="connection.control_bootstrap.failed", error={ "category": "connection", "code": failure.reason_code, "retryable": True, "safe_to_retry": True, "side_effect_status": "none", }, ) raise failure monkeypatch.setattr(facade_module, "provision_wifi_once", successful_write) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr(facade_module, "_host_route_class", lambda _target: "direct-or-routed") monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) monkeypatch.setattr( facade_module, "_await_control_endpoint_reachable", _reachable_control_endpoint, ) monkeypatch.setattr(facade_module, "_control_endpoint_reachable", lambda _target: True) service._bootstrap_prestart_control_ready_owned = MethodType( # type: ignore[method-assign] # noqa: SLF001 failed_bootstrap, service, ) request = _connect_request( device_id="k1-a", ssid="lab-router", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, idempotency_key="applied-network-device-info-recovery", ) failed = asyncio.run(service.connect(request)) assert writes == 1 assert bootstrap_attempts == 1 assert failed["configured_connection_mode"] == "bridge" assert failed["active_connection_mode"] is None assert failed["connection_lifecycle"]["connection_ready"] is False assert failed["connection_attempt"]["status"] == "failed" assert failed["connection_attempt"]["phase"] == "network_applied" assert failed["connection_attempt"]["control_state"] == "control_not_ready" assert failed["connection_attempt"]["safe_next_action"] == "verify-control-read-only" assert failed["network_mutation_ledger"]["resolution"] == "target-observed" assert failed["network_provisioning_idempotency"]["active_operation_id"] is None replayed = asyncio.run(service.connect(request)) assert writes == 1 assert bootstrap_attempts == 1 assert replayed["connection_lifecycle"]["connection_ready"] is False assert replayed["connection_attempt"]["phase"] == "network_applied" assert replayed["connection_attempt"]["control_state"] == "control_not_ready" service._bootstrap_prestart_control_ready_owned = MethodType( # type: ignore[method-assign] # noqa: SLF001 _synthetic_prestart_control_bootstrap, service, ) monkeypatch.setattr( facade_module, "_probe_control_endpoint_socket", lambda _target: facade_module.TcpReachabilityProbeResult(reachable=True), ) monkeypatch.setattr( facade_module, "read_wifi_status_once", lambda *_args, **_kwargs: asyncio.sleep( 0, result=_wifi_status_read("192.168.68.50", device_id="k1-a"), ), ) recovered = asyncio.run(service.verify_connection(ConnectionVerifyRequest())) assert writes == 1 assert recovered["connection_lifecycle"]["connection_ready"] is True assert recovered["connection_lifecycle"]["active_mode"] == "bridge" assert recovered["last_operation"]["action"] == "connection.verify" assert recovered["last_operation"]["status"] == "succeeded" assert recovered["connection_attempt"]["status"] == "succeeded" assert recovered["connection_attempt"]["phase"] == "network_applied" assert recovered["connection_attempt"]["control_state"] == "ready" assert recovered["connection_attempt"]["safe_next_action"] == "start-acquisition" assert ( recovered["connection_attempt"]["recovery_operation_id"] == recovered["last_operation"]["operation_id"] ) semantic_after_verify = service._semantic_topology_store.snapshot() # type: ignore[union-attr] # noqa: SLF001 assert semantic_after_verify.record is not None assert semantic_after_verify.record.source == "ble-read-only-status" restarted_service, _ = service_with_fake_runtime(tmp_path) restarted_replay = asyncio.run(restarted_service.connect(request)) restarted_network = next( item for item in restarted_replay["operations"] if item["action"] == facade_module.ACTION_NETWORK_PROVISION ) assert writes == 1 assert restarted_network["stage_code"] == "durable-terminal-replay" assert restarted_network["result"]["replay_binding_available"] is True assert restarted_network["result"]["target_ipv4"] == "192.168.68.50" assert restarted_replay["connection_attempt"]["control_state"] == "unknown" # A same-UUID advertisement is incidental presence, not a reason to hide # the exact resolved-Apply LAN recovery target or force another GATT read. _set_scanned_k1(restarted_service, device_id="k1-a") advertised_recovery = restarted_service.state() configured_observation = advertised_recovery["connection_policy"]["actions"][ "observe-configured-device-network" ] assert advertised_recovery["current_device_recovery"] is None assert configured_observation["allowed"] is True assert configured_observation["required_transport_ref"] == "k1-a" assert configured_observation["required_connection_mode"] == "bridge" assert configured_observation["requires_live_gatt_validation"] is False assert ( "fresh-candidate-supersedes-durable-recovery" not in configured_observation["reason_codes"] ) durable_ble_reads = 0 async def forbidden_durable_ble_read(*_: object, **__: object) -> dict[str, Any]: nonlocal durable_ble_reads durable_ble_reads += 1 raise AssertionError("resolved Apply recovery must stay LAN/MQTT-only") monkeypatch.setattr( facade_module, "read_wifi_status_once", forbidden_durable_ble_read, ) restarted_verified = asyncio.run( restarted_service.verify_connection( ConnectionVerifyRequest( device_id="k1-a", source="durable-configured-state", compatibility_attestation=ATTESTATION, ) ) ) assert writes == 1 assert durable_ble_reads == 0 assert restarted_verified["last_operation"]["action"] == "connection.verify" assert restarted_verified["last_operation"]["status"] == "succeeded" assert ( restarted_verified["connection_attempt"]["attempt_id"] == restarted_network["operation_id"] ) assert restarted_verified["connection_attempt"]["control_state"] == "ready" assert restarted_verified["connection_attempt"]["safe_next_action"] == ("start-acquisition") @pytest.mark.parametrize( ("mismatched_field", "mismatched_value"), [ ("transport_ref", "foreign-k1"), ("connection_mode", "quick-connect"), ("ipv4", "192.168.68.99"), ("source", "foreign-evidence-source"), ("compatibility_profile_id", "foreign.compatibility.profile"), ], ) def test_resolved_apply_durable_mismatch_blocks_policy_and_verify_without_io( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, mismatched_field: str, mismatched_value: str, ) -> None: service, _ = service_with_fake_runtime(tmp_path) ledger = service._network_mutation_ledger # noqa: SLF001 observation = NetworkStatusEvidence( mode="WIFI_CLIENT", ipv4="192.168.68.50", status_code=1, reserved=0, ) prepared = ledger.prepare( operation_id="resolved-apply-mismatch", transport_ref="k1-a", intended_mode="bridge", write_mode="with_response", baseline_status=NetworkStatusEvidence( mode="WIFI_AP", ipv4="192.168.56.1", status_code=1, reserved=1, ), ) dispatching = ledger.mark_dispatching( prepared.operation_id, expected_revision=prepared.revision, ) observing = ledger.mark_observing( dispatching.operation_id, expected_revision=dispatching.revision, write_confirmed=True, observation=observation, ) ledger.resolve( observing.operation_id, expected_revision=observing.revision, resolution="target-observed", ) topology_store = service._semantic_topology_store # noqa: SLF001 assert topology_store is not None exact_record = topology_store.commit( transport_ref="k1-a", connection_mode="bridge", ipv4="192.168.68.50", compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, firmware_version=ATTESTATION.firmware_version, source="ble-post-write-status", observed_at_utc="2026-08-11T12:00:00Z", ) mismatched_record = exact_record.as_dict() mismatched_record[mismatched_field] = mismatched_value mismatched_snapshot_dict = { "schema_version": "missioncore.xgrids-k1-semantic-topology/v1", "status": "available", "configured_offline_evidence": True, "live_connection_authority": False, "reason_code": None, "record": mismatched_record, } mismatched_snapshot = SimpleNamespace( status="available", record=SimpleNamespace(**mismatched_record), reason_code=None, configured_offline_evidence=True, live_connection_authority=False, as_dict=lambda: mismatched_snapshot_dict, ) monkeypatch.setattr(topology_store, "snapshot", lambda: mismatched_snapshot) calls = {"host_probe": 0, "ble_read": 0, "network_write": 0, "control_open": 0} def forbidden_host_probe(*_: object, **__: object) -> None: calls["host_probe"] += 1 raise AssertionError("mismatched durable target must not probe the host") async def forbidden_ble_read(*_: object, **__: object) -> dict[str, Any]: calls["ble_read"] += 1 raise AssertionError("mismatched durable target must not read BLE") async def forbidden_network_write(*_: object, **__: object) -> dict[str, Any]: calls["network_write"] += 1 raise AssertionError("mismatched durable target must not write the network") def forbidden_control_open(*_: object, **__: object) -> dict[str, object]: calls["control_open"] += 1 raise AssertionError("mismatched durable target must not open control") monkeypatch.setattr( facade_module, "_probe_configured_endpoint_host_only", forbidden_host_probe, ) monkeypatch.setattr(facade_module, "read_wifi_status_once", forbidden_ble_read) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_network_write) monkeypatch.setattr( service._application_control_session, # noqa: SLF001 "open", forbidden_control_open, ) before = service.state() decision = before["connection_policy"]["actions"]["observe-configured-device-network"] assert decision["allowed"] is False assert "resolved-apply-durable-target-mismatch" in decision["reason_codes"] assert decision["required_transport_ref"] is None assert decision.get("required_connection_mode") is None with pytest.raises(facade_module.ConnectionVerificationError) as raised: asyncio.run( service.verify_connection( ConnectionVerifyRequest( device_id="k1-a", source="durable-configured-state", compatibility_attestation=ATTESTATION, ) ) ) assert raised.value.reason_code == ("connection-verify-resolved-apply-target-mismatch") assert calls == { "host_probe": 0, "ble_read": 0, "network_write": 0, "control_open": 0, } after = ledger.snapshot() assert after.record is not None assert after.record.operation_id == "resolved-apply-mismatch" assert after.record.write_confirmed is True assert after.record.resolution == "target-observed" def test_applied_network_bootstrap_cancellation_does_not_cancel_fast_ack_or_rewrite( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service, device_id="k1-a") writes = 0 async def successful_write( *_: object, on_write_dispatch: Callable[[dict[str, Any], str], None] | None = None, **__: object, ) -> dict[str, Any]: nonlocal writes writes += 1 _dispatch_test_network_write(on_write_dispatch) return { "started_at_utc": "2026-08-09T11:30:00Z", "completed_at_utc": "2026-08-09T11:30:01Z", "profile_id": "xgrids-k1-fw3-wifi-v1", "outcome": "lan_address_observed", "write_mode": "with_response", "observations": [ {"status": _wifi_status_read("192.168.68.50", device_id="k1-a")["status"]} ], } def cancelled_control_open(**_: object) -> None: raise asyncio.CancelledError monkeypatch.setattr(facade_module, "provision_wifi_once", successful_write) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr(facade_module, "_host_route_class", lambda _target: "direct-or-routed") monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) monkeypatch.setattr( facade_module, "_await_control_endpoint_reachable", _reachable_control_endpoint, ) monkeypatch.setattr(facade_module, "_control_endpoint_reachable", lambda _target: True) service._bootstrap_prestart_control_ready_owned = MethodType( # type: ignore[method-assign] # noqa: SLF001 XgridsK1CompatibilityService._bootstrap_prestart_control_ready_owned, # noqa: SLF001 service, ) monkeypatch.setattr( service._application_control_session, # noqa: SLF001 "open", cancelled_control_open, ) request = _connect_request( device_id="k1-a", ssid="lab-router", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, idempotency_key="applied-network-device-info-cancelled", ) fast_ack = asyncio.run(service.connect(request)) assert fast_ack["connection_attempt"]["phase"] == "network_applied" cancelled = service.state() assert writes == 1 network_operation = next( item for item in cancelled["operations"] if item["action"] == "network.provision" ) assert network_operation["status"] == "succeeded" assert network_operation["result"]["phase"] == "network_applied" bootstrap_operation = next( item for item in service._operations.snapshot() # noqa: SLF001 if item["action"] == facade_module.ACTION_CONNECTION_CONTROL_BOOTSTRAP ) assert bootstrap_operation["status"] == "cancelled" assert cancelled["connection_attempt"]["phase"] == "network_applied" assert cancelled["connection_attempt"]["control_state"] == "unknown" assert cancelled["connection_attempt"]["safe_next_action"] == ("verify-control-read-only") replayed = asyncio.run(service.connect(request)) assert writes == 1 assert replayed["connection_attempt"]["phase"] == "network_applied" assert replayed["connection_attempt"]["control_state"] == "unknown" def _install_successful_fast_ack_bridge_write( monkeypatch: pytest.MonkeyPatch, ) -> list[str]: writes: list[str] = [] async def successful_write( *_: object, on_write_dispatch: Callable[[dict[str, Any], str], None] | None = None, **__: object, ) -> dict[str, Any]: writes.append("network-write") _dispatch_test_network_write(on_write_dispatch) return { "started_at_utc": "2026-08-11T10:00:00Z", "completed_at_utc": "2026-08-11T10:00:01Z", "profile_id": "xgrids-k1-fw3-wifi-v1", "outcome": "lan_address_observed", "write_mode": "with_response", "observations": [ {"status": _wifi_status_read("192.168.68.50", device_id="k1-a")["status"]} ], } monkeypatch.setattr(facade_module, "provision_wifi_once", successful_write) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) monkeypatch.setattr(facade_module, "_control_endpoint_reachable", lambda _target: True) return writes def test_connect_fast_ack_does_not_wait_for_blocked_endpoint_and_write_is_once( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service, device_id="k1-a") writes = _install_successful_fast_ack_bridge_write(monkeypatch) request = _connect_request( device_id="k1-a", ssid="lab-router", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, idempotency_key="fast-ack-blocked-endpoint-once", ) async def scenario() -> None: endpoint_started = asyncio.Event() release_endpoint = asyncio.Event() async def blocked_endpoint(*_: object, **__: object) -> object: endpoint_started.set() await release_endpoint.wait() path = _direct_host_path("192.168.68.50") service._observe_connection_transport( # noqa: SLF001 "192.168.68.50", path=path, reachable=True, ) return facade_module._CorrelatedEndpointObservation( # noqa: SLF001 path=path, reachable=True, reason_code=None, ) monkeypatch.setattr( facade_module, "_await_control_endpoint_reachable", blocked_endpoint, ) fast_ack = await asyncio.wait_for(service.connect(request), timeout=1.0) assert endpoint_started.is_set() assert writes == ["network-write"] network_operation = next( item for item in fast_ack["operations"] if item["action"] == facade_module.ACTION_NETWORK_PROVISION ) assert network_operation["status"] == "succeeded" assert network_operation["stage_code"] == "network-configured" assert network_operation["result"]["phase"] == "network_applied" assert network_operation["result"]["control_state"] == "unknown" assert network_operation["result"]["host_route_ready"] is None assert network_operation["result"]["control_endpoint_reachable"] is None assert fast_ack["connection_attempt"]["control_state"] == "unknown" assert fast_ack["connection_attempt"]["safe_next_action"] == ("wait-for-current-attempt") with service._lock: # noqa: SLF001 continuation_task = service._control_bootstrap_continuation_task # noqa: SLF001 assert continuation_task is not None assert not continuation_task.done() release_endpoint.set() await asyncio.wait_for(asyncio.shield(continuation_task), timeout=1.0) ready = service.state() assert ready["connection_attempt"]["control_state"] == "ready" assert ready["connection_attempt"]["safe_next_action"] == "start-acquisition" replay = await service.connect(request) assert writes == ["network-write"] assert replay["connection_attempt"]["phase"] == "network_applied" asyncio.run(scenario()) def test_connect_fast_ack_does_not_wait_for_blocked_device_info( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service, device_id="k1-a") writes = _install_successful_fast_ack_bridge_write(monkeypatch) monkeypatch.setattr( facade_module, "_await_control_endpoint_reachable", _reachable_control_endpoint, ) synthetic_bootstrap = service._bootstrap_prestart_control_ready_owned # noqa: SLF001 request = _connect_request( device_id="k1-a", ssid="lab-router", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, idempotency_key="fast-ack-blocked-device-info", ) async def scenario() -> None: device_info_started = asyncio.Event() release_device_info = asyncio.Event() async def blocked_bootstrap( _service: XgridsK1CompatibilityService, *, parent_operation_id: str | None, connection_mode: facade_module.ConnectionMode, inspection_only: bool = False, ) -> None: device_info_started.set() await release_device_info.wait() await synthetic_bootstrap( parent_operation_id=parent_operation_id, connection_mode=connection_mode, inspection_only=inspection_only, ) service._bootstrap_prestart_control_ready_owned = MethodType( # type: ignore[method-assign] # noqa: SLF001 blocked_bootstrap, service, ) fast_ack = await asyncio.wait_for(service.connect(request), timeout=1.0) assert device_info_started.is_set() assert writes == ["network-write"] assert fast_ack["connection_attempt"]["status"] == "running" assert fast_ack["connection_attempt"]["control_state"] == "unknown" assert fast_ack["connection_attempt"]["safe_next_action"] == ("wait-for-current-attempt") with service._lock: # noqa: SLF001 continuation_task = service._control_bootstrap_continuation_task # noqa: SLF001 assert continuation_task is not None release_device_info.set() await asyncio.wait_for(asyncio.shield(continuation_task), timeout=1.0) assert service.state()["connection_attempt"]["control_state"] == "ready" asyncio.run(scenario()) @pytest.mark.parametrize("observed_state", ["ready", "scanning"]) def test_reset_retired_apply_continuation_settles_without_receiver_rehydrate( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, observed_state: str, ) -> None: """A reset-owned Apply settles physical truth without reviving capture.""" service, runtime = service_with_fake_runtime(tmp_path) old_binding = _seed_supervised_connection( service, transport_ref="k1-a", logical_device_id="k1-a", ) _seed_unresolved_physical_stop_for_retirement(service, old_binding) reset = service.select_connection_mode( DesiredConnectionModeRequest( connection_mode="bridge", expected_revision=service.state()["desired_connection_mode_revision"], reset_scenario=True, reset_id="reset-retired-apply-scanning-stop-only-0001", ) ) async def fresh_scan( _duration_seconds: float, *, on_admitted: Callable[[], None] | None = None, ) -> dict[str, Any]: assert on_admitted is not None on_admitted() return _ble_scan_result("k1-a") monkeypatch.setattr(facade_module, "scan", fresh_scan) scanned = asyncio.run(service.scan_ble(BleScanRequest(duration_seconds=1.0))) _set_scanned_k1(service, device_id="k1-a") writes = _install_successful_fast_ack_bridge_write(monkeypatch) monkeypatch.setattr( facade_module, "_await_control_endpoint_reachable", _reachable_control_endpoint, ) synthetic_bootstrap = service._bootstrap_prestart_control_ready_owned # noqa: SLF001 coordinator = service._physical_command_coordinator # noqa: SLF001 inspection_modes: list[bool] = [] async def physical_bootstrap( bound_service: XgridsK1CompatibilityService, *, parent_operation_id: str | None, connection_mode: facade_module.ConnectionMode, inspection_only: bool = False, ) -> None: inspection_modes.append(inspection_only) assert inspection_only is True coordinator.prepare_read_only_bootstrap() coordinator.application_response( ApplicationMqttResponseEvidence( operation_key=f"bootstrap:{parent_operation_id}:DeviceInfoRequest", response_topic="lixel/application/response/device_info", payload_sha256="7" * 64, modeling_action=None, result_code=None, success=None, observed_at_utc="2026-08-14T08:30:00.000Z", ) ) await synthetic_bootstrap( parent_operation_id=parent_operation_id, connection_mode=connection_mode, inspection_only=inspection_only, ) verified = bound_service._application_control_session.snapshot().get( # noqa: SLF001 "verified_control" ) assert isinstance(verified, dict) reopened = bound_service._physical_command_ledger.snapshot().record # noqa: SLF001 assert reopened is not None assert reopened.stage == "observing" coordinator.bind_control_session( PhysicalCommandRuntimeBinding( vendor_device_id_sha256=( reopened.identity.vendor_device_id_sha256 ), device_serial_sha256=reopened.identity.device_serial_sha256, compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, intent_id=str(verified["intent_id"]), transport_ref=str(verified["transport_ref"]), connection_mode=verified["connection_mode"], # type: ignore[arg-type] target_ipv4=str(verified["target_ipv4"]), target_port=int(verified["target_port"]), host_path_epoch=int(verified["host_path_epoch"]), control_session_id=str(verified["control_session_id"]), producer_generation=int(verified["producer_generation"]), ) ) coordinator.device_status( ApplicationMqttDeviceStatusEvidence( vendor_device_id_sha256=( reopened.identity.vendor_device_id_sha256 ), device_serial_sha256=reopened.identity.device_serial_sha256, session_state=observed_state, # type: ignore[arg-type] session_state_code=( MODELING_STATE_BASE + (302 if observed_state == "scanning" else 300) ), project_bound=observed_state == "scanning", project_id_sha256=( "8" * 64 if observed_state == "scanning" else None ), init_ready=observed_state == "scanning", status_message_sha256="9" * 64, mqtt_retained=False, observed_at_utc="2026-08-14T08:30:01.000Z", ) ) bound_service._acquire_application_control_process_lease() # noqa: SLF001 async def forbidden_receiver_rehydrate(**_kwargs: object) -> None: pytest.fail("reset-owned SCANNING settlement must not recreate a receiver") service._bootstrap_prestart_control_ready_owned = MethodType( # type: ignore[method-assign] # noqa: SLF001 physical_bootstrap, service, ) monkeypatch.setattr( service, "_rehydrate_active_acquisition_after_restart", forbidden_receiver_rehydrate, ) request = _connect_request( device_id="k1-a", ssid="lab-router", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, idempotency_key="reset-retired-apply-scanning-stop-only", operation_id="op-00000000-0000-4000-8000-000000001401", expected_mode_revision=reset["desired_connection_mode_revision"], expected_discovery_generation=scanned["ble_discovery_generation"], ) async def scenario() -> tuple[ dict[str, Any], dict[str, Any], dict[str, Any] | None, ]: applied = await service.connect(request) with service._lock: # noqa: SLF001 continuation_task = service._control_bootstrap_continuation_task # noqa: SLF001 if continuation_task is not None: await asyncio.wait_for(asyncio.shield(continuation_task), timeout=1.0) settled = service.state() await service.connect(request.model_copy(update={"operation_id": None})) successor: dict[str, Any] | None = None if observed_state == "ready": with pytest.raises(facade_module.NetworkProvisioningConflict) as stale: await service.connect( request.model_copy( update={ "operation_id": None, "ssid": "changed-without-reconfiguration", } ) ) assert stale.value.reason_code == "physical-command-target-retired" prepared = await service.prepare_connection_reconfiguration( _reconfiguration_request(settled, "change-network") ) fresh = await service.scan_ble(BleScanRequest(duration_seconds=1.0)) _set_scanned_k1(service, device_id="k1-a") monkeypatch.setattr( service, "_schedule_control_bootstrap_continuation", lambda **_kwargs: None, ) successor = await service.connect( _connect_request( device_id="k1-a", ssid="new-lab-router", password=SecretStr(SECONDARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, idempotency_key="reset-ready-explicit-change-network-successor", operation_id="op-00000000-0000-4000-8000-000000001402", expected_mode_revision=prepared[ "desired_connection_mode_revision" ], expected_discovery_generation=fresh[ "ble_discovery_generation" ], expected_reconfiguration_revision=fresh[ "connection_reconfiguration" ]["revision"], expected_reconfiguration_intent_id=fresh[ "connection_reconfiguration" ]["intent_id"], ) ) return applied, settled, successor applied, settled, successor = asyncio.run(scenario()) physical = settled["physical_command"] control = settled["application_control_session"] acquisition = settled["acquisition"] assert applied["connection_attempt"]["phase"] == "network_applied" assert inspection_modes == [True] assert writes == ( ["network-write", "network-write"] if observed_state == "ready" else ["network-write"] ) expected_resolution = ( "physical-active-observed" if observed_state == "scanning" else "physical-standby-observed" ) assert physical["record"]["resolution"] == expected_resolution assert physical["requires_reconciliation"] is False assert physical["resolved_active_recovery_required"] is ( observed_state == "scanning" ) if observed_state == "scanning": assert control["state"] == "scanning" assert control["inspection_only"] is True assert control["can_stop"] is True assert control["can_start"] is False assert acquisition["state"] == "failed" assert acquisition["requested_streams"] == [] assert acquisition["result"]["recovery_only"] is True assert settled["connection_attempt"]["safe_next_action"] == "stop-acquisition" assert settled["connection_policy"]["actions"]["stop-acquisition"]["allowed"] is True assert settled["connection_policy"]["actions"]["start-acquisition"]["allowed"] is False authority = service._connection_scenario_reset_retired_transport_authority # noqa: SLF001 assert authority is not None synthetic_standby = { **physical, "status": "resolved", "requires_reconciliation": False, "resolved_active_recovery_required": False, "reconciled_physical_state": "standby", "physical_active": False, "observed_session_state": "ready", "record": { **physical["record"], "resolution": "stop-standby-observed", }, } with service._lock: # noqa: SLF001 assert ( service._consumed_reset_authority_has_safe_reconfiguration_successor_locked( # noqa: SLF001 authority=authority, physical=physical, request=request, ) is False ) # Even after a later STOP proves standby, the old request itself # still lacks a separately committed Change Network generation. assert ( service._consumed_reset_authority_has_safe_reconfiguration_successor_locked( # noqa: SLF001 authority=authority, physical=synthetic_standby, request=request, ) is False ) service._connection_reconfiguration_revision += 1 # noqa: SLF001 service._connection_reconfiguration_intent_id = ( # noqa: SLF001 "change-network-after-explicit-stop" ) service._connection_reconfiguration_intent = "change-network" # noqa: SLF001 service._connection_reconfiguration_required_transport_ref = "k1-a" # noqa: SLF001 service._connection_reconfiguration_required_connection_mode = "bridge" # noqa: SLF001 service._ble_discovery_generation += 1 # noqa: SLF001 service._connection_reconfiguration_minimum_discovery_generation = ( # noqa: SLF001 service._ble_discovery_generation # noqa: SLF001 ) successor_request = request.model_copy( update={ "operation_id": None, "ssid": "new-network-after-explicit-stop", "idempotency_key": "new-key-after-explicit-stop", "expected_discovery_generation": ( service._ble_discovery_generation # noqa: SLF001 ), "expected_reconfiguration_revision": ( service._connection_reconfiguration_revision # noqa: SLF001 ), "expected_reconfiguration_intent_id": ( service._connection_reconfiguration_intent_id # noqa: SLF001 ), } ) assert service._consumed_reset_authority_has_safe_reconfiguration_successor_locked( # noqa: SLF001 authority=authority, physical=synthetic_standby, request=successor_request, ) else: assert control["state"] == "connection-ready" assert control["inspection_only"] is True assert control["inspection_promotion_allowed"] is True assert settled["connection_attempt"]["safe_next_action"] == ( "start-acquisition" ) assert successor is not None assert successor["last_operation"]["status"] == "succeeded" assert service._connection_scenario_reset_retired_transport_authority is None # noqa: SLF001 assert runtime.phase == "idle" assert runtime.source_mode == "idle" assert runtime.start_calls == [] assert service._acquisition_session_lease is None # noqa: SLF001 assert service.camera_preview.snapshot()["phase"] == "idle" assert service._live_perception_camera_binding is None # noqa: SLF001 @pytest.mark.parametrize("supersession", ["intent", "runtime"]) def test_control_bootstrap_continuation_cannot_publish_stale_parent_proof( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, supersession: str, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service, device_id="k1-a") writes = _install_successful_fast_ack_bridge_write(monkeypatch) request = _connect_request( device_id="k1-a", ssid="lab-router", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, idempotency_key=f"fast-ack-stale-{supersession}", ) async def scenario() -> None: endpoint_started = asyncio.Event() release_endpoint = asyncio.Event() async def blocked_endpoint(*_: object, **__: object) -> object: endpoint_started.set() await release_endpoint.wait() return facade_module._CorrelatedEndpointObservation( # noqa: SLF001 path=_direct_host_path("192.168.68.50"), reachable=True, reason_code=None, ) monkeypatch.setattr( facade_module, "_await_control_endpoint_reachable", blocked_endpoint, ) fast_ack = await service.connect(request) assert endpoint_started.is_set() with service._lock: # noqa: SLF001 continuation_task = service._control_bootstrap_continuation_task # noqa: SLF001 if supersession == "runtime": service._snapshot_runtime_id = "snapshot-runtime-superseded" # noqa: SLF001 assert continuation_task is not None if supersession == "intent": service._connection_supervisor.set_intent( # noqa: SLF001 intent_id="explicit-new-intent", requested_mode="bridge", ) release_endpoint.set() with pytest.raises(facade_module.ConnectionVerificationError): await asyncio.wait_for(asyncio.shield(continuation_task), timeout=1.0) state = service.state() assert writes == ["network-write"] assert fast_ack["connection_attempt"]["phase"] == "network_applied" assert state["connection_attempt"]["phase"] == "network_applied" assert state["connection_attempt"]["control_state"] == "control_not_ready" assert state["connection_attempt"]["safe_next_action"] == ("verify-control-read-only") assert state["network_mutation_ledger"]["resolution"] == "target-observed" asyncio.run(scenario()) def test_service_close_cancels_owned_control_bootstrap_without_rewriting_network( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service, device_id="k1-a") writes = _install_successful_fast_ack_bridge_write(monkeypatch) request = _connect_request( device_id="k1-a", ssid="lab-router", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, idempotency_key="fast-ack-service-close-owns-child", ) async def scenario() -> None: endpoint_started = asyncio.Event() async def blocked_endpoint(*_: object, **__: object) -> object: endpoint_started.set() await asyncio.Event().wait() monkeypatch.setattr( facade_module, "_await_control_endpoint_reachable", blocked_endpoint, ) fast_ack = await service.connect(request) assert endpoint_started.is_set() with service._lock: # noqa: SLF001 continuation_task = service._control_bootstrap_continuation_task # noqa: SLF001 continuation = service._control_bootstrap_continuation # noqa: SLF001 assert continuation_task is not None assert continuation is not None service.close() with pytest.raises(asyncio.CancelledError): await continuation_task child = service._operations.get(continuation.operation_id).as_dict() # noqa: SLF001 network = service._operations.get(continuation.parent_operation_id).as_dict() # noqa: SLF001 assert child["status"] == "cancelled" assert network["status"] == "succeeded" assert network["result"]["phase"] == "network_applied" assert fast_ack["connection_attempt"]["phase"] == "network_applied" assert writes == ["network-write"] asyncio.run(scenario()) def test_control_bootstrap_final_fence_rejects_supersession_during_device_info( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service, device_id="k1-a") writes = _install_successful_fast_ack_bridge_write(monkeypatch) monkeypatch.setattr( facade_module, "_await_control_endpoint_reachable", _reachable_control_endpoint, ) control = FakeInteractiveControlSession(initial_state="idle") original_open = control.open def open_with_exact_identity( *, connection_binding: ApplicationConnectionBinding, **kwargs: object, ) -> dict[str, object]: snapshot = original_open(connection_binding=connection_binding, **kwargs) intent = service._connection_supervisor.snapshot().intent # noqa: SLF001 assert intent is not None control.verified_control = _verified_control_for_binding( connection_binding, logical_device_id=str(intent.expected_device_id or service._device_id), # noqa: SLF001 ) return snapshot monkeypatch.setattr(control, "open", open_with_exact_identity) service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 production_bootstrap = MethodType( XgridsK1CompatibilityService._bootstrap_prestart_control_ready_owned, # noqa: SLF001 service, ) request = _connect_request( device_id="k1-a", ssid="lab-router", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, idempotency_key="fast-ack-device-info-final-fence", ) async def scenario() -> None: device_info_ready = asyncio.Event() release_device_info = asyncio.Event() async def ready_then_block( _service: XgridsK1CompatibilityService, *, parent_operation_id: str | None, connection_mode: facade_module.ConnectionMode, inspection_only: bool = False, ) -> None: await production_bootstrap( parent_operation_id=parent_operation_id, connection_mode=connection_mode, inspection_only=inspection_only, ) device_info_ready.set() await release_device_info.wait() service._bootstrap_prestart_control_ready_owned = MethodType( # type: ignore[method-assign] # noqa: SLF001 ready_then_block, service, ) fast_ack = await service.connect(request) await asyncio.wait_for(device_info_ready.wait(), timeout=1.0) with service._lock: # noqa: SLF001 continuation_task = service._control_bootstrap_continuation_task # noqa: SLF001 continuation = service._control_bootstrap_continuation # noqa: SLF001 assert continuation_task is not None assert continuation is not None child_before_release = service._operations.get( # noqa: SLF001 continuation.operation_id ).as_dict() assert child_before_release["status"] == "running" service._connection_supervisor.record_monitor_failure( # noqa: SLF001 "test-route-lost-during-device-info" ) release_device_info.set() with pytest.raises(facade_module.ConnectionVerificationError): await asyncio.wait_for(asyncio.shield(continuation_task), timeout=1.0) child = service._operations.get(continuation.operation_id).as_dict() # noqa: SLF001 network = service._operations.get(continuation.parent_operation_id).as_dict() # noqa: SLF001 state = service.state() assert child["status"] == "failed" assert network["status"] == "succeeded" assert network["result"]["phase"] == "network_applied" assert fast_ack["connection_attempt"]["phase"] == "network_applied" assert state["connection_attempt"]["control_state"] == "control_not_ready" assert state["connection_attempt"]["safe_next_action"] != "start-acquisition" assert control.state in {"closed", "idle"} assert writes == ["network-write"] asyncio.run(scenario()) def test_historical_bootstrap_success_loses_ready_projection_with_live_route( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service, device_id="k1-a") writes = _install_successful_fast_ack_bridge_write(monkeypatch) monkeypatch.setattr( facade_module, "_await_control_endpoint_reachable", _reachable_control_endpoint, ) request = _connect_request( device_id="k1-a", ssid="lab-router", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, idempotency_key="fast-ack-live-authority-loss", ) async def scenario() -> None: await service.connect(request) with service._lock: # noqa: SLF001 continuation_task = service._control_bootstrap_continuation_task # noqa: SLF001 if continuation_task is not None: await asyncio.wait_for(asyncio.shield(continuation_task), timeout=1.0) ready = service.state() assert ready["connection_attempt"]["control_state"] == "ready" assert ready["connection_attempt"]["safe_next_action"] == "start-acquisition" service._connection_supervisor.record_monitor_failure( # noqa: SLF001 "test-route-loss-after-bootstrap-success" ) lost = service.state() child = next( item for item in service._operations.snapshot() # noqa: SLF001 if item["action"] == facade_module.ACTION_CONNECTION_CONTROL_BOOTSTRAP and item.get("context", {}).get("ownership") == "service-owned-apply-continuation" ) assert child["status"] == "succeeded" assert lost["connection_attempt"]["control_state"] == "control_not_ready" assert lost["connection_attempt"]["safe_next_action"] != "start-acquisition" assert lost["connection_lifecycle"]["ready_to_start"] is False assert writes == ["network-write"] asyncio.run(scenario()) def test_control_bootstrap_cancelled_before_first_step_is_never_left_accepted( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service, device_id="k1-a") writes = _install_successful_fast_ack_bridge_write(monkeypatch) monkeypatch.setattr( facade_module, "_await_control_endpoint_reachable", _reachable_control_endpoint, ) request = _connect_request( device_id="k1-a", ssid="lab-router", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, idempotency_key="fast-ack-cancel-before-first-step", ) async def scenario() -> None: connected = await service.connect(request) with service._lock: # noqa: SLF001 first_task = service._control_bootstrap_continuation_task # noqa: SLF001 if first_task is not None: await asyncio.wait_for(asyncio.shield(first_task), timeout=1.0) await asyncio.sleep(0) network = next( item for item in connected["operations"] if item["action"] == facade_module.ACTION_NETWORK_PROVISION ) result = network["result"] service._schedule_control_bootstrap_continuation( # noqa: SLF001 parent_operation_id=network["operation_id"], connection_mode=result["connection_mode"], transport_ref=result["transport_ref"], target=facade_module.EndpointTarget( result["target_ipv4"], result["target_port"], ), device_session_id=result["device_session_id"], ) with service._lock: # noqa: SLF001 cancelled_task = service._control_bootstrap_continuation_task # noqa: SLF001 cancelled_continuation = service._control_bootstrap_continuation # noqa: SLF001 assert cancelled_task is not None assert cancelled_continuation is not None # No await has occurred since create_task: the coroutine has not entered. service._request_control_bootstrap_continuation_close() # noqa: SLF001 with pytest.raises(asyncio.CancelledError): await cancelled_task await asyncio.sleep(0) child = service._operations.get( # noqa: SLF001 cancelled_continuation.operation_id ).as_dict() assert child["status"] == "cancelled" assert child["stage_code"] == "control-bootstrap-cancelled" with service._lock: # noqa: SLF001 assert service._control_bootstrap_continuation is None # noqa: SLF001 assert service._control_bootstrap_continuation_task is None # noqa: SLF001 assert service._control_bootstrap_continuation_loop is None # noqa: SLF001 assert writes == ["network-write"] asyncio.run(scenario()) def _seed_terminal_network_attempt( service: XgridsK1CompatibilityService, ) -> None: operation, created = service._operations.begin( # noqa: SLF001 facade_module.ACTION_NETWORK_PROVISION, operation_id="op-00000000-0000-4000-8000-000000009901", context={ "snapshot_runtime_id": service.state()["snapshot_runtime_id"], "transport_ref": "terminal-attempt-k1", "connection_mode": "bridge", }, ) assert created is True service._operations.transition( # noqa: SLF001 operation.operation_id, "running", stage_code="ble-provisioning-write", message_code="connection.network.running", ) service._operations.transition( # noqa: SLF001 operation.operation_id, "succeeded", stage_code="network-configured", message_code="connection.network.succeeded", result={ "phase": "network_applied", "side_effect_status": "applied", "automatic_retry": False, }, ) def test_terminal_connection_attempt_projects_current_local_cleanup_not_wait( tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) _seed_terminal_network_attempt(service) runtime.source_mode = "live" runtime.phase = "error" state = service.state() assert state["connection_attempt"]["status"] == "succeeded" assert state["connection_policy"]["actions"]["stop-local-receiver"]["allowed"] is True assert state["connection_attempt"]["safe_next_action"] == ("stop-local-receiver") assert ( state["connection_attempt"]["diagnostic_bundle"]["attempt"]["safe_next_action"] == "stop-local-receiver" ) def test_terminal_connection_attempt_without_allowed_action_never_claims_wait_or_scan( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) _seed_terminal_network_attempt(service) monkeypatch.setattr( facade_module, "ble_runtime_snapshot", lambda: { "owner_epoch": 9, "owner_loop_bound": False, "active_operation_kind": "status-read", "cleanup_pending": True, "poisoned": True, }, ) state = service.state() assert state["connection_attempt"]["status"] == "succeeded" assert state["connection_policy"]["actions"]["scan-ble"]["allowed"] is False assert state["connection_policy"]["actions"]["stop-local-receiver"]["allowed"] is False assert state["connection_attempt"]["safe_next_action"] == ("manual-recovery-required") def test_connection_attempt_projection_never_starts_without_ready_control() -> None: runtime_id = "snapshot-runtime-test" network_operation_id = "op-00000000-0000-4000-8000-000000000001" network_operation = { "operation_id": network_operation_id, "action": facade_module.ACTION_NETWORK_PROVISION, "status": "succeeded", "stage_code": "network-configured", "context": { "snapshot_runtime_id": runtime_id, "transport_ref": "k1-a", "connection_mode": "bridge", }, "result": { "phase": "network_applied", "control_state": "unknown", "snapshot_runtime_id": runtime_id, "parent_intent_id": network_operation_id, "transport_ref": "k1-a", "connection_mode": "bridge", "target_ipv4": "192.168.68.50", "target_port": facade_module.CONTROL_MQTT_PORT, }, "events": [], } without_child = facade_module._connection_attempt_projection([network_operation]) # noqa: SLF001 assert without_child is not None assert without_child["control_state"] == "unknown" assert without_child["safe_next_action"] == "verify-control-read-only" foreign_child = { "operation_id": "op-00000000-0000-4000-8000-000000000002", "action": facade_module.ACTION_CONNECTION_CONTROL_BOOTSTRAP, "status": "running", "stage_code": "mqtt-device-info", "context": { "parent_operation_id": network_operation["operation_id"], "connection_mode": "bridge", }, "events": [], } foreign = facade_module._connection_attempt_projection( # noqa: SLF001 [network_operation, foreign_child] ) assert foreign is not None assert foreign["safe_next_action"] == "verify-control-read-only" owned_child = { **foreign_child, "context": { "ownership": "service-owned-apply-continuation", "snapshot_runtime_id": runtime_id, "parent_operation_id": network_operation["operation_id"], "parent_intent_id": network_operation["operation_id"], "connection_mode": "bridge", "transport_ref": "k1-a", "target_ipv4": "192.168.68.50", "target_port": facade_module.CONTROL_MQTT_PORT, "device_session_id": "device-session-test", "network_mutation_performed": False, "ble_operation_performed": False, "automatic_retry": False, }, } owned = facade_module._connection_attempt_projection( # noqa: SLF001 [network_operation, owned_child] ) assert owned is not None assert owned["control_state"] == "unknown" assert owned["safe_next_action"] == "wait-for-current-attempt" ready_child = { **owned_child, "status": "succeeded", "result": { "connection_mode": "bridge", "control_verified": True, "network_mutation_performed": False, "ble_operation_performed": False, "automatic_retry": False, }, } ready = facade_module._connection_attempt_projection( # noqa: SLF001 [network_operation, ready_child] ) assert ready is not None assert ready["control_state"] == "ready" assert ready["safe_next_action"] == "start-acquisition" scanning_child = { **ready_child, "result": { **ready_child["result"], "physical_reconciliation": { "performed": True, "resolution": "physical-active-observed", "observed_session_state": "scanning", "device_write_performed": False, "automatic_retry": False, }, }, } scanning = facade_module._connection_attempt_projection( # noqa: SLF001 [network_operation, scanning_child] ) assert scanning is not None assert scanning["control_state"] == "unknown" assert scanning["safe_next_action"] == "stop-acquisition" assert scanning["safe_next_action"] != "start-acquisition" assert scanning["physical_reconciliation"] == ( scanning_child["result"]["physical_reconciliation"] ) foreign_verify = { "operation_id": "op-00000000-0000-4000-8000-000000000003", "action": facade_module.ACTION_CONNECTION_VERIFY, "status": "succeeded", "stage_code": "device-info-confirmed", "context": { "snapshot_runtime_id": runtime_id, "requested_transport_ref": "other-k1", "requested_connection_mode": "quick-connect", }, "result": { "write_performed": False, "control_verified": True, "verified_binding": { "snapshot_runtime_id": runtime_id, "intent_id": "foreign-intent", "transport_ref": "other-k1", "connection_mode": "quick-connect", "target_ipv4": "192.168.43.1", "target_port": facade_module.CONTROL_MQTT_PORT, "host_path_epoch": 2, }, }, "events": [], } foreign_verify_projection = facade_module._connection_attempt_projection( # noqa: SLF001 [network_operation, foreign_verify] ) assert foreign_verify_projection is not None assert foreign_verify_projection["control_state"] == "unknown" assert foreign_verify_projection["safe_next_action"] == "verify-control-read-only" exact_verify_context = { "snapshot_runtime_id": runtime_id, "recovery_parent_operation_id": network_operation_id, "recovery_parent_intent_id": network_operation_id, "recovery_transport_ref": "k1-a", "recovery_connection_mode": "bridge", "recovery_target_ipv4": "192.168.68.50", "recovery_target_port": facade_module.CONTROL_MQTT_PORT, } exact_verify = { **foreign_verify, "status": "running", "context": exact_verify_context, "result": None, } exact_pending = facade_module._connection_attempt_projection( # noqa: SLF001 [network_operation, exact_verify] ) assert exact_pending is not None assert exact_pending["control_state"] == "unknown" assert exact_pending["safe_next_action"] == "wait-for-current-attempt" wrong_verify_binding = { **exact_verify, "status": "succeeded", "result": foreign_verify["result"], } wrong_verify = facade_module._connection_attempt_projection( # noqa: SLF001 [network_operation, wrong_verify_binding] ) assert wrong_verify is not None assert wrong_verify["control_state"] == "unknown" assert wrong_verify["safe_next_action"] == "verify-control-read-only" exact_verify_success = { **exact_verify, "status": "succeeded", "result": { "write_performed": False, "control_verified": True, "verified_binding": { "snapshot_runtime_id": runtime_id, "intent_id": "durable-read-only-verify-intent", "transport_ref": "k1-a", "connection_mode": "bridge", "target_ipv4": "192.168.68.50", "target_port": facade_module.CONTROL_MQTT_PORT, "host_path_epoch": 2, }, }, } exact_ready = facade_module._connection_attempt_projection( # noqa: SLF001 [network_operation, exact_verify_success] ) assert exact_ready is not None assert exact_ready["control_state"] == "ready" assert exact_ready["safe_next_action"] == "start-acquisition" def test_connect_reconfiguration_admission_fences_mode_selection_before_transition_gate( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: """Connect's pre-secret semantic admission is one deterministic winner.""" service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service, device_id="k1-a") borrow_entered = threading.Event() release_borrow = threading.Event() connect_failures: list[BaseException] = [] device_writes: list[str] = [] @contextmanager def paused_network_ble_borrow() -> Iterator[object]: # Connect has passed its semantic admission and retains the # reconfiguration gate across durable journal creation. Mode Select # cannot publish a stale draft in this pre-transition interval. borrow_entered.set() assert release_borrow.wait(2.0) raise RuntimeError("synthetic admitted Connect ended before BLE") yield object() # pragma: no cover - contextmanager generator marker async def forbidden_device_write(*_: object, **__: object) -> dict[str, Any]: device_writes.append("gatt-write") raise AssertionError("stale mode Connect crossed the GATT boundary") monkeypatch.setattr( service, "_borrow_network_ble_process_lease", paused_network_ble_borrow, ) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_device_write) request = _connect_request( device_id="k1-a", ssid="lab-router", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, idempotency_key="connect-admission-wins-before-mode-selection", ) def run_connect() -> None: try: asyncio.run(service.connect(request)) except BaseException as exc: # pragma: no branch - expected contract edge connect_failures.append(exc) connect_thread = threading.Thread(target=run_connect, daemon=True) connect_thread.start() assert borrow_entered.wait(2.0) try: with pytest.raises(facade_module.NetworkProvisioningConflict) as blocked: service.select_connection_mode( DesiredConnectionModeRequest( connection_mode="quick-connect", expected_revision=0, ) ) assert blocked.value.reason_code == "connection-mode-selection-lifecycle-busy" finally: release_borrow.set() connect_thread.join(timeout=3.0) assert connect_thread.is_alive() is False assert len(connect_failures) == 1 assert isinstance(connect_failures[0], RuntimeError) assert str(connect_failures[0]) == "synthetic admitted Connect ended before BLE" assert device_writes == [] state = service.state() assert state["desired_connection_mode"] == "bridge" assert state["desired_connection_mode_revision"] == 0 assert state["configured_connection_mode"] is None assert state["active_connection_mode"] is None operation = next(item for item in state["operations"] if item["action"] == "network.provision") assert operation["status"] == "failed" assert operation["error"]["side_effect_status"] == "none" terminal_record = next( record for record in ( service._require_network_provisioning_idempotency_journal() # noqa: SLF001 .snapshot() .records ) if record.operation_id == operation["operation_id"] ) terminal = terminal_record.terminal assert terminal is not None assert terminal.side_effect_status == "none" assert terminal.safe_to_retry is True def test_mode_selection_is_rejected_while_connect_owns_transition_gate( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: """Once Connect owns lifecycle admission its exact mode cannot change.""" service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service, device_id="k1-a") capture_entered = threading.Event() release_capture = threading.Event() connect_failures: list[BaseException] = [] device_writes: list[str] = [] def paused_capture(_device_id: str) -> None: # Capture is the first candidate-bound step after Connect acquired the # lifecycle gate and repeated its exact mode/discovery CAS check. capture_entered.set() assert release_capture.wait(2.0) return None async def forbidden_device_write(*_: object, **__: object) -> dict[str, Any]: device_writes.append("gatt-write") raise AssertionError("test precondition must fail before GATT") monkeypatch.setattr(facade_module, "_capture_network_intent_device", paused_capture) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_device_write) request = _connect_request( device_id="k1-a", ssid="lab-router", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, idempotency_key="mode-cas-connect-owns-transition-gate", ) def run_connect() -> None: try: asyncio.run(service.connect(request)) except BaseException as exc: # pragma: no branch - expected contract edge connect_failures.append(exc) connect_thread = threading.Thread(target=run_connect, daemon=True) connect_thread.start() assert capture_entered.wait(2.0) try: with pytest.raises(facade_module.NetworkProvisioningConflict) as busy_select: service.select_connection_mode( DesiredConnectionModeRequest( connection_mode="quick-connect", expected_revision=0, ) ) assert busy_select.value.reason_code == "connection-mode-selection-lifecycle-busy" during_connect = service.state() assert during_connect["desired_connection_mode"] == "bridge" assert during_connect["desired_connection_mode_revision"] == 0 finally: release_capture.set() connect_thread.join(timeout=3.0) assert connect_thread.is_alive() is False assert len(connect_failures) == 1 assert isinstance(connect_failures[0], facade_module.NetworkProvisioningConflict) assert connect_failures[0].reason_code == "network-provision-candidate-not-fresh" assert device_writes == [] state = service.state() assert state["desired_connection_mode"] == "bridge" assert state["desired_connection_mode_revision"] == 0 operation = next(item for item in state["operations"] if item["action"] == "network.provision") assert operation["status"] == "failed" assert operation["error"]["side_effect_status"] == "none" def test_mode_selection_winning_before_start_final_admission_publishes_no_start( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: """A newer prepared-mode draft wins before START owns its final fence.""" service, runtime = service_with_fake_runtime(tmp_path) _select_connection_mode(service, "quick-connect") control = FakeInteractiveControlSession() service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 binding = _seed_supervised_connection( service, target_ipv4=facade_module.AP_FALLBACK_IPV4, connection_mode="quick-connect", transport_ref="k1-a", ) control.verified_control = _verified_control_for_binding(binding) prepared = service.prepare_acquisition( _prepare_request( project_name="TEST001", host=facade_module.AP_FALLBACK_IPV4, compatibility_attestation=QUICK_CONNECT_ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] fingerprint_entered = threading.Event() release_fingerprint = threading.Event() start_failures: list[BaseException] = [] selection_results: list[dict[str, Any]] = [] selection_failures: list[BaseException] = [] original_fingerprint = service._request_fingerprint # noqa: SLF001 def paused_fingerprint(action: str, payload: dict[str, Any]) -> str: if action == facade_module.ACTION_ACQUISITION_START: fingerprint_entered.set() assert release_fingerprint.wait(2.0) return original_fingerprint(action, payload) monkeypatch.setattr(service, "_request_fingerprint", paused_fingerprint) def run_start() -> None: try: service.start_acquisition( _start_request( acquisition_id=acquisition_id, physical_acceptance=PHYSICAL_ACCEPTANCE, ) ) except BaseException as exc: # pragma: no branch - expected race loser start_failures.append(exc) start_thread = threading.Thread(target=run_start, daemon=True) start_thread.start() assert fingerprint_entered.wait(2.0) def run_selection() -> None: try: selection_results.append( service.select_connection_mode( DesiredConnectionModeRequest( connection_mode="bridge", expected_revision=1, ) ) ) except BaseException as exc: # pragma: no cover - assertion aid selection_failures.append(exc) selection_thread = threading.Thread(target=run_selection, daemon=True) selection_thread.start() try: deadline = time.monotonic() + 2.0 while time.monotonic() < deadline: with service._lock: # noqa: SLF001 if service._desired_connection_mode_revision == 2: # noqa: SLF001 break time.sleep(0.01) with service._lock: # noqa: SLF001 assert service._desired_connection_mode == "bridge" # noqa: SLF001 assert service._desired_connection_mode_revision == 2 # noqa: SLF001 finally: release_fingerprint.set() start_thread.join(timeout=3.0) selection_thread.join(timeout=3.0) assert start_thread.is_alive() is False assert selection_thread.is_alive() is False assert selection_failures == [] assert selection_results[0]["desired_connection_mode"] == "bridge" assert selection_results[0]["desired_connection_mode_revision"] == 2 assert len(start_failures) == 1 assert isinstance(start_failures[0], facade_module.NetworkProvisioningConflict) assert start_failures[0].reason_code == "connection-mode-switch-pending" assert control.start_projects == [] assert runtime.start_calls == [] state = service.state() assert state["acquisition"]["state"] == "prepared" start_operation = next( item for item in state["operations"] if item["action"] == "acquisition.start" ) assert start_operation["status"] == "failed" assert start_operation["error"]["side_effect_status"] == "none" def test_start_owned_and_queued_states_reject_mode_selection_until_dispatch_resolves( tmp_path: Path, ) -> None: """Queued START remains a mode-selection fence after the HTTP call returns.""" service, runtime = service_with_fake_runtime(tmp_path) _select_connection_mode(service, "quick-connect") request_start_entered = threading.Event() release_request_start = threading.Event() class QueuedStartControl(FakeInteractiveControlSession): def request_start( self, *, project_name: str, confirmation: object, command_context: object, preparation_checkpoint_observer: object | None = None, expected_session_generation: int | None = None, expected_state_revision: int | None = None, ) -> dict[str, object]: del preparation_checkpoint_observer assert confirmation is not None assert command_context is not None assert self.state == "project-ready" self._accept_checkpoint( expected_session_generation=expected_session_generation, expected_state_revision=expected_state_revision, ) self.start_projects.append(project_name) self.start_contexts.append(command_context) self.state = "start-requested" request_start_entered.set() assert release_request_start.wait(2.0) # The real worker has only been released here; modeling:start has # deliberately not been published in this deterministic fixture. return self.snapshot() control = QueuedStartControl() service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 binding = _seed_supervised_connection( service, target_ipv4=facade_module.AP_FALLBACK_IPV4, connection_mode="quick-connect", transport_ref="k1-a", ) control.verified_control = _verified_control_for_binding(binding) prepared = service.prepare_acquisition( _prepare_request( project_name="TEST001", host=facade_module.AP_FALLBACK_IPV4, compatibility_attestation=QUICK_CONNECT_ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] start_failures: list[BaseException] = [] def run_start() -> None: try: service.start_acquisition( _start_request( acquisition_id=acquisition_id, physical_acceptance=PHYSICAL_ACCEPTANCE, ) ) except BaseException as exc: # pragma: no cover - assertion aid start_failures.append(exc) start_thread = threading.Thread(target=run_start, daemon=True) start_thread.start() assert request_start_entered.wait(2.0) try: with pytest.raises(facade_module.NetworkProvisioningConflict) as owned: service.select_connection_mode( DesiredConnectionModeRequest( connection_mode="bridge", expected_revision=1, ) ) assert owned.value.reason_code == "connection-mode-selection-lifecycle-busy" finally: release_request_start.set() start_thread.join(timeout=3.0) assert start_thread.is_alive() is False assert start_failures == [] queued = service.state() assert queued["acquisition"]["state"] == "starting" assert queued["desired_connection_mode"] == "quick-connect" assert queued["desired_connection_mode_revision"] == 1 assert queued["connection_lifecycle"]["mode_selection"] == { "allowed": False, "reason_codes": [ "connection-mode-selection-physical-state-unsafe", "connection-mode-selection-control-state-unsafe", ], "automatic_retry": False, } assert "select-connection-mode" not in queued["connection_lifecycle"]["allowed_actions"] assert runtime.start_calls with pytest.raises(facade_module.NetworkProvisioningConflict) as queued_select: service.select_connection_mode( DesiredConnectionModeRequest( connection_mode="bridge", expected_revision=1, ) ) assert queued_select.value.reason_code == "connection-mode-selection-physical-state-unsafe" assert service.state()["desired_connection_mode_revision"] == 1 @pytest.mark.parametrize( ("source_mode", "target_mode", "target_ipv4", "source_attestation"), [ ( "quick-connect", "bridge", facade_module.AP_FALLBACK_IPV4, QUICK_CONNECT_ATTESTATION, ), ( "bridge", "quick-connect", "192.168.1.20", ATTESTATION, ), ], ids=["quick-to-bridge", "bridge-to-quick"], ) def test_pending_mode_scan_aborts_purely_local_prepared_acquisition_without_stop( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, source_mode: facade_module.ConnectionMode, target_mode: facade_module.ConnectionMode, target_ipv4: str, source_attestation: CompatibilityAttestationRequest, ) -> None: """PREPARE without START is locally reversible at the explicit Scan commit.""" service, runtime = service_with_fake_runtime(tmp_path) if source_mode != "bridge": _select_connection_mode(service, source_mode) source_revision = service.state()["desired_connection_mode_revision"] control = FakeInteractiveControlSession() service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 binding = _seed_supervised_connection( service, target_ipv4=target_ipv4, connection_mode=source_mode, transport_ref="k1-a", ) control.verified_control = _verified_control_for_binding(binding) prepared = service.prepare_acquisition( _prepare_request( project_name="TEST001", host=target_ipv4, compatibility_attestation=source_attestation, ) ) assert prepared["acquisition"]["state"] == "prepared" assert control.state == "project-ready" switched = service.select_connection_mode( DesiredConnectionModeRequest( connection_mode=target_mode, expected_revision=source_revision, ) ) assert switched["connection_policy"]["actions"]["scan-ble"]["allowed"] is True assert switched["connection_lifecycle"]["mode_selection"]["allowed"] is True assert "select-connection-mode" in switched["connection_lifecycle"]["allowed_actions"] physical_or_network_edges: list[str] = [] async def fake_scan( _duration_seconds: float, *, on_admitted: Callable[[], None] | None = None, ) -> dict[str, Any]: assert service._acquisition is not None # noqa: SLF001 assert service._acquisition.state == "aborted" # noqa: SLF001 assert control.state == "idle" assert on_admitted is not None on_admitted() return _ble_scan_result(f"{target_mode}-candidate") async def forbidden_device_write(*_: object, **__: object) -> dict[str, Any]: physical_or_network_edges.append("network-write") raise AssertionError("prepared mode switch must not write K1 network state") monkeypatch.setattr(facade_module, "scan", fake_scan) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_device_write) monkeypatch.setattr( service._physical_command_coordinator, # noqa: SLF001 "prepare", lambda *_args, **_kwargs: physical_or_network_edges.append("physical-command"), ) scanned = asyncio.run(service.scan_ble(1.0)) assert physical_or_network_edges == [] assert control.start_projects == [] assert control.stop_calls == 0 assert runtime.start_calls == [] assert runtime.stop_calls == 0 assert scanned["acquisition"]["state"] == "aborted" assert scanned["acquisition"]["result"] == { "receiver_started": False, "device_command_attempted": False, "reason_code": "superseded-by-connection-mode-switch", } assert scanned["configured_connection_mode"] is None assert scanned["active_connection_mode"] is None assert [item["device_id"] for item in scanned["devices"]] == [f"{target_mode}-candidate"] def test_mode_draft_can_be_cancelled_before_scan_without_touching_active_binding( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: """Quick -> Bridge draft -> Quick is two local CAS writes and no I/O.""" service, runtime = service_with_fake_runtime(tmp_path) _select_connection_mode(service, "quick-connect") control = FakeInteractiveControlSession(initial_state="project-ready") service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 binding = _seed_supervised_connection( service, target_ipv4=facade_module.AP_FALLBACK_IPV4, connection_mode="quick-connect", transport_ref="k1-a", ) control.verified_control = _verified_control_for_binding(binding) before = service.state() before_supervisor_revision = service._connection_supervisor.snapshot().revision # noqa: SLF001 device_edges: list[str] = [] async def forbidden_scan(*_: object, **__: object) -> dict[str, Any]: device_edges.append("ble-scan") raise AssertionError("draft cancellation must not scan") async def forbidden_network_write(*_: object, **__: object) -> dict[str, Any]: device_edges.append("network-write") raise AssertionError("draft cancellation must not write network state") monkeypatch.setattr(facade_module, "scan", forbidden_scan) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_network_write) monkeypatch.setattr( service._physical_command_coordinator, # noqa: SLF001 "prepare", lambda *_args, **_kwargs: device_edges.append("physical-command"), ) switched = service.select_connection_mode( DesiredConnectionModeRequest( connection_mode="bridge", expected_revision=before["desired_connection_mode_revision"], ) ) cancelled = service.select_connection_mode( DesiredConnectionModeRequest( connection_mode="quick-connect", expected_revision=switched["desired_connection_mode_revision"], ) ) assert device_edges == [] assert runtime.start_calls == [] assert runtime.stop_calls == 0 assert control.state == "project-ready" assert control.start_projects == [] assert control.stop_calls == 0 assert cancelled["desired_connection_mode_revision"] == ( before["desired_connection_mode_revision"] + 2 ) assert cancelled["desired_connection_mode"] == "quick-connect" assert cancelled["configured_connection_mode"] == "quick-connect" assert cancelled["active_connection_mode"] == "quick-connect" assert ( cancelled["connection_lifecycle"]["active_binding_key"] == before["connection_lifecycle"]["active_binding_key"] ) assert ( cancelled["connection_lifecycle"]["active_binding"] == before["connection_lifecycle"]["active_binding"] ) assert cancelled["connection_lifecycle"]["mode_change"]["state"] == "ready" assert cancelled["connection_lifecycle"]["connection_ready"] is True assert cancelled["connection_lifecycle"]["ready_to_start"] is True assert cancelled["connection_lifecycle"]["mode_selection"]["allowed"] is True assert service._connection_supervisor.snapshot().revision == before_supervisor_revision # noqa: SLF001 def test_lifecycle_mode_selection_is_disallowed_while_acquiring( tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) _select_connection_mode(service, "quick-connect") control = FakeInteractiveControlSession() service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 binding = _seed_supervised_connection( service, target_ipv4=facade_module.AP_FALLBACK_IPV4, connection_mode="quick-connect", transport_ref="k1-a", ) control.verified_control = _verified_control_for_binding(binding) service.prepare_acquisition( _prepare_request( project_name="TEST001", host=facade_module.AP_FALLBACK_IPV4, compatibility_attestation=QUICK_CONNECT_ATTESTATION, ) ) with service._lock: # noqa: SLF001 assert service._acquisition is not None # noqa: SLF001 service._acquisition.transition( # noqa: SLF001 "starting", message_code="acquisition.start.waiting_receiver_ready", ) service._acquisition.transition( # noqa: SLF001 "acquiring", message_code="acquisition.acquiring", ) service._acquisition_start_operation_id = "test-start-operation" # noqa: SLF001 runtime.source_mode = "live" runtime.phase = "live" control.state = "scanning" state = service.state() assert state["connection_lifecycle"]["mode_selection"]["allowed"] is False assert ( "connection-mode-selection-physical-state-unsafe" in state["connection_lifecycle"]["mode_selection"]["reason_codes"] ) assert ( "connection-mode-selection-control-state-unsafe" in state["connection_lifecycle"]["mode_selection"]["reason_codes"] ) assert "select-connection-mode" not in state["connection_lifecycle"]["allowed_actions"] def test_lifecycle_mode_selection_is_disallowed_by_unsafe_physical_ledger( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) control = FakeInteractiveControlSession(initial_state="connection-ready") service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 binding = _seed_supervised_connection(service, connection_mode="bridge") control.verified_control = _verified_control_for_binding(binding) monkeypatch.setattr( service._physical_command_coordinator, # noqa: SLF001 "snapshot", lambda: { "status": "unresolved", "requires_reconciliation": True, "record": None, }, ) state = service.state() assert state["connection_lifecycle"]["mode_selection"] == { "allowed": False, "reason_codes": ["connection-mode-selection-physical-state-unsafe"], "automatic_retry": False, } assert "select-connection-mode" not in state["connection_lifecycle"]["allowed_actions"] def test_disconnected_mode_draft_ignores_old_physical_history_without_io( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: """A cold selector is local; the old ledger still fences later actions.""" service, runtime = service_with_fake_runtime(tmp_path) control = FakeInteractiveControlSession(initial_state="idle") service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 physical_snapshot = { "status": "unresolved", "requires_reconciliation": True, "resolved_active_recovery_required": False, "record": { "operation_id": "old-stop", "action": "stop", "stage": "observing", "resolution": None, }, } monkeypatch.setattr( service._physical_command_coordinator, # noqa: SLF001 "snapshot", lambda: physical_snapshot, ) device_edges: list[str] = [] monkeypatch.setattr( facade_module, "scan", lambda *_args, **_kwargs: device_edges.append("scan"), ) monkeypatch.setattr( facade_module, "provision_wifi_once", lambda *_args, **_kwargs: device_edges.append("network-write"), ) before = service.state() assert before["connection_lifecycle"]["mode_selection"]["allowed"] is True selected = service.select_connection_mode( DesiredConnectionModeRequest( connection_mode="quick-connect", expected_revision=before["desired_connection_mode_revision"], ) ) assert selected["desired_connection_mode"] == "quick-connect" assert selected["desired_connection_mode_revision"] == 1 assert selected["physical_command"]["requires_reconciliation"] is True assert selected["connection_policy"]["actions"]["provision-fresh-device"]["allowed"] is False assert runtime.start_calls == [] assert runtime.stop_calls == 0 assert control.state == "idle" assert device_edges == [] def test_carried_old_reopen_audit_does_not_freeze_a_successor_mode_draft() -> None: physical_snapshot: dict[str, object] = { "status": "unresolved", "requires_reconciliation": True, "record": { "operation_id": "successor-stop", "revision": 41, "stage": "observing", "resolution": None, "operator_retirements": [ { "retirement_id": "old-retirement", "original_attempt": {"operation_id": "old-stop"}, } ], "operator_reconciliation_reopens": [ { "retirement_id": "old-retirement", "retired_record_revision": 12, } ], }, } assert ( facade_module._physical_command_pending_reopened_reconciliation_mode( # noqa: SLF001 physical_snapshot ) is None ) assert ( facade_module._connection_mode_selection_reason_codes( # noqa: SLF001 acquisition_state=None, acquisition_lease_retained=False, acquisition_start_operation_id=None, runtime={"source_mode": "idle"}, physical_command=physical_snapshot, control_state="idle", desired_connection_mode="bridge", ) == [] ) _RECOVERY_VENDOR_HASH = "a" * 64 _RECOVERY_SERIAL_HASH = "b" * 64 _RECOVERY_PROJECT_HASH = "c" * 64 _RECOVERY_ACQUISITION_ID = "acquisition-persisted-active-k1" _RECOVERY_START_OPERATION_ID = "physical-start-persisted-active-k1" def _persist_resolved_active_start_for_restart( service: XgridsK1CompatibilityService, ) -> None: """Persist one successful START without retaining process-local acquisition.""" identity = PhysicalCommandIdentity( vendor_device_id_sha256=_RECOVERY_VENDOR_HASH, device_serial_sha256=_RECOVERY_SERIAL_HASH, ) connection = PhysicalCommandConnectionBinding( intent_id="old-start-intent", transport_ref="test-ble-transport", connection_mode="bridge", target_ipv4="192.168.68.52", target_port=facade_module.CONTROL_MQTT_PORT, host_path_epoch=1, control_session_id="old-start-control", producer_generation=1, ) def status( session_state: str, *, observed_at_utc: str, ) -> PhysicalCommandStatusEvidence: project_bound = session_state == "scanning" return PhysicalCommandStatusEvidence( source="live-control-session", vendor_device_id_sha256=_RECOVERY_VENDOR_HASH, device_serial_sha256=_RECOVERY_SERIAL_HASH, control_session_id=connection.control_session_id, host_path_epoch=connection.host_path_epoch, producer_generation=connection.producer_generation, session_state=session_state, # type: ignore[arg-type] session_state_code=302 if session_state == "scanning" else 300, project_bound=project_bound, project_id_sha256=_RECOVERY_PROJECT_HASH if project_bound else None, init_ready=project_bound, status_message_sha256=hashlib.sha256( f"{session_state}:{observed_at_utc}".encode() ).hexdigest(), mqtt_retained=False, observed_at_utc=observed_at_utc, ) ledger = service._physical_command_ledger # noqa: SLF001 ledger.prepare( operation_id=_RECOVERY_START_OPERATION_ID, parent_operation_id=None, acquisition_id=_RECOVERY_ACQUISITION_ID, action="start", identity=identity, connection=connection, compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, payload_sha256="d" * 64, baseline_status=status( "ready", observed_at_utc="2026-08-09T12:00:00.000Z", ), ) ledger.mark_dispatching(_RECOVERY_START_OPERATION_ID) ledger.mark_observing( _RECOVERY_START_OPERATION_ID, publish_call_returned=True, packet_id=41, ) ledger.mark_qos2_completed(_RECOVERY_START_OPERATION_ID, packet_id=41) ledger.record_application_response( _RECOVERY_START_OPERATION_ID, PhysicalCommandApplicationResponse( operation_id=_RECOVERY_START_OPERATION_ID, action="start", control_session_id=connection.control_session_id, host_path_epoch=connection.host_path_epoch, producer_generation=connection.producer_generation, result_code=PHYSICAL_COMMAND_APPLICATION_SUCCESS_CODE, success=True, payload_sha256="e" * 64, observed_at_utc="2026-08-09T12:00:01.000Z", ), ) ledger.record_status_observation( _RECOVERY_START_OPERATION_ID, status("scanning", observed_at_utc="2026-08-09T12:00:02.000Z"), ) ledger.resolve( _RECOVERY_START_OPERATION_ID, resolution="start-active-observed", ) def _persist_resolved_unclassified_stop_for_restart( service: XgridsK1CompatibilityService, ) -> tuple[str, int]: """Persist the exact legacy startup shape without process-local owners.""" _persist_resolved_active_start_for_restart(service) ledger = service._physical_command_ledger # noqa: SLF001 start = ledger.snapshot().record assert start is not None assert start.last_status is not None stop_operation_id = "physical-stop-resolved-unclassified-k1" ledger.prepare( operation_id=stop_operation_id, parent_operation_id=start.operation_id, acquisition_id=start.acquisition_id, action="stop", identity=start.identity, connection=start.connection, compatibility_profile_id=start.compatibility_profile_id, payload_sha256="6" * 64, baseline_status=start.last_status, ) resolved = ledger.resolve( stop_operation_id, resolution="not-dispatched", ) assert resolved.resolved_unclassified_stop_recovery_required is True return stop_operation_id, resolved.revision def _persist_classified_ready_stop_for_restart( service: XgridsK1CompatibilityService, ) -> tuple[str, PhysicalCommandConnectionBinding]: """Persist S0 plus one read-only READY proof on an obsolete C1 binding.""" stop_operation_id, _ = _persist_resolved_unclassified_stop_for_restart(service) coordinator = service._physical_command_coordinator # noqa: SLF001 observed_at_utc = datetime.now(UTC).isoformat(timespec="milliseconds").replace( "+00:00", "Z", ) c1 = PhysicalCommandRuntimeBinding( vendor_device_id_sha256=_RECOVERY_VENDOR_HASH, device_serial_sha256=_RECOVERY_SERIAL_HASH, compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, intent_id="classified-ready-c1-intent", transport_ref="test-ble-transport", connection_mode="bridge", target_ipv4="192.168.68.52", target_port=facade_module.CONTROL_MQTT_PORT, host_path_epoch=7, control_session_id="classified-ready-c1-control", producer_generation=7, ) coordinator.application_response( ApplicationMqttResponseEvidence( operation_key="bootstrap:classified-ready-c1:DeviceInfoRequest", response_topic="lixel/application/response/device_info", payload_sha256="4" * 64, modeling_action=None, result_code=None, success=None, observed_at_utc=observed_at_utc, ) ) coordinator.bind_control_session(c1) coordinator.device_status( ApplicationMqttDeviceStatusEvidence( vendor_device_id_sha256=_RECOVERY_VENDOR_HASH, device_serial_sha256=_RECOVERY_SERIAL_HASH, session_state="ready", session_state_code=MODELING_STATE_BASE + 300, project_bound=False, project_id_sha256=None, init_ready=False, status_message_sha256="5" * 64, mqtt_retained=False, observed_at_utc=observed_at_utc, ) ) classified = coordinator.reconcile_unresolved( reconciliation_id="classified-ready-c1", ) assert classified["operation_id"] == stop_operation_id assert classified["resolution"] == "not-dispatched" return stop_operation_id, PhysicalCommandConnectionBinding( intent_id=c1.intent_id, transport_ref=c1.transport_ref, connection_mode=c1.connection_mode, target_ipv4=c1.target_ipv4, target_port=c1.target_port, host_path_epoch=c1.host_path_epoch, control_session_id=c1.control_session_id, producer_generation=c1.producer_generation, ) def test_resolved_active_power_loss_exposes_local_retirement_and_revokes_target( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) _persist_resolved_active_start_for_restart(service) _seed_terminal_network_attempt(service) before = service.state() checkpoint = before["physical_command"]["operator_retirement"] action = before["connection_policy"]["actions"]["retire-unavailable-physical-target"] io_calls: list[str] = [] async def forbidden_io(*_args: object, **_kwargs: object) -> object: io_calls.append("device-or-network-io") raise AssertionError("resolved-active retirement must stay local-only") monkeypatch.setattr(facade_module, "read_wifi_status_once", forbidden_io) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_io) monkeypatch.setattr( service, "_probe_control_endpoint", lambda *_args, **_kwargs: io_calls.append("tcp-probe"), ) assert before["physical_command"]["resolved_active_recovery_required"] is True assert checkpoint["allowed"] is True assert action["allowed"] is True assert action["target_source"] == "durable-physical-command" assert action["required_transport_ref"] == "test-ble-transport" assert before["connection_policy"]["recommended_action"] == ( "retire-unavailable-physical-target" ) assert before["connection_attempt"]["safe_next_action"] == ( "retire-unavailable-physical-target" ) retired = service.retire_unavailable_physical_command( RetireUnavailablePhysicalCommandRequest( retirement_id="retirement-resolved-active-power-loss", expected_operation_id=checkpoint["expected_operation_id"], expected_revision=checkpoint["expected_revision"], expected_transport_ref=checkpoint["expected_transport_ref"], operator_confirmed=True, reason="device-permanently-unavailable-or-replaced", ) ) assert retired["physical_command"]["record"]["resolution"] == ( "operator-retired-outcome-unknown" ) assert retired["physical_command"]["operator_retirement"]["allowed"] is False assert retired["selected_device_id"] is None assert retired["k1_ip"] is None assert retired["connection_policy"]["facts"]["retired_transport_refs"] == ["test-ble-transport"] assert runtime.start_calls == [] assert runtime.stop_calls == 0 assert io_calls == [] class _VerifyPhysicalRecoveryCoordinator: """Small exact-proof coordinator double for facade Verify recovery tests.""" def __init__( self, *, observed_session_state: str | None, reconciliation_ready: bool, prepared_stop_operation_id: str | None = None, ) -> None: self.observed_session_state = observed_session_state self.reconciliation_ready = reconciliation_ready self.resolution: str | None = None self.reconciliation_ids: list[str] = [] self.verified_control: dict[str, object] | None = None self.prepared_stop_operation_id = prepared_stop_operation_id def _resolved_record(self, reconciliation_id: str) -> dict[str, object]: assert self.verified_control is not None connection = { field: self.verified_control[field] for field in ( "intent_id", "transport_ref", "connection_mode", "target_ipv4", "target_port", "host_path_epoch", "control_session_id", "producer_generation", ) } return { "operation_id": self.prepared_stop_operation_id or "persisted-start-observing", "acquisition_id": "acq-persisted-start", "action": "stop" if self.prepared_stop_operation_id is not None else "start", "stage": "resolved", "resolution": ( "not-dispatched" if self.prepared_stop_operation_id is not None else self.resolution ), "compatibility_profile_id": XGRIDS_K1_COMPATIBILITY_PROFILE_ID, "connection": { "transport_ref": "test-ble-transport", "connection_mode": "bridge", }, "reconciliations": [ { "reconciliation_id": reconciliation_id, "kind": ( "prepared-stop-classification" if self.prepared_stop_operation_id is not None else "ambiguous-outcome" ), "resolution": "physical-active-observed", "original_attempt": { "operation_id": ( self.prepared_stop_operation_id or "persisted-start-observing" ), "action": ( "stop" if self.prepared_stop_operation_id is not None else "start" ), }, "verified_binding": {"connection": connection}, "observation": { "source": "explicit-read-only-reconciliation", "control_session_id": self.verified_control["control_session_id"], "host_path_epoch": self.verified_control["host_path_epoch"], "producer_generation": self.verified_control["producer_generation"], "session_state": "scanning", "project_bound": True, "project_id_sha256": "8" * 64, "init_ready": True, "mqtt_retained": False, }, } ], } def snapshot(self) -> dict[str, object]: resolved_active_recovery_required = self.resolution == "physical-active-observed" reconciliations = [{"resolution": self.resolution}] if self.resolution is not None else [] return { "status": "resolved" if self.resolution is not None else "unresolved", "reason_code": ( None if self.resolution is not None else "physical-command-reconciliation-required" ), "requires_reconciliation": self.resolution is None, "resolved_active_recovery_required": resolved_active_recovery_required, "automatic_replay_allowed": False, "normal_session_recovery_supported": False, "recovery_requirement": ( "explicit-read-only-deviceinfo-and-non-retained-devicestatus" if self.resolution is None or resolved_active_recovery_required else None ), "runtime_bound": True, "reconciliation_ready": ( (self.resolution is None or resolved_active_recovery_required) and self.reconciliation_ready ), "observed_session_state": self.observed_session_state, "active_operation_id": None, "record": { "operation_id": self.prepared_stop_operation_id or "persisted-start-observing", "action": "stop" if self.prepared_stop_operation_id is not None else "start", "stage": "resolved" if self.resolution is not None else "observing", "resolution": self.resolution, "connection": { "transport_ref": "test-ble-transport", "connection_mode": "bridge", }, "reconciliations": reconciliations, }, } def reconcile_unresolved(self, *, reconciliation_id: str) -> dict[str, object]: assert self.reconciliation_ready is True assert self.observed_session_state in {"ready", "scanning"} self.reconciliation_ids.append(reconciliation_id) self.resolution = ( "physical-standby-observed" if self.observed_session_state == "ready" else "physical-active-observed" ) return self._resolved_record(reconciliation_id) def reconcile_resolved_active( self, *, reconciliation_id: str, ) -> dict[str, object]: assert self.resolution == "physical-active-observed" assert self.reconciliation_ready is True assert self.observed_session_state in {"ready", "scanning"} self.reconciliation_ids.append(reconciliation_id) if self.observed_session_state == "ready": self.resolution = "physical-standby-observed" return self._resolved_record(reconciliation_id) def _install_synthetic_verify_recovery( service: XgridsK1CompatibilityService, coordinator: _VerifyPhysicalRecoveryCoordinator, ) -> None: """Install a no-I/O topology+DeviceInfo path while keeping real gates.""" _seed_supervised_connection(service, connection_mode="bridge", with_control=False) with service._lock: # noqa: SLF001 service._connection_verification = { # noqa: SLF001 "lease_generation": service._connection_lease_generation, # noqa: SLF001 "lease_state": "reachable", } service._physical_command_coordinator = coordinator # type: ignore[assignment] # noqa: SLF001 async def verify_topology_without_io( bound_service: XgridsK1CompatibilityService, request: ConnectionVerifyRequest, ) -> tuple[str, bool, None]: operation, created = bound_service._operations.begin( # noqa: SLF001 facade_module.ACTION_CONNECTION_VERIFY, operation_id=request.operation_id, deadline_seconds=10.0, ) if created: bound_service._operations.transition( # noqa: SLF001 operation.operation_id, "running", stage_code="topology-confirmed-device-info-pending", message_code="connection.verify.device_info_pending", ) return operation.operation_id, created, None async def bootstrap_with_process_holder( bound_service: XgridsK1CompatibilityService, *, parent_operation_id: str | None, connection_mode: facade_module.ConnectionMode, inspection_only: bool = False, ) -> None: await _synthetic_prestart_control_bootstrap( bound_service, parent_operation_id=parent_operation_id, connection_mode=connection_mode, inspection_only=inspection_only, ) verified = bound_service._application_control_session.snapshot().get( # noqa: SLF001 "verified_control" ) assert isinstance(verified, dict) coordinator.verified_control = dict(verified) bound_service._acquire_application_control_process_lease() # noqa: SLF001 service._verify_connection_owned = MethodType( # type: ignore[method-assign] # noqa: SLF001 verify_topology_without_io, service, ) service._bootstrap_prestart_control_ready_owned = MethodType( # type: ignore[method-assign] # noqa: SLF001 bootstrap_with_process_holder, service, ) def _install_real_coordinator_bootstrap( service: XgridsK1CompatibilityService, *, observed_session_state: str, ) -> None: """Install exact DeviceInfo/status evidence on the facade's real topology path.""" assert observed_session_state in {"ready", "scanning"} coordinator = service._physical_command_coordinator # noqa: SLF001 async def bootstrap_with_real_coordinator( bound_service: XgridsK1CompatibilityService, *, parent_operation_id: str | None, connection_mode: facade_module.ConnectionMode, inspection_only: bool = False, ) -> None: coordinator.prepare_read_only_bootstrap() coordinator.application_response( ApplicationMqttResponseEvidence( operation_key=( f"bootstrap:{parent_operation_id}:DeviceInfoRequest" ), response_topic="lixel/application/response/device_info", payload_sha256="7" * 64, modeling_action=None, result_code=None, success=None, observed_at_utc="2026-08-13T08:00:00.000Z", ) ) await _synthetic_prestart_control_bootstrap( bound_service, parent_operation_id=parent_operation_id, connection_mode=connection_mode, inspection_only=inspection_only, ) verified = bound_service._application_control_session.snapshot().get( # noqa: SLF001 "verified_control" ) assert isinstance(verified, dict) coordinator.bind_control_session( PhysicalCommandRuntimeBinding( vendor_device_id_sha256=_RECOVERY_VENDOR_HASH, device_serial_sha256=_RECOVERY_SERIAL_HASH, compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, intent_id=str(verified["intent_id"]), transport_ref=str(verified["transport_ref"]), connection_mode=verified["connection_mode"], # type: ignore[arg-type] target_ipv4=str(verified["target_ipv4"]), target_port=int(verified["target_port"]), host_path_epoch=int(verified["host_path_epoch"]), control_session_id=str(verified["control_session_id"]), producer_generation=int(verified["producer_generation"]), ) ) scanning = observed_session_state == "scanning" coordinator.device_status( ApplicationMqttDeviceStatusEvidence( vendor_device_id_sha256=_RECOVERY_VENDOR_HASH, device_serial_sha256=_RECOVERY_SERIAL_HASH, session_state=observed_session_state, # type: ignore[arg-type] session_state_code=MODELING_STATE_BASE + (302 if scanning else 300), project_bound=scanning, project_id_sha256=_RECOVERY_PROJECT_HASH if scanning else None, init_ready=scanning, status_message_sha256="8" * 64, mqtt_retained=False, observed_at_utc="2026-08-13T08:00:01.000Z", ) ) bound_service._acquire_application_control_process_lease() # noqa: SLF001 service._bootstrap_prestart_control_ready_owned = MethodType( # type: ignore[method-assign] # noqa: SLF001 bootstrap_with_real_coordinator, service, ) def _install_real_coordinator_verify_recovery( service: XgridsK1CompatibilityService, *, observed_session_state: str, ) -> None: """Drive public Verify with real durable reconciliation and no topology I/O.""" assert observed_session_state in {"ready", "scanning"} _seed_supervised_connection(service, connection_mode="bridge", with_control=False) with service._lock: # noqa: SLF001 service._connection_verification = { # noqa: SLF001 "lease_generation": service._connection_lease_generation, # noqa: SLF001 "lease_state": "reachable", } async def verify_topology_without_io( bound_service: XgridsK1CompatibilityService, request: ConnectionVerifyRequest, ) -> tuple[str, bool, None]: operation, created = bound_service._operations.begin( # noqa: SLF001 facade_module.ACTION_CONNECTION_VERIFY, operation_id=request.operation_id, deadline_seconds=10.0, ) if created: bound_service._operations.transition( # noqa: SLF001 operation.operation_id, "running", stage_code="topology-confirmed-device-info-pending", message_code="connection.verify.device_info_pending", ) return operation.operation_id, created, None service._verify_connection_owned = MethodType( # type: ignore[method-assign] # noqa: SLF001 verify_topology_without_io, service, ) _install_real_coordinator_bootstrap( service, observed_session_state=observed_session_state, ) def _retained_physical_recovery_verify_request( *, operation_id: str, ) -> ConnectionVerifyRequest: """Address the exact process-retained K1 seeded by recovery fixtures.""" return ConnectionVerifyRequest( device_id="test-ble-transport", source="retained-current-process", compatibility_attestation=ATTESTATION, operation_id=operation_id, ) def _install_terminal_camera_error_residual( service: XgridsK1CompatibilityService, monkeypatch: pytest.MonkeyPatch, *, cleanup_failure: Exception | None = None, producer_alive: bool = False, ) -> list[str]: """Reproduce the inert camera/process residue left by archive failure.""" source_id = facade_module.DEFAULT_ACQUISITION_CAMERA_SOURCE camera_state = dict(service.camera_preview.snapshot()) camera_state.update( { "phase": "error", "generation": 17, "active_source_id": source_id, "delivery": None, "error": { "code": "segment-too-large", "message": "synthetic terminal camera archive failure", }, } ) camera_state["recording"] = { "active": False, "source_end_expected": False, "session": None, "active_epoch": None, "committed_media_segment_count": None, "producer_alive": producer_alive, "producer_age_ms": None, "last_segment_age_ms": None, "preview_consumer_count": 0, "completed_epochs": 1, "last_summary": None, } camera_gate = threading.RLock() cleanup_calls: list[str] = [] def snapshot() -> dict[str, Any]: with camera_gate: copied = dict(camera_state) copied["recording"] = dict(camera_state["recording"]) error = camera_state.get("error") copied["error"] = dict(error) if isinstance(error, dict) else None return copied def stop_current() -> dict[str, Any]: cleanup_calls.append("stop-current") if cleanup_failure is not None: raise cleanup_failure with camera_gate: camera_state.update( { "phase": "idle", "generation": None, "active_source_id": None, "delivery": None, "error": None, } ) return snapshot() monkeypatch.setattr(service.camera_preview, "snapshot", snapshot) monkeypatch.setattr(service.camera_preview, "stop_current", stop_current) assert service._ensure_camera_preview_process_lease() is True # noqa: SLF001 with service._lock: # noqa: SLF001 service._live_perception_camera_binding = ( # noqa: SLF001 "camera-failed-session", source_id, 17, ) service._camera_activation_lineage = ( # noqa: SLF001 "acq-camera-failed", "camera-failed-session", 0, ) service._camera_activation_retry_lineage = ( # noqa: SLF001 "acq-camera-failed", "camera-failed-session", 0, ) service._camera_activation_retry_not_before_monotonic = 42.0 # noqa: SLF001 return cleanup_calls def test_explicit_verify_reconciles_persisted_start_to_ready_without_device_io( tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) coordinator = _VerifyPhysicalRecoveryCoordinator( observed_session_state="ready", reconciliation_ready=True, ) _install_synthetic_verify_recovery(service, coordinator) operation_id = "op-00000000-0000-4000-8000-000000001201" verify_state = asyncio.run( service.verify_connection( _retained_physical_recovery_verify_request(operation_id=operation_id) ) ) state = service.state() assert coordinator.reconciliation_ids == [f"{operation_id}.physical"] assert state["physical_command"]["requires_reconciliation"] is False assert state["physical_command"]["record"]["resolution"] == ("physical-standby-observed") assert state["connection_lifecycle"]["mode_selection"]["allowed"] is True, state[ "connection_lifecycle" ]["mode_selection"] assert verify_state["last_operation"]["status"] == "succeeded" assert verify_state["last_operation"]["stage_code"] == ("physical-reconciliation-confirmed") assert verify_state["last_operation"]["result"]["physical_reconciliation"] == { "performed": True, "resolution": "physical-standby-observed", "observed_session_state": "ready", "device_write_performed": False, "automatic_retry": False, } assert service._application_control_process_lease_holders == {"control"} # noqa: SLF001 def test_explicit_verify_reconciliation_does_not_require_normal_command_authority( tmp_path: Path, ) -> None: """Fresh DeviceInfo/READY resolves the old edge before command authority exists.""" service, _ = service_with_fake_runtime(tmp_path) coordinator = _VerifyPhysicalRecoveryCoordinator( observed_session_state="ready", reconciliation_ready=True, ) _install_synthetic_verify_recovery(service, coordinator) bootstrap = service._bootstrap_prestart_control_ready_owned # noqa: SLF001 reconciliation_validations: list[str] = [] async def bootstrap_with_command_authority_blocked( bound_service: XgridsK1CompatibilityService, *, parent_operation_id: str | None, connection_mode: facade_module.ConnectionMode, inspection_only: bool = False, ) -> None: await bootstrap( parent_operation_id=parent_operation_id, connection_mode=connection_mode, inspection_only=inspection_only, ) control = bound_service._application_control_session # noqa: SLF001 def reject_normal_command_authority() -> None: raise RuntimeError("normal command authority remains blocked") def accept_exact_read_only_reconciliation() -> None: reconciliation_validations.append("read-only") control.validate_connection_binding = reject_normal_command_authority # type: ignore[method-assign] control.validate_physical_reconciliation_binding = ( # type: ignore[method-assign] accept_exact_read_only_reconciliation ) service._bootstrap_prestart_control_ready_owned = MethodType( # type: ignore[method-assign] # noqa: SLF001 bootstrap_with_command_authority_blocked, service, ) operation_id = "op-00000000-0000-4000-8000-000000001212" result = asyncio.run( service.verify_connection( _retained_physical_recovery_verify_request(operation_id=operation_id) ) ) assert reconciliation_validations == ["read-only", "read-only"] assert result["last_operation"]["status"] == "succeeded" assert result["physical_command"]["record"]["resolution"] == ("physical-standby-observed") def test_explicit_verify_reconciliation_rechecks_binding_before_durable_commit( tmp_path: Path, ) -> None: """A route/control change between proof and CAS leaves the ledger unresolved.""" service, _ = service_with_fake_runtime(tmp_path) coordinator = _VerifyPhysicalRecoveryCoordinator( observed_session_state="ready", reconciliation_ready=True, ) _install_synthetic_verify_recovery(service, coordinator) bootstrap = service._bootstrap_prestart_control_ready_owned # noqa: SLF001 validation_count = 0 async def bootstrap_with_binding_change( bound_service: XgridsK1CompatibilityService, *, parent_operation_id: str | None, connection_mode: facade_module.ConnectionMode, inspection_only: bool = False, ) -> None: await bootstrap( parent_operation_id=parent_operation_id, connection_mode=connection_mode, inspection_only=inspection_only, ) control = bound_service._application_control_session # noqa: SLF001 def validate_until_commit() -> None: nonlocal validation_count validation_count += 1 if validation_count == 2: raise RuntimeError("control generation changed before commit") control.validate_physical_reconciliation_binding = ( # type: ignore[method-assign] validate_until_commit ) service._bootstrap_prestart_control_ready_owned = MethodType( # type: ignore[method-assign] # noqa: SLF001 bootstrap_with_binding_change, service, ) operation_id = "op-00000000-0000-4000-8000-000000001213" with pytest.raises(facade_module.ConnectionVerificationError) as failure: asyncio.run( service.verify_connection( _retained_physical_recovery_verify_request(operation_id=operation_id) ) ) assert failure.value.reason_code == "physical-command-reconciliation-failed" assert validation_count == 2 assert coordinator.reconciliation_ids == [] physical = coordinator.snapshot() assert physical["requires_reconciliation"] is True assert physical["record"]["resolution"] is None operation = service.state()["last_operation"] assert operation["operation_id"] == operation_id assert operation["status"] == "failed" def test_explicit_verify_reconciles_scanning_as_active_without_unblocking_mode_change( tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) coordinator = _VerifyPhysicalRecoveryCoordinator( observed_session_state="scanning", reconciliation_ready=True, ) _install_synthetic_verify_recovery(service, coordinator) state = asyncio.run( service.verify_connection( _retained_physical_recovery_verify_request( operation_id="op-00000000-0000-4000-8000-000000001202" ) ) ) assert state["physical_command"]["requires_reconciliation"] is False assert state["physical_command"]["record"]["resolution"] == ("physical-active-observed") assert state["connection_lifecycle"]["mode_selection"]["allowed"] is False assert ( "connection-mode-selection-physical-state-unsafe" in state["connection_lifecycle"]["mode_selection"]["reason_codes"] ) assert ( "physical-device-already-active" not in state["connection_policy"]["actions"]["scan-ble"]["reason_codes"] ) assert ( "physical-device-already-active" in state["connection_policy"]["actions"]["provision-fresh-device"]["reason_codes"] ) assert state["acquisition"]["acquisition_id"] == "acq-persisted-start" assert state["acquisition"]["state"] == "failed" assert state["acquisition"]["cleanup_pending"] is False assert state["acquisition"]["requested_streams"] == [] assert state["acquisition"]["result"]["recovery_only"] is True assert state["acquisition"]["result"]["automatic_replay_allowed"] is False assert state["application_control_session"]["can_stop"] is True assert state["last_operation"]["result"]["physical_reconciliation"] == { "performed": True, "resolution": "physical-active-observed", "observed_session_state": "scanning", "device_write_performed": False, "automatic_retry": False, } def test_explicit_verify_scanning_cleans_terminal_camera_residual_for_stop_only_shell( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) coordinator = _VerifyPhysicalRecoveryCoordinator( observed_session_state="scanning", reconciliation_ready=True, ) _install_synthetic_verify_recovery(service, coordinator) cleanup_calls = _install_terminal_camera_error_residual(service, monkeypatch) operation_id = "op-00000000-0000-4000-8000-000000001214" state = asyncio.run( service.verify_connection( _retained_physical_recovery_verify_request(operation_id=operation_id) ) ) control = service._application_control_session # noqa: SLF001 assert isinstance(control, FakeInteractiveControlSession) assert cleanup_calls == ["stop-current"] assert coordinator.reconciliation_ids == [f"{operation_id}.physical"] assert state["physical_command"]["record"]["resolution"] == ( "physical-active-observed" ) assert state["acquisition"]["acquisition_id"] == "acq-persisted-start" assert state["acquisition"]["state"] == "failed" assert state["acquisition"]["result"]["recovery_only"] is True assert state["application_control_session"]["can_stop"] is True assert service.camera_preview.snapshot()["phase"] == "idle" assert service._live_perception_camera_binding is None # noqa: SLF001 assert service._camera_activation_lineage is None # noqa: SLF001 assert service._camera_activation_retry_lineage is None # noqa: SLF001 assert service._camera_activation_retry_not_before_monotonic == 0.0 # noqa: SLF001 assert service._application_control_process_lease_holders == { # noqa: SLF001 "control" } assert control.start_projects == [] assert control.stop_calls == 0 assert runtime.start_calls == [] assert runtime.stop_calls == 0 def test_explicit_verify_scanning_camera_cleanup_failure_retains_fence( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) coordinator = _VerifyPhysicalRecoveryCoordinator( observed_session_state="scanning", reconciliation_ready=True, ) _install_synthetic_verify_recovery(service, coordinator) cleanup_calls = _install_terminal_camera_error_residual( service, monkeypatch, cleanup_failure=RuntimeError("synthetic terminal camera cleanup failed"), ) operation_id = "op-00000000-0000-4000-8000-000000001215" with pytest.raises(facade_module.ConnectionVerificationError) as failure: asyncio.run( service.verify_connection( _retained_physical_recovery_verify_request(operation_id=operation_id) ) ) state = service.state() control = service._application_control_session # noqa: SLF001 assert isinstance(control, FakeInteractiveControlSession) assert failure.value.reason_code == "physical-command-reconciliation-failed" assert cleanup_calls == ["stop-current"] assert coordinator.reconciliation_ids == [f"{operation_id}.physical"] assert state["physical_command"]["record"]["resolution"] == ( "physical-active-observed" ) assert state["acquisition"] is None assert state["last_operation"]["operation_id"] == operation_id assert state["last_operation"]["status"] == "failed" assert service.camera_preview.snapshot()["phase"] == "error" assert service._live_perception_camera_binding is not None # noqa: SLF001 assert service._camera_activation_lineage is not None # noqa: SLF001 assert service._camera_activation_retry_lineage is not None # noqa: SLF001 assert service._application_control_process_lease_holders == { # noqa: SLF001 "camera" } assert control.start_projects == [] assert control.stop_calls == 0 assert runtime.start_calls == [] assert runtime.stop_calls == 0 def test_explicit_verify_scanning_refuses_to_cleanup_live_camera_producer( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) coordinator = _VerifyPhysicalRecoveryCoordinator( observed_session_state="scanning", reconciliation_ready=True, ) _install_synthetic_verify_recovery(service, coordinator) cleanup_calls = _install_terminal_camera_error_residual( service, monkeypatch, producer_alive=True, ) operation_id = "op-00000000-0000-4000-8000-000000001216" with pytest.raises(facade_module.ConnectionVerificationError) as failure: asyncio.run( service.verify_connection( _retained_physical_recovery_verify_request(operation_id=operation_id) ) ) control = service._application_control_session # noqa: SLF001 assert isinstance(control, FakeInteractiveControlSession) assert failure.value.reason_code == "physical-command-reconciliation-failed" assert cleanup_calls == [] assert service._acquisition is None # noqa: SLF001 assert service.camera_preview.snapshot()["recording"]["producer_alive"] is True assert service._application_control_process_lease_holders == { # noqa: SLF001 "camera" } assert control.start_projects == [] assert control.stop_calls == 0 assert runtime.start_calls == [] assert runtime.stop_calls == 0 def test_fresh_service_real_verify_rotation_rehydrates_one_stop_only_target( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: original, _ = service_with_fake_runtime(tmp_path) _persist_resolved_active_start_for_restart(original) assert original._acquisition is None # noqa: SLF001 # A genuinely fresh facade starts with no process-local acquisition. Its # only physical authority is the persisted resolved-active START record. restarted, _ = service_with_fake_runtime(tmp_path) assert restarted._acquisition is None # noqa: SLF001 assert restarted.state()["physical_command"]["resolved_active_recovery_required"] is True _set_scanned_k1(restarted, device_id="test-ble-transport") async def read_status( device_id: str, *, timeout_seconds: float, rediscover: bool, **_: object, ) -> dict[str, Any]: assert (device_id, timeout_seconds, rediscover) == ( "test-ble-transport", 20.0, False, ) return _wifi_status_read("10.255.254.77", device_id=device_id) monkeypatch.setattr(facade_module, "read_wifi_status_once", read_status) monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False) monkeypatch.setattr(facade_module, "_host_route_class", lambda _target: "direct-or-routed") monkeypatch.setattr(facade_module, "_control_endpoint_reachable", lambda _target: True) monkeypatch.setattr(facade_module, "_inspect_host_path", _direct_host_path) coordinator = restarted._physical_command_coordinator # noqa: SLF001 published_physical_edges: list[str] = [] async def bootstrap_recovery_control( bound_service: XgridsK1CompatibilityService, *, parent_operation_id: str | None, connection_mode: facade_module.ConnectionMode, inspection_only: bool = False, ) -> None: await _synthetic_prestart_control_bootstrap( bound_service, parent_operation_id=parent_operation_id, connection_mode=connection_mode, inspection_only=inspection_only, ) control = bound_service._application_control_session # noqa: SLF001 verified = control.snapshot().get("verified_control") assert isinstance(verified, dict) coordinator.application_response( ApplicationMqttResponseEvidence( operation_key="bootstrap:1:DeviceInfoRequest", response_topic="lixel/application/response/device_info", payload_sha256="f" * 64, modeling_action=None, result_code=None, success=None, observed_at_utc="2026-08-09T12:10:00.000Z", ) ) coordinator.bind_control_session( PhysicalCommandRuntimeBinding( vendor_device_id_sha256=_RECOVERY_VENDOR_HASH, device_serial_sha256=_RECOVERY_SERIAL_HASH, compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, intent_id=str(verified["intent_id"]), transport_ref=str(verified["transport_ref"]), connection_mode=verified["connection_mode"], # type: ignore[arg-type] target_ipv4=str(verified["target_ipv4"]), target_port=int(verified["target_port"]), host_path_epoch=int(verified["host_path_epoch"]), control_session_id=str(verified["control_session_id"]), producer_generation=int(verified["producer_generation"]), ) ) coordinator.device_status( ApplicationMqttDeviceStatusEvidence( vendor_device_id_sha256=_RECOVERY_VENDOR_HASH, device_serial_sha256=_RECOVERY_SERIAL_HASH, session_state="scanning", session_state_code=MODELING_STATE_BASE + 302, project_bound=True, project_id_sha256=_RECOVERY_PROJECT_HASH, init_ready=True, status_message_sha256="1" * 64, mqtt_retained=False, observed_at_utc="2026-08-09T12:10:01.000Z", ) ) original_request_stop = control.request_stop def request_stop_with_durable_edge( *, confirmation: object, command_context: object, dispatch_admission_deadline_reached: Callable[[], bool] | None = None, expected_session_generation: int | None = None, expected_state_revision: int | None = None, ) -> dict[str, object]: assert dispatch_admission_deadline_reached is not None payload = b"recovered-stop" coordinator.prepare( command_context, # type: ignore[arg-type] action="stop", envelope=OneShotPublishEnvelope( operation_key="modeling:stop", topic="lixel/application/request/modeling", payload=payload, payload_sha256=hashlib.sha256(payload).hexdigest(), payload_bytes=len(payload), qos=2, retain=False, ), ) published_physical_edges.append("stop") return original_request_stop( confirmation=confirmation, command_context=command_context, dispatch_admission_deadline_reached=( dispatch_admission_deadline_reached ), expected_session_generation=expected_session_generation, expected_state_revision=expected_state_revision, ) control.request_stop = request_stop_with_durable_edge # type: ignore[method-assign] bound_service._acquire_application_control_process_lease() # noqa: SLF001 restarted._bootstrap_prestart_control_ready_owned = MethodType( # type: ignore[method-assign] # noqa: SLF001 bootstrap_recovery_control, restarted, ) verify_operation_id = "op-00000000-0000-4000-8000-000000001230" verified = asyncio.run( restarted.verify_connection( ConnectionVerifyRequest( device_id="test-ble-transport", compatibility_attestation=ATTESTATION, operation_id=verify_operation_id, expected_discovery_generation=0, ) ) ) acquisition = verified["acquisition"] assert acquisition["acquisition_id"] == _RECOVERY_ACQUISITION_ID assert acquisition["device_session_id"] == verified["device_session"]["device_session_id"] assert acquisition["state"] == "failed" assert acquisition["cleanup_pending"] is False assert acquisition["requested_streams"] == [] assert acquisition["project_name"] is None assert acquisition["result"] == { "receiver_stopped": True, "device_state": "scanning", "recovery_only": True, "physical_command_operation_id": _RECOVERY_START_OPERATION_ID, "physical_reconciliation_id": f"{verify_operation_id}.physical", "project_id_sha256": _RECOVERY_PROJECT_HASH, "automatic_replay_allowed": False, } assert verified["application_control_session"]["state"] == "scanning" assert verified["application_control_session"]["can_stop"] is True assert published_physical_edges == [] control = restarted._application_control_session # noqa: SLF001 control_snapshot = control.snapshot() with pytest.raises(RuntimeError, match="ожидать сохранения проекта"): restarted.prepare_acquisition( _prepare_request( project_name="must-not-prepare", compatibility_attestation=ATTESTATION, expected_control_session_generation=control_snapshot["session_generation"], expected_control_state_revision=control_snapshot["state_revision"], ) ) with pytest.raises(RuntimeError, match="ещё не готов принять START"): restarted.start_acquisition( _start_request( acquisition_id=_RECOVERY_ACQUISITION_ID, expected_state_revision=acquisition["state_revision"], physical_acceptance=PHYSICAL_ACCEPTANCE, expected_control_session_generation=control_snapshot["session_generation"], expected_control_state_revision=control_snapshot["state_revision"], ) ) assert published_physical_edges == [] stop_operation_id = "op-00000000-0000-4000-8000-000000001231" stop_request = _stop_request( acquisition_id=_RECOVERY_ACQUISITION_ID, operation_id=stop_operation_id, idempotency_key="recovered-stop-once", mode="graceful", expected_control_session_generation=control_snapshot["session_generation"], expected_control_state_revision=control_snapshot["state_revision"], physical_acceptance=PHYSICAL_ACCEPTANCE, ) stopped = restarted.stop_acquisition(stop_request) assert stopped["acquisition"]["result"]["recovery_only"] is True assert published_physical_edges == ["stop"] repeated = restarted.stop_acquisition(stop_request) assert repeated["last_operation"]["operation_id"] == stop_operation_id assert published_physical_edges == ["stop"] payload_hash = hashlib.sha256(b"recovered-stop").hexdigest() dispatch = ApplicationMqttPublishEvidence( operation_key="modeling:stop", topic="lixel/application/request/modeling", payload_sha256=payload_hash, qos=2, retain=False, packet_id=None, ) coordinator.publish_dispatching(dispatch) returned = ApplicationMqttPublishEvidence( operation_key="modeling:stop", topic="lixel/application/request/modeling", payload_sha256=payload_hash, qos=2, retain=False, packet_id=42, ) coordinator.publish_result(returned, publish_call_returned=True) coordinator.qos2_completed(returned) coordinator.application_response( ApplicationMqttResponseEvidence( operation_key="modeling:stop", response_topic="lixel/application/response/modeling", payload_sha256="2" * 64, modeling_action="stop", result_code=PHYSICAL_COMMAND_APPLICATION_SUCCESS_CODE, success=True, observed_at_utc="2026-08-09T12:10:02.000Z", ) ) coordinator.device_status( ApplicationMqttDeviceStatusEvidence( vendor_device_id_sha256=_RECOVERY_VENDOR_HASH, device_serial_sha256=_RECOVERY_SERIAL_HASH, session_state="ready", session_state_code=MODELING_STATE_BASE + 300, project_bound=False, project_id_sha256=None, init_ready=False, status_message_sha256="3" * 64, mqtt_retained=False, observed_at_utc="2026-08-09T12:10:03.000Z", ) ) coordinator.resolve("stop") control.state = "completed" ready = restarted.state() assert ready["physical_command"]["record"]["resolution"] == "stop-standby-observed" assert ready["physical_command"]["resolved_active_recovery_required"] is False assert ready["connection_lifecycle"]["mode_selection"]["allowed"] is True terminal_stop = next( operation for operation in ready["operations"] if operation["operation_id"] == stop_operation_id ) assert terminal_stop["status"] == "succeeded" assert published_physical_edges == ["stop"] def test_active_reconciliation_survives_post_commit_adoption_failure_and_next_ready_verify( tmp_path: Path, ) -> None: service, _ = service_with_fake_runtime(tmp_path) coordinator = _VerifyPhysicalRecoveryCoordinator( observed_session_state="scanning", reconciliation_ready=True, ) _install_synthetic_verify_recovery(service, coordinator) bootstrap_attempts = 0 async def bootstrap_with_first_adoption_failure( bound_service: XgridsK1CompatibilityService, *, parent_operation_id: str | None, connection_mode: facade_module.ConnectionMode, inspection_only: bool = False, ) -> None: nonlocal bootstrap_attempts bootstrap_attempts += 1 await _synthetic_prestart_control_bootstrap( bound_service, parent_operation_id=parent_operation_id, connection_mode=connection_mode, inspection_only=inspection_only, ) bound_service._acquire_application_control_process_lease() # noqa: SLF001 if bootstrap_attempts == 1: control = bound_service._application_control_session # noqa: SLF001 def fail_after_durable_commit(*_args: object, **_kwargs: object) -> None: raise RuntimeError("synthetic adoption loss after ledger commit") control.adopt_reconciled_scanning = fail_after_durable_commit # type: ignore[method-assign] service._bootstrap_prestart_control_ready_owned = MethodType( # type: ignore[method-assign] # noqa: SLF001 bootstrap_with_first_adoption_failure, service, ) first_operation = "op-00000000-0000-4000-8000-000000001210" with pytest.raises(facade_module.ConnectionVerificationError): asyncio.run( service.verify_connection( _retained_physical_recovery_verify_request(operation_id=first_operation) ) ) after_failure = service.state() assert coordinator.resolution == "physical-active-observed" assert after_failure["physical_command"]["resolved_active_recovery_required"] is True assert after_failure["application_control_session"]["state"] == "idle" mutation_reasons = after_failure["connection_policy"]["actions"][ "provision-fresh-device" ]["reason_codes"] assert "physical-command-reconciliation-required" in mutation_reasons assert "physical-device-already-active" in mutation_reasons assert after_failure["connection_policy"]["actions"]["verify-control-device-info"][ "allowed" ] is True coordinator.observed_session_state = "ready" second_operation = "op-00000000-0000-4000-8000-000000001211" verify_result = asyncio.run( service.verify_connection( _retained_physical_recovery_verify_request(operation_id=second_operation) ) ) recovered = service.state() assert coordinator.reconciliation_ids == [ f"{first_operation}.physical", f"{second_operation}.physical", ] assert coordinator.resolution == "physical-standby-observed" assert verify_result["last_operation"]["status"] == "succeeded" assert recovered["physical_command"]["resolved_active_recovery_required"] is False assert recovered["physical_command"]["requires_reconciliation"] is False assert recovered["connection_lifecycle"]["mode_selection"]["allowed"] is True, recovered[ "connection_lifecycle" ]["mode_selection"] @pytest.mark.parametrize( ("proof_kind", "observed_session_state"), [ ("missing-status", None), ("retained-status", "ready"), ("stale-device-info", None), ], ) def test_explicit_verify_fails_closed_without_fresh_physical_recovery_proof( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, proof_kind: str, observed_session_state: str | None, ) -> None: del proof_kind service, _ = service_with_fake_runtime(tmp_path) coordinator = _VerifyPhysicalRecoveryCoordinator( observed_session_state=observed_session_state, reconciliation_ready=False, ) _install_synthetic_verify_recovery(service, coordinator) monkeypatch.setattr( facade_module, "PHYSICAL_RECONCILIATION_PROOF_TIMEOUT_SECONDS", 0.0, ) operation_id = "op-00000000-0000-4000-8000-000000001203" with pytest.raises(facade_module.ConnectionVerificationError) as raised: asyncio.run( service.verify_connection( _retained_physical_recovery_verify_request(operation_id=operation_id) ) ) assert raised.value.reason_code == "physical-command-reconciliation-proof-timeout" assert coordinator.reconciliation_ids == [] state = service.state() operation = next(item for item in state["operations"] if item["operation_id"] == operation_id) assert operation["status"] == "failed" assert operation["stage_code"] == "physical-reconciliation-failed" assert operation["error"]["code"] == ("physical-command-reconciliation-proof-timeout") assert operation["error"]["safe_to_retry"] is True assert operation["error"]["side_effect_status"] == "none" assert state["application_control_session"]["state"] == "idle" assert service._application_control_process_lease_holders == set() # noqa: SLF001 assert state["connection_policy"]["actions"]["verify-control-device-info"]["allowed"] is True def test_bootstrap_identity_rejection_retires_only_session_opened_by_attempt( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: """Rejected DeviceInfo cannot leak a ready socket or process lease.""" service, _ = service_with_fake_runtime(tmp_path) control = FakeInteractiveControlSession(initial_state="idle") service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 _seed_supervised_connection( service, connection_mode="bridge", transport_ref="k1-a", with_control=False, ) physical_edges: list[str] = [] def reject_identity(**_: object) -> None: raise DeviceIdentityPinStoreCorrupt("synthetic DeviceInfo pin rejection") monkeypatch.setattr(service, "_pin_or_match_device_identity", reject_identity) monkeypatch.setattr( service._physical_command_coordinator, # noqa: SLF001 "prepare", lambda *_args, **_kwargs: physical_edges.append("physical-command"), ) with pytest.raises(facade_module.ConnectionVerificationError) as rejected: asyncio.run( XgridsK1CompatibilityService._bootstrap_prestart_control_ready_owned( # noqa: SLF001 service, parent_operation_id=None, connection_mode="bridge", ) ) assert rejected.value.reason_code == "control-bootstrap-device-identity-unverified" assert physical_edges == [] state = service.state() assert state["application_control_session"]["state"] == "idle" assert service._application_control_process_lease_holders == set() # noqa: SLF001 assert state["active_connection_mode"] is None assert state["connection_policy"]["actions"]["scan-ble"]["allowed"] is True assert state["connection_policy"]["actions"]["verify-control-device-info"]["allowed"] is True @pytest.mark.parametrize("inspection_only", [True, False], ids=["verify", "ordinary"]) def test_read_only_bootstrap_detaches_physical_observer_before_fresh_control_open( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, inspection_only: bool, ) -> None: service, _ = service_with_fake_runtime(tmp_path) control = FakeInteractiveControlSession(initial_state="idle") service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 _seed_supervised_connection( service, connection_mode="bridge", transport_ref="k1-a", with_control=False, ) ordering: list[str] = [] def detach_before_read_only_open() -> None: ordering.append("physical-observer-detached") monkeypatch.setattr( service._physical_command_coordinator, # noqa: SLF001 "prepare_read_only_bootstrap", detach_before_read_only_open, ) original_open = control.open def open_after_detach( *, connection_binding: ApplicationConnectionBinding, **kwargs: object, ) -> dict[str, object]: if inspection_only: assert ordering == ["physical-observer-detached"] else: assert ordering == [] ordering.append("fresh-control-observer-opened") return original_open(connection_binding=connection_binding, **kwargs) monkeypatch.setattr(control, "open", open_after_detach) asyncio.run( XgridsK1CompatibilityService._bootstrap_prestart_control_ready_owned( # noqa: SLF001 service, parent_operation_id=None, connection_mode="bridge", inspection_only=inspection_only, ) ) assert ordering == ( ["physical-observer-detached", "fresh-control-observer-opened"] if inspection_only else ["fresh-control-observer-opened"] ) assert control.state == "connection-ready" def test_polling_self_cleans_prepared_acquisition_after_proven_prestart_failure( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: """A battery/control loss before START recovers without refresh or ABORT.""" service, runtime = service_with_fake_runtime(tmp_path) _select_connection_mode(service, "quick-connect") class TerminalPrestartControl(FakeInteractiveControlSession): failure: dict[str, object] | None = None def snapshot(self) -> dict[str, object]: snapshot = super().snapshot() snapshot["failure"] = self.failure return snapshot control = TerminalPrestartControl() service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 binding = _seed_supervised_connection( service, target_ipv4=facade_module.AP_FALLBACK_IPV4, connection_mode="quick-connect", transport_ref="k1-a", ) control.verified_control = _verified_control_for_binding(binding) prepared = service.prepare_acquisition( _prepare_request( project_name="TEST001", host=facade_module.AP_FALLBACK_IPV4, compatibility_attestation=QUICK_CONNECT_ATTESTATION, ) ) assert prepared["acquisition"]["state"] == "prepared" service._acquire_application_control_process_lease() # noqa: SLF001 physical_or_network_edges: list[str] = [] monkeypatch.setattr( service._physical_command_coordinator, # noqa: SLF001 "prepare", lambda *_args, **_kwargs: physical_or_network_edges.append("physical-command"), ) async def forbidden_device_write(*_: object, **__: object) -> dict[str, Any]: physical_or_network_edges.append("network-write") raise AssertionError("polling recovery must remain read/local-only") monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_device_write) control.state = "failed" control.failure = { "reason_code": "mqtt_network_loop_failed", "modeling_command_attempted": False, "safe_to_retry": True, "network_change_admissible": True, } recovered = service.state() assert physical_or_network_edges == [] assert runtime.start_calls == [] assert runtime.stop_calls == 0 assert recovered["acquisition"]["state"] == "aborted" assert recovered["acquisition"]["result"] == { "receiver_started": False, "device_command_attempted": False, "reason_code": "prestart-control-terminal-failure", } assert recovered["application_control_session"]["state"] == "idle" assert service._application_control_process_lease_holders == set() # noqa: SLF001 assert recovered["connection_policy"]["actions"]["scan-ble"]["allowed"] is True @pytest.mark.parametrize("observed_session_state", ["ready", "scanning"]) def test_verify_classification_settles_original_prepared_stop_as_not_dispatched( tmp_path: Path, observed_session_state: str, ) -> None: service, _ = service_with_fake_runtime(tmp_path) original_stop_operation_id = "op-00000000-0000-4000-8000-000000001409" operation, created = service._operations.begin( # noqa: SLF001 facade_module.ACTION_ACQUISITION_STOP, operation_id=original_stop_operation_id, device_id="known-k1", device_session_id="old-stop-session", deadline_seconds=60.0, idempotency_key="old-prepared-stop", ) assert created is True service._operations.transition( # noqa: SLF001 operation.operation_id, "running", stage_code="awaiting-external-stop", message_code="acquisition.stop.device_stopping", ) coordinator = _VerifyPhysicalRecoveryCoordinator( observed_session_state=observed_session_state, reconciliation_ready=True, prepared_stop_operation_id=original_stop_operation_id, ) _install_synthetic_verify_recovery(service, coordinator) verify_operation_id = "op-00000000-0000-4000-8000-000000001410" verified = asyncio.run( service.verify_connection( _retained_physical_recovery_verify_request(operation_id=verify_operation_id) ) ) original = service._operations.get(original_stop_operation_id) # noqa: SLF001 assert original.status == "failed" assert original.stage_code == "physical-stop-classified-not-dispatched" assert original.error == { "category": "device", "code": "physical-stop-not-dispatched", "retryable": False, "safe_to_retry": False, "side_effect_status": "none", "physical_command_sent": False, "automatic_replay_allowed": False, } assert coordinator._resolved_record(f"{verify_operation_id}.physical")["resolution"] == ( # noqa: SLF001 "not-dispatched" ) if observed_session_state == "scanning": assert verified["acquisition"]["result"]["physical_command_operation_id"] == ( original_stop_operation_id ) assert verified["application_control_session"]["can_stop"] is True else: assert verified["application_control_session"]["can_stop"] is False acquisition = verified.get("acquisition") assert not ( isinstance(acquisition, dict) and isinstance(acquisition.get("result"), dict) and acquisition["result"].get("recovery_only") is True ) @pytest.mark.parametrize("observed_session_state", ["ready", "scanning"]) def test_public_verify_reconciles_fresh_service_resolved_unclassified_stop_without_writes( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, observed_session_state: str, ) -> None: original, _ = service_with_fake_runtime(tmp_path) stop_operation_id, compatibility_revision = ( _persist_resolved_unclassified_stop_for_restart(original) ) restarted, runtime = service_with_fake_runtime(tmp_path) before = restarted._physical_command_ledger.snapshot().record # noqa: SLF001 assert before is not None assert before.operation_id == stop_operation_id assert before.revision == compatibility_revision assert before.stage == "resolved" assert before.resolution == "not-dispatched" assert before.resolved_unclassified_stop_recovery_required is True assert restarted._acquisition is None # noqa: SLF001 forbidden_io: list[str] = [] async def forbid_device_io(*_args: object, **_kwargs: object) -> object: forbidden_io.append("device-io") raise AssertionError("resolved STOP Verify must stay read-only") monkeypatch.setattr(facade_module, "read_wifi_status_once", forbid_device_io) monkeypatch.setattr(facade_module, "provision_wifi_once", forbid_device_io) _install_real_coordinator_verify_recovery( restarted, observed_session_state=observed_session_state, ) verify_operation_id = "op-00000000-0000-4000-8000-000000001411" verified = asyncio.run( restarted.verify_connection( _retained_physical_recovery_verify_request( operation_id=verify_operation_id, ) ) ) after = restarted._physical_command_ledger.snapshot().record # noqa: SLF001 assert after is not None assert after.operation_id == stop_operation_id assert after.revision == compatibility_revision + 1 assert after.stage == "resolved" assert after.resolution == "not-dispatched" assert after.resolved_unclassified_stop_recovery_required is False classification = after.reconciliations[-1] assert classification.kind == "prepared-stop-classification" assert classification.original_attempt.stage == "resolved" assert classification.original_attempt.resolution == "not-dispatched" assert classification.resolution == ( "physical-active-observed" if observed_session_state == "scanning" else "physical-standby-observed" ) assert verified["last_operation"]["operation_id"] == verify_operation_id assert verified["last_operation"]["status"] == "succeeded" assert verified["last_operation"]["result"]["write_performed"] is False assert verified["last_operation"]["result"]["physical_reconciliation"] == { "performed": True, "resolution": classification.resolution, "observed_session_state": observed_session_state, "device_write_performed": False, "automatic_retry": False, } control = restarted._application_control_session # noqa: SLF001 assert isinstance(control, FakeInteractiveControlSession) assert control.start_projects == [] assert control.stop_calls == 0 assert runtime.start_calls == [] assert runtime.stop_calls == 0 assert forbidden_io == [] if observed_session_state == "ready": assert verified.get("acquisition") is None assert verified["application_control_session"]["state"] == "connection-ready" assert verified["application_control_session"]["can_stop"] is False assert verified["connection_policy"]["actions"]["start-acquisition"][ "allowed" ] is True assert "physical-command-reconciliation-required" not in verified[ "connection_policy" ]["actions"]["start-acquisition"]["reason_codes"] assert verified["connection_lifecycle"]["mode_selection"]["allowed"] is False with pytest.raises(facade_module.NetworkProvisioningConflict) as mutation: restarted._require_physical_command_network_mutation_allowed() # noqa: SLF001 assert mutation.value.reason_code == "physical-command-reconciliation-required" else: assert verified["application_control_session"]["state"] == "scanning" assert verified["application_control_session"]["can_stop"] is True assert verified["acquisition"]["result"]["recovery_only"] is True assert verified["acquisition"]["result"]["physical_command_operation_id"] == ( stop_operation_id ) assert verified["connection_policy"]["actions"]["start-acquisition"][ "allowed" ] is False assert verified["connection_policy"]["actions"]["stop-acquisition"][ "allowed" ] is True def test_restart_classified_ready_uses_fresh_live_binding_for_one_start( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: """C1 proves historical standby; fresh DeviceInfo + live READY on C2 owns START.""" original, _ = service_with_fake_runtime(tmp_path) stop_operation_id, c1 = _persist_classified_ready_stop_for_restart(original) classified = original._physical_command_ledger.snapshot().record # noqa: SLF001 assert classified is not None assert classified.operation_id == stop_operation_id assert classified.reconciliations[-1].verified_binding.connection == c1 restarted, runtime = service_with_fake_runtime(tmp_path) binding = _seed_supervised_connection( restarted, target_ipv4="192.168.68.52", connection_mode="bridge", transport_ref="test-ble-transport", logical_device_id="known-k1", ) stable_path = _direct_host_path(binding.target_ipv4) monkeypatch.setattr( restarted, "_sample_host_path", lambda *_args, **_kwargs: stable_path, ) control = _BindingValidatingControlSession(restarted, binding) control.open(connection_binding=binding) control.verified_control = _verified_control_for_binding( binding, logical_device_id="known-k1", control_session_id="fresh-live-c2-control", control_proof_revision=2, ) restarted._application_control_session = control # type: ignore[assignment] # noqa: SLF001 restarted._reconcile_connection_supervisor( # noqa: SLF001 control.snapshot(), runtime.snapshot(), ) restarted._acquire_application_control_process_lease() # noqa: SLF001 coordinator = restarted._physical_command_coordinator # noqa: SLF001 observed_at_utc = datetime.now(UTC).isoformat(timespec="milliseconds").replace( "+00:00", "Z", ) coordinator.application_response( ApplicationMqttResponseEvidence( operation_key="bootstrap:fresh-live-c2:DeviceInfoRequest", response_topic="lixel/application/response/device_info", payload_sha256="6" * 64, modeling_action=None, result_code=None, success=None, observed_at_utc=observed_at_utc, ) ) verified = control.verified_control assert verified is not None c2 = PhysicalCommandRuntimeBinding( vendor_device_id_sha256=_RECOVERY_VENDOR_HASH, device_serial_sha256=_RECOVERY_SERIAL_HASH, compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID, intent_id=str(verified["intent_id"]), transport_ref=str(verified["transport_ref"]), connection_mode=verified["connection_mode"], # type: ignore[arg-type] target_ipv4=str(verified["target_ipv4"]), target_port=int(verified["target_port"]), host_path_epoch=int(verified["host_path_epoch"]), control_session_id=str(verified["control_session_id"]), producer_generation=int(verified["producer_generation"]), ) assert c2.control_session_id != c1.control_session_id coordinator.bind_control_session(c2) coordinator.device_status( ApplicationMqttDeviceStatusEvidence( vendor_device_id_sha256=_RECOVERY_VENDOR_HASH, device_serial_sha256=_RECOVERY_SERIAL_HASH, session_state="ready", session_state_code=MODELING_STATE_BASE + 300, project_bound=False, project_id_sha256=None, init_ready=False, status_message_sha256="7" * 64, mqtt_retained=False, observed_at_utc=observed_at_utc, ) ) inherited_reconciliations = classified.reconciliations ready = restarted.state() workspace = restarted.enter_application_workspace( EnterApplicationWorkspaceRequest( operator_confirmed=True, expected_session_generation=ready["application_control_session"][ "session_generation" ], expected_state_revision=ready["application_control_session"]["state_revision"], ) ) prepared = restarted.prepare_acquisition( _prepare_request( project_name="RESTART_READY_C2", host=binding.target_ipv4, compatibility_attestation=ATTESTATION, expected_control_session_generation=workspace["application_control_session"][ "session_generation" ], expected_control_state_revision=workspace["application_control_session"][ "state_revision" ], ) ) before_start = restarted._physical_command_ledger.snapshot().record # noqa: SLF001 assert before_start == classified assert before_start.reconciliations == inherited_reconciliations prepared_edges: list[str] = [] original_request_start = control.request_start def request_start_with_durable_edge( *, project_name: str, confirmation: object, command_context: object, preparation_checkpoint_observer: object | None = None, expected_session_generation: int | None = None, expected_state_revision: int | None = None, ) -> dict[str, object]: payload = b"fresh-start-on-c2" coordinator.prepare( command_context, # type: ignore[arg-type] action="start", envelope=OneShotPublishEnvelope( operation_key="modeling:start", topic="lixel/application/request/modeling", payload=payload, payload_sha256=hashlib.sha256(payload).hexdigest(), payload_bytes=len(payload), qos=2, retain=False, ), ) prepared_edges.append("start") return original_request_start( project_name=project_name, confirmation=confirmation, command_context=command_context, preparation_checkpoint_observer=preparation_checkpoint_observer, expected_session_generation=expected_session_generation, expected_state_revision=expected_state_revision, ) control.request_start = request_start_with_durable_edge # type: ignore[method-assign] start_operation_id = "op-00000000-0000-4000-8000-000000001412" started = restarted.start_acquisition( _start_request( acquisition_id=prepared["acquisition"]["acquisition_id"], operation_id=start_operation_id, physical_acceptance=PHYSICAL_ACCEPTANCE, expected_control_session_generation=prepared["application_control_session"][ "session_generation" ], expected_control_state_revision=prepared["application_control_session"][ "state_revision" ], ) ) successor = restarted._physical_command_ledger.snapshot().record # noqa: SLF001 assert successor is not None assert successor.operation_id == start_operation_id assert successor.parent_operation_id == stop_operation_id assert successor.action == "start" assert successor.stage == "prepared" assert successor.connection.control_session_id == c2.control_session_id assert successor.connection.host_path_epoch == c2.host_path_epoch assert successor.connection.producer_generation == c2.producer_generation assert successor.baseline_status.control_session_id == c2.control_session_id assert successor.reconciliations == inherited_reconciliations assert prepared_edges == ["start"] assert control.start_projects == ["RESTART_READY_C2"] assert len(runtime.start_calls) == 1 assert started["acquisition"]["state"] == "starting" def test_recovered_terminal_stop_losing_wifi_stays_acknowledged_unconfirmed_and_never_replays( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: service, runtime = service_with_fake_runtime(tmp_path) class TerminalStopControl(FakeInteractiveControlSession): failure: dict[str, object] | None = None def snapshot(self) -> dict[str, object]: snapshot = super().snapshot() snapshot["failure"] = self.failure return snapshot control = TerminalStopControl(initial_state="workspace-ready") service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 binding = _seed_supervised_connection( service, connection_mode="bridge", transport_ref="k1-a", ) control.verified_control = _verified_control_for_binding(binding) prepared = service.prepare_acquisition( _prepare_request( project_name="RECOVERED_STOP", host="192.168.1.20", compatibility_attestation=ATTESTATION, ) ) acquisition_id = prepared["acquisition"]["acquisition_id"] service.start_acquisition( _start_request( acquisition_id=acquisition_id, physical_acceptance=PHYSICAL_ACCEPTANCE, ) ) start_operation_id = service._acquisition_start_operation_id # noqa: SLF001 assert isinstance(start_operation_id, str) monkeypatch.setattr( service._physical_command_coordinator, # noqa: SLF001 "snapshot", lambda: _exact_start_physical_proof( operation_id=start_operation_id, acquisition_id=acquisition_id, binding=binding, resolved=True, ), ) runtime.mark_ready() runtime.pcl_frames = 1 acquiring = service.state() assert acquiring["acquisition"]["state"] == "acquiring" # Model the already-sealed local half after power loss. A later read-only # Verify has adopted SCANNING, so the terminal acquisition exposes one # explicit canonical STOP without restarting the receiver or capture. service._stop_acquisition_sources( # noqa: SLF001 camera_status="failed", camera_failure_code="power-loss-before-recovery-stop", ) with service._lock: # noqa: SLF001 assert service._acquisition is not None # noqa: SLF001 service._acquisition.transition( # noqa: SLF001 "failed", message_code="acquisition.connection_lost", result={"receiver_stopped": True, "device_state": "active-unconfirmed"}, ) control.state = "scanning" stop_operation_id = "op-00000000-0000-4000-8000-000000001220" stop_request = _stop_request( acquisition_id=acquisition_id, operation_id=stop_operation_id, mode="graceful", physical_acceptance=PHYSICAL_ACCEPTANCE, ) issued = service.stop_acquisition(stop_request) assert issued["acquisition"]["state"] == "failed" assert control.stop_calls == 1 stop_operation = next( operation for operation in issued["operations"] if operation["operation_id"] == stop_operation_id ) assert stop_operation["status"] == "running" control.state = "failed" control.failure = { "reason_code": "mqtt_network_loop_failed", "safe_to_retry": False, "modeling_command_attempted": True, "network_change_admissible": True, "network_change_reconciliation": { "device_session_state": "scan_stopping", "device_project_bound": True, "system_error_code": None, "stop_complete": True, "standby_confirmed": False, "automatic_retry": False, }, } physical_proof = { "status": "unresolved", "reason_code": "physical-command-reconciliation-required", "requires_reconciliation": True, "resolved_active_recovery_required": False, "record": { "operation_id": stop_operation_id, "action": "stop", "stage": "observing", "resolution": None, "application_response": {"action": "stop", "success": True}, "last_status": { "session_state": "scan_stopping", "mqtt_retained": False, "project_bound": True, "system_error_code": None, }, "connection": { "transport_ref": "k1-a", "connection_mode": "bridge", }, "reconciliations": [], }, } monkeypatch.setattr( service._physical_command_coordinator, # noqa: SLF001 "snapshot", lambda: physical_proof, ) recovered = service.state() terminal_stop = next( operation for operation in recovered["operations"] if operation["operation_id"] == stop_operation_id ) assert terminal_stop["status"] == "failed" assert terminal_stop["stage_code"] == "stop-acknowledged-standby-unconfirmed" assert terminal_stop["error"] == { "category": "device", "code": "stop-acknowledged-standby-unconfirmed", "retryable": False, "safe_to_retry": False, "side_effect_status": "unknown", "automatic_replay_allowed": False, } assert recovered["application_control_session"]["state"] == "idle" assert recovered["source_mode"] == "idle" assert recovered["acquisition"]["cleanup_pending"] is False assert control.stop_calls == 1 repeated = service.stop_acquisition(stop_request) repeated_stop = next( operation for operation in repeated["operations"] if operation["operation_id"] == stop_operation_id ) assert repeated_stop["stage_code"] == "stop-acknowledged-standby-unconfirmed" assert control.stop_calls == 1 def test_mode_select_winner_fences_concurrent_prepare_before_stale_record( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: """PREPARE and Mode Select share one winner before local publication.""" service, runtime = service_with_fake_runtime(tmp_path) _select_connection_mode(service, "quick-connect") control = FakeInteractiveControlSession(initial_state="connection-ready") service._application_control_session = control # type: ignore[assignment] # noqa: SLF001 binding = _seed_supervised_connection( service, target_ipv4=facade_module.AP_FALLBACK_IPV4, connection_mode="quick-connect", transport_ref="k1-a", ) control.verified_control = _verified_control_for_binding(binding) selection_entered = threading.Event() release_selection = threading.Event() selection_results: list[dict[str, Any]] = [] selection_failures: list[BaseException] = [] original_runtime_snapshot = runtime.snapshot snapshot_pause_used = False snapshot_pause_lock = threading.Lock() def paused_selection_runtime_snapshot() -> dict[str, object]: nonlocal snapshot_pause_used should_pause = False if threading.current_thread().name == "mode-select-winner": with snapshot_pause_lock: if not snapshot_pause_used: snapshot_pause_used = True should_pause = True if should_pause: selection_entered.set() assert release_selection.wait(2.0) return original_runtime_snapshot() monkeypatch.setattr(runtime, "snapshot", paused_selection_runtime_snapshot) def run_selection() -> None: try: selection_results.append( service.select_connection_mode( DesiredConnectionModeRequest( connection_mode="bridge", expected_revision=1, ) ) ) except BaseException as exc: # pragma: no cover - assertion aid selection_failures.append(exc) selection_thread = threading.Thread( target=run_selection, name="mode-select-winner", daemon=True, ) selection_thread.start() assert selection_entered.wait(2.0) try: with pytest.raises(facade_module.ApplicationControlProcessLeaseUnavailable): service.prepare_acquisition( _prepare_request( project_name="STALE01", host=facade_module.AP_FALLBACK_IPV4, compatibility_attestation=QUICK_CONNECT_ATTESTATION, ) ) finally: release_selection.set() selection_thread.join(timeout=3.0) assert selection_thread.is_alive() is False assert selection_failures == [] assert selection_results[0]["desired_connection_mode"] == "bridge" assert selection_results[0]["desired_connection_mode_revision"] == 2 assert service._acquisition is None # noqa: SLF001 assert control.state == "connection-ready" device_edges: list[str] = [] async def fake_scan( _duration_seconds: float, *, on_admitted: Callable[[], None] | None = None, ) -> dict[str, Any]: assert service._acquisition is None # noqa: SLF001 assert control.state == "idle" assert on_admitted is not None on_admitted() return _ble_scan_result("bridge-candidate") async def forbidden_network_write(*_: object, **__: object) -> dict[str, Any]: device_edges.append("network-write") raise AssertionError("losing PREPARE must not create a device edge") monkeypatch.setattr(facade_module, "scan", fake_scan) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_network_write) monkeypatch.setattr( service._physical_command_coordinator, # noqa: SLF001 "prepare", lambda *_args, **_kwargs: device_edges.append("physical-command"), ) scanned = asyncio.run(service.scan_ble(1.0)) assert device_edges == [] assert scanned["acquisition"] is None assert scanned["desired_connection_mode"] == "bridge" assert [item["device_id"] for item in scanned["devices"]] == ["bridge-candidate"] @pytest.mark.parametrize( ("network_stage", "expected_resolution", "expected_terminal_records"), [ ("prepared", "not-dispatched", 0), ("dispatching", "interrupted", 1), ("observing", "interrupted", 1), ], ids=["prepared", "dispatching", "observing"], ) def test_restart_after_any_open_network_stage_starts_with_a_clean_explicit_flow( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, network_stage: str, expected_resolution: str, expected_terminal_records: int, ) -> None: """CONN-08/11: restart terminalizes audit without restoring live authority.""" first, _ = service_with_fake_runtime(tmp_path) _seed_supervised_connection( first, target_ipv4="192.168.68.50", connection_mode="bridge", transport_ref="k1-a", logical_device_id="device-a", ) _set_scanned_k1(first, device_id="k1-a") _seed_legacy_network_mutation_without_idempotency( first, operation_id=f"restart-{network_stage}-operation", stage=network_stage, ) assert first.state()["selected_device_id"] == "k1-a" # A process restart loses every CoreBluetooth object even when the same # macOS UUID is later advertised again. Construction/recovery is durable # bookkeeping only and may not discover, read or write the device. _SYNTHETIC_SCAN_CAPTURES.clear() implicit_device_edges: list[str] = [] async def forbidden_scan(*_: object, **__: object) -> dict[str, Any]: implicit_device_edges.append("scan") raise AssertionError("restart recovery must not scan automatically") async def forbidden_read(*_: object, **__: object) -> dict[str, Any]: implicit_device_edges.append("read") raise AssertionError("restart recovery must not open GATT automatically") async def forbidden_write(*_: object, **__: object) -> dict[str, Any]: implicit_device_edges.append("write") raise AssertionError("restart recovery must not replay a network write") monkeypatch.setattr(facade_module, "scan", forbidden_scan) monkeypatch.setattr(facade_module, "read_wifi_status_once", forbidden_read) monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_write) restarted, _ = service_with_fake_runtime(tmp_path) state = restarted.state() assert implicit_device_edges == [] assert state["devices"] == [] assert state["selected_device_id"] is None assert state["device_session"] is None assert state["current_device_recovery"] is None assert state["configured_connection_mode"] is None assert state["active_connection_mode"] is None assert state["connection_lifecycle"]["active_binding"] is None assert state["connection_lifecycle"]["connection_ready"] is False assert state["network_write_reconciliation"] is None assert state["network_mutation_ledger"]["status"] == "resolved" assert state["network_mutation_ledger"]["resolution"] == expected_resolution assert state["network_provisioning_idempotency"]["active_operation_id"] is None assert state["network_provisioning_idempotency"]["terminal_record_count"] == ( expected_terminal_records ) assert state["connection_policy"]["actions"]["scan-ble"]["allowed"] is True assert state["connection_lifecycle"]["automatic_retry"] is False # A later advertisement is only a fresh candidate. It does not resurrect # the old binding, but it does make a new explicit Connect admissible. _set_scanned_k1(restarted, device_id="k1-a") fresh = restarted.state() assert fresh["selected_device_id"] is None assert fresh["active_connection_mode"] is None assert fresh["connection_policy"]["actions"]["provision-fresh-device"]["allowed"] is True assert implicit_device_edges == [] def test_power_loss_before_network_prepare_clears_selection_without_write_or_retry( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: """CONN-10: a pre-PREPARED disconnect is a clean, retryable no-write end.""" service, _ = service_with_fake_runtime(tmp_path) _seed_supervised_connection( service, target_ipv4=facade_module.AP_FALLBACK_IPV4, connection_mode="quick-connect", transport_ref="k1-a", logical_device_id="device-a", ) _set_scanned_k1(service, device_id="k1-a") provisioning_calls = 0 async def powered_off_before_prepare( *_: object, on_write_dispatch: Callable[[dict[str, Any], str], None] | None = None, **__: object, ) -> dict[str, Any]: nonlocal provisioning_calls provisioning_calls += 1 assert on_write_dispatch is not None error = RuntimeError("K1 powered off before durable prepare") error.operation_stage = "gatt-connect" # type: ignore[attr-defined] error.device_write_attempted = False # type: ignore[attr-defined] error.device_write_confirmed = False # type: ignore[attr-defined] raise error monkeypatch.setattr(facade_module, "provision_wifi_once", powered_off_before_prepare) with pytest.raises(RuntimeError, match="powered off before durable prepare"): asyncio.run( service.connect( _connect_request( device_id="k1-a", ssid="lab-router", password=SecretStr(PRIMARY_TEST_CREDENTIAL), connection_mode="bridge", compatibility_attestation=ATTESTATION, ) ) ) state = service.state() operation = next(item for item in state["operations"] if item["action"] == "network.provision") assert provisioning_calls == 1 assert state["selected_device_id"] is None assert state["device_session"] is None assert state["configured_connection_mode"] is None assert state["active_connection_mode"] is None assert state["network_mutation_ledger"]["status"] == "empty" assert state["network_provisioning_idempotency"]["active_operation_id"] is None assert operation["status"] == "failed" assert operation["error"]["side_effect_status"] == "none" assert operation["error"]["safe_to_retry"] is True assert operation["context"]["automatic_retry"] is False assert state["connection_attempt"]["phase"] == "network_not_applied" assert state["connection_attempt"]["side_effect_status"] == "none" assert state["connection_attempt"]["automatic_retry"] is False assert state["connection_policy"]["actions"]["scan-ble"]["allowed"] is True _set_scanned_k1(service, device_id="k1-a") assert ( service.state()["connection_policy"]["actions"]["provision-fresh-device"]["allowed"] is True ) assert provisioning_calls == 1 def test_power_loss_after_dispatch_becomes_terminal_unknown_without_replay( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: """CONN-12: a dispatched write is unknown audit, never an automatic retry.""" service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service, device_id="k1-a") write_calls = 0 async def powered_off_after_dispatch( *_: object, on_write_dispatch: Callable[[dict[str, Any], str], None] | None = None, **__: object, ) -> dict[str, Any]: nonlocal write_calls write_calls += 1 _dispatch_test_network_write(on_write_dispatch) error = RuntimeError("K1 powered off after dispatch") error.operation_stage = "gatt-write" # type: ignore[attr-defined] error.device_write_attempted = True # type: ignore[attr-defined] error.device_write_confirmed = False # type: ignore[attr-defined] raise error monkeypatch.setattr(facade_module, "provision_wifi_once", powered_off_after_dispatch) with pytest.raises(RuntimeError, match="powered off after dispatch"): asyncio.run( service.connect( _connect_request( device_id="k1-a", ssid="lab-router", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, ) ) ) # The old advertisement may already be gone after the failed write. The # durable unresolved ledger still pins an exact read-only target and must # outrank a generic new scan in current operator guidance. _set_scanned_devices(service, []) failed = service.state() failed_operation = next( item for item in failed["operations"] if item["action"] == "network.provision" ) assert write_calls == 1 assert failed["selected_device_id"] is None assert failed["device_session"] is None assert failed["network_mutation_ledger"]["status"] == "unresolved" assert failed["network_mutation_ledger"]["stage"] == "dispatching" assert failed_operation["error"]["side_effect_status"] == "unknown" assert failed_operation["error"]["safe_to_retry"] is False assert failed_operation["context"]["automatic_retry"] is False assert failed["connection_attempt"]["phase"] == "network_outcome_unknown" assert failed["connection_attempt"]["side_effect_status"] == "unknown" assert failed["connection_attempt"]["safe_next_action"] == "verify-control-read-only" assert failed["connection_attempt"]["automatic_retry"] is False assert ( failed["connection_policy"]["actions"]["observe-configured-device-network"]["allowed"] is True ) assert failed["connection_policy"]["recommended_action"] == ( "observe-configured-device-network" ) assert failed["connection_policy"]["actions"]["scan-ble"]["allowed"] is True _set_scanned_k1(service, device_id="k1-a") assert ( service.state()["connection_policy"]["actions"]["provision-fresh-device"]["allowed"] is True ) assert write_calls == 1 _SYNTHETIC_SCAN_CAPTURES.clear() restarted, _ = service_with_fake_runtime(tmp_path) terminal = restarted.state() assert write_calls == 1 assert terminal["selected_device_id"] is None assert terminal["device_session"] is None assert terminal["network_write_reconciliation"] is None assert terminal["network_mutation_ledger"]["status"] == "resolved" assert terminal["network_mutation_ledger"]["resolution"] == "interrupted" assert terminal["network_provisioning_idempotency"]["active_operation_id"] is None durable_terminal = ( restarted._require_network_provisioning_idempotency_journal() # noqa: SLF001 .snapshot() .records[-1] ) assert durable_terminal.terminal is not None assert durable_terminal.terminal.outcome_code == "network.provision.interrupted" assert durable_terminal.terminal.side_effect_status == "reconciled" assert durable_terminal.terminal.safe_to_retry is False _set_scanned_k1(restarted, device_id="k1-a") assert ( restarted.state()["connection_policy"]["actions"]["provision-fresh-device"]["allowed"] is True ) assert write_calls == 1 def test_power_loss_during_observation_preserves_audit_and_releases_ownership( monkeypatch: pytest.MonkeyPatch, tmp_path: Path, ) -> None: """CONN-13: bounded observation survives; selection and ownership do not.""" service, _ = service_with_fake_runtime(tmp_path) _set_scanned_k1(service, device_id="k1-a") baseline = _wifi_status_read(None, device_id="k1-a")["status"] bounded_baseline = {key: baseline[key] for key in ("mode", "ipv4", "status_code", "reserved")} write_calls = 0 async def power_lost_while_observing( *_: object, on_write_dispatch: Callable[[dict[str, Any], str], None] | None = None, **__: object, ) -> dict[str, Any]: nonlocal write_calls write_calls += 1 assert on_write_dispatch is not None on_write_dispatch(baseline, "with_response") return { "started_at_utc": "2026-08-08T10:00:00Z", "completed_at_utc": "2026-08-08T10:00:01Z", "profile_id": "xgrids-k1-fw3-wifi-v1", "outcome": "connection-lost-during-status-observation", "write_mode": "with_response", "baseline_status": baseline, "observations": [{"status": baseline}], } monkeypatch.setattr(facade_module, "provision_wifi_once", power_lost_while_observing) with pytest.raises(RuntimeError, match="не сообщило адрес"): asyncio.run( service.connect( _connect_request( device_id="k1-a", ssid="lab-router", password=SecretStr(PRIMARY_TEST_CREDENTIAL), compatibility_attestation=ATTESTATION, ) ) ) failed = service.state() failed_record = service._network_mutation_ledger.snapshot().record # noqa: SLF001 failed_operation = next( item for item in failed["operations"] if item["action"] == "network.provision" ) assert write_calls == 1 assert failed["selected_device_id"] is None assert failed["device_session"] is None assert failed["network_mutation_ledger"]["status"] == "unresolved" assert failed["network_mutation_ledger"]["stage"] == "observing" assert failed_record is not None assert failed_record.write_confirmed is True assert failed_record.last_observation is not None assert failed_record.last_observation.as_dict() == bounded_baseline assert failed_operation["error"]["side_effect_status"] == "unknown" assert failed_operation["error"]["safe_to_retry"] is False assert failed_operation["context"]["automatic_retry"] is False assert failed["connection_policy"]["actions"]["scan-ble"]["allowed"] is True _set_scanned_k1(service, device_id="k1-a") assert ( service.state()["connection_policy"]["actions"]["provision-fresh-device"]["allowed"] is True ) assert write_calls == 1 _SYNTHETIC_SCAN_CAPTURES.clear() restarted, _ = service_with_fake_runtime(tmp_path) terminal = restarted.state() terminal_record = restarted._network_mutation_ledger.snapshot().record # noqa: SLF001 assert write_calls == 1 assert terminal["selected_device_id"] is None assert terminal["device_session"] is None assert terminal["network_write_reconciliation"] is None assert terminal["network_mutation_ledger"]["status"] == "resolved" assert terminal["network_mutation_ledger"]["resolution"] == "interrupted" assert terminal_record is not None assert terminal_record.last_observation is not None assert terminal_record.last_observation.as_dict() == bounded_baseline assert terminal["network_provisioning_idempotency"]["active_operation_id"] is None _set_scanned_k1(restarted, device_id="k1-a") assert ( restarted.state()["connection_policy"]["actions"]["provision-fresh-device"]["allowed"] is True ) assert write_calls == 1