Безопасное завершение калибровки при отключении K1

This commit is contained in:
DCCONSTRUCTIONS
2026-08-23 13:55:28 +03:00
parent 3e5aedd74d
commit 6e7428a116
2 changed files with 314 additions and 10 deletions
+203
View File
@@ -17194,6 +17194,209 @@ def test_bound_scan_over_without_stop_dominates_late_empty_camera_epoch_failure(
assert control.stop_calls == stop_calls_before == 0
def test_accepted_start_then_scan_over_during_calibration_stops_local_wait_only(
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)
prepared = service.prepare_acquisition(
_prepare_request(
project_name="POWERLOSS001",
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)
physical = _exact_start_physical_proof(
operation_id=start_operation_id,
acquisition_id=acquisition_id,
binding=binding,
resolved=False,
)
physical.update(
{
"runtime_bound": True,
"reconciliation_ready": True,
"observed_session_state": "scan_over",
"active_operation_id": start_operation_id,
}
)
record = physical["record"]
assert isinstance(record, dict)
record["last_status"] = None
monkeypatch.setattr(
service._physical_command_coordinator, # noqa: SLF001
"snapshot",
lambda: physical,
)
runtime.mark_ready()
awaiting = service.state()
assert awaiting["acquisition"]["state"] == "awaiting_external_start"
assert runtime.pcl_frames == 0
original_control_snapshot = control.snapshot
def failed_during_calibration_snapshot() -> dict[str, object]:
snapshot = original_control_snapshot()
snapshot["outcome_unknown"] = True
snapshot["failure"] = {
"reason_code": "mqtt_network_loop_failed",
"failed_phase": "initializing",
"modeling_command_attempted": True,
"stop_command_attempted": False,
"diagnostic_snapshot_unavailable": [],
"diagnostic_evidence_unavailable": [],
"safe_to_retry": False,
}
snapshot["transport"] = {
"state": "failed",
"publish_attempts": 12,
"device_status_reports": 4,
"latest_device_session_state": "scan_over",
"latest_device_project_bound": True,
"latest_device_init_ready": False,
"latest_system_error_code": None,
"automatic_retry": False,
"automatic_reconnect": False,
}
return snapshot
monkeypatch.setattr(control, "snapshot", failed_during_calibration_snapshot)
control.state = "failed"
control.state_revision += 1
monkeypatch.setattr(service, "_seal_acquisition_capture_clock", lambda: None)
camera_stop_calls: list[str] = []
monkeypatch.setattr(
service.camera_preview,
"stop_current",
lambda: camera_stop_calls.append("stop") or {},
)
start_projects_before = list(control.start_projects)
physical_record_before = json.dumps(record, sort_keys=True)
terminal = service.state()
start_operation = next(
operation
for operation in terminal["operations"]
if operation["operation_id"] == start_operation_id
)
assert terminal["acquisition"]["state"] == "interrupted"
assert terminal["acquisition"]["message_code"] == (
"acquisition.recovery.device_standby_observed"
)
assert terminal["acquisition"]["result"] == {
"receiver_stopped": True,
"device_state": "scan_over",
"device_stop": "not-sent",
"automatic_command_retry": False,
"read_only_recovery": True,
"physical_reconciliation_required": True,
}
assert terminal["acquisition"]["cleanup_pending"] is False
assert start_operation["status"] == "interrupted"
assert start_operation["stage_code"] == (
"physical-start-active-but-no-point-before-standby"
)
assert start_operation["error"]["side_effect_status"] == "succeeded"
assert start_operation["error"]["automatic_replay_allowed"] is False
assert camera_stop_calls == ["stop"]
assert runtime.stop_calls == 1
assert control.start_projects == start_projects_before == ["POWERLOSS001"]
assert control.stop_calls == 0
assert physical["status"] == "unresolved"
assert physical["requires_reconciliation"] is True
assert json.dumps(record, sort_keys=True) == physical_record_before
repeated = service.state()
assert repeated["acquisition"] == terminal["acquisition"]
assert repeated["physical_command"]["status"] == "unresolved"
assert repeated["physical_command"]["requires_reconciliation"] is True
assert camera_stop_calls == ["stop"]
assert runtime.stop_calls == 1
assert control.start_projects == ["POWERLOSS001"]
assert control.stop_calls == 0
@pytest.mark.parametrize(
"invalid_proof",
[
"active-owner",
"application-response",
"binding-generation",
"qos2",
"retained-target",
],
)
def test_pre_active_scan_over_classifier_rejects_inexact_start_proof(
tmp_path: Path,
invalid_proof: 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)
operation_id = "op-00000000-0000-4000-8000-000000009901"
acquisition_id = "acq-00000000-0000-4000-8000-000000009901"
physical = _exact_start_physical_proof(
operation_id=operation_id,
acquisition_id=acquisition_id,
binding=binding,
resolved=False,
)
physical.update(
{
"runtime_bound": True,
"reconciliation_ready": True,
"observed_session_state": "scan_over",
"active_operation_id": operation_id,
}
)
record = physical["record"]
assert isinstance(record, dict)
record["last_status"] = None
verified_control = _verified_control_for_binding(binding)
if invalid_proof == "active-owner":
physical["active_operation_id"] = "op-other-start"
elif invalid_proof == "application-response":
response = record["application_response"]
assert isinstance(response, dict)
response["operation_id"] = "op-other-start"
elif invalid_proof == "binding-generation":
verified_control["producer_generation"] = 2
elif invalid_proof == "qos2":
record["qos2_completed"] = False
else:
record["last_status"] = {
"session_state": "scanning",
"project_bound": True,
"init_ready": True,
"mqtt_retained": True,
"system_error_code": None,
}
assert (
service._matching_accepted_start_scan_over_before_active( # noqa: SLF001
physical,
acquisition_id=acquisition_id,
start_operation_id=operation_id,
verified_control=verified_control,
)
is False
)
def test_active_stream_recovery_reopens_exact_camera_epoch_once_and_fences_stale_lineage(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,