Стабилизация подключения K1 после сна и ожидания Bluetooth

This commit is contained in:
DCCONSTRUCTIONS
2026-08-23 16:24:05 +03:00
parent 5ebc9fc27c
commit c041a569f6
9 changed files with 393 additions and 29 deletions
+84
View File
@@ -2222,6 +2222,90 @@ def test_start_outcome_unknown_blocks_reopen_even_when_transport_is_closed(
session.retire_for_network_change()
def test_post_start_read_only_timeout_preserves_durable_active_proof_without_stop_authority(
monkeypatch: pytest.MonkeyPatch,
) -> None:
class PostStartRefreshFailureExecutor(FakeExecutor):
start_attempted = False
start_active_confirmed = False
def execute_canonical_start(self, *_args: object, **kwargs: object) -> object:
type(self).start_attempted = True
self.records.append("start:11-12")
self.transport.ready = False
observer = kwargs.get("start_active_observer")
assert callable(observer)
observer()
type(self).start_active_confirmed = True
self.records.append("refresh:13-14-timeout")
raise ApplicationMqttTransportError(
"post-START read-only response timed out after host wake",
reason_code="mqtt_response_timeout",
)
def snapshot(self) -> dict[str, object]:
return {
"dialogue_stage": (
"start-active-observed"
if type(self).start_active_confirmed
else "start-attempted"
),
"start_attempted": type(self).start_attempted,
"start_active_confirmed": type(self).start_active_confirmed,
"start_complete": False,
"stop_attempted": False,
"response_evidence": [],
"automatic_retry": False,
}
FakeExecutor.records = []
PostStartRefreshFailureExecutor.start_attempted = False
PostStartRefreshFailureExecutor.start_active_confirmed = False
monkeypatch.setattr(
session_module,
"PhysicalAcceptanceDialogueExecutor",
PostStartRefreshFailureExecutor,
)
coordinator = FakePhysicalCommandCoordinator()
scanning_observed = threading.Event()
session = InteractiveApplicationControlSession(
FakeAuthorityLoader(),
transport_factory=lambda host: FakeTransport(host), # type: ignore[arg-type]
physical_command_coordinator=coordinator, # type: ignore[arg-type]
scanning_observer=scanning_observed.set,
)
coordinator.phase_probe = lambda: str(session.snapshot()["state"])
session.open(
host="192.168.1.20",
timezone_name="Europe/Moscow",
connection_binding=_connection_binding(),
)
_wait_phase(session, "connection-ready")
session.enter_workspace()
_wait_phase(session, "workspace-ready")
session.open_project_prompt()
_wait_phase(session, "project-ready")
session.request_start(
project_name="SLEEP_WAKE",
confirmation=_confirmation(),
command_context=_physical_context("start"),
preparation_checkpoint_observer=_successful_start_checkpoint_observer, # type: ignore[arg-type]
)
failed = _wait_phase(session, "failed")
assert coordinator.resolutions == [("start", "initializing")]
assert scanning_observed.is_set()
assert failed["can_stop"] is False
assert failed["outcome_unknown"] is True
assert failed["failure"]["reason_code"] == "mqtt_response_timeout" # type: ignore[index]
assert failed["dialogue"]["start_active_confirmed"] is True # type: ignore[index]
assert FakeExecutor.records[-2:] == [
"start:11-12",
"refresh:13-14-timeout",
]
@pytest.mark.parametrize(
("disconnect_error", "expected_reason_code"),
[