fix(k1): close verified stop checkpoint gap

This commit is contained in:
DCCONSTRUCTIONS
2026-08-14 19:46:51 +03:00
parent 17a07355cf
commit 4a24275ddc
4 changed files with 259 additions and 5 deletions
@@ -26,6 +26,7 @@ from k1link.device_plugins.xgrids_k1.connection_supervisor import (
)
from k1link.device_plugins.xgrids_k1.facade import (
XGRIDS_K1_COMPATIBILITY_PROFILE_ID,
ConnectionVerificationError,
OperatorPresenceRequest,
StopAcquisitionRequest,
XgridsK1CompatibilityService,
@@ -454,6 +455,143 @@ def test_repeated_reset_reopen_fresh_ready_ceases_old_active_checkpoint(
assert service._active_acquisition_checkpoint_trust == "trusted" # noqa: SLF001
def test_restart_ready_after_dispatched_stop_ceases_active_checkpoint(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
"""Fresh READY settles a dispatched STOP whose outcome crossed restart."""
service = _service(tmp_path, monkeypatch)
original = _connection(
control_session_id="checkpoint-dispatched-stop-original-control",
host_path_epoch=1,
producer_generation=1,
)
_prepare_and_activate_checkpoint(service, original)
ledger = service._physical_command_ledger # noqa: SLF001
identity = PhysicalCommandIdentity(
vendor_device_id_sha256=VENDOR_SHA256,
device_serial_sha256=SERIAL_SHA256,
)
ledger.prepare(
operation_id=FIRST_STOP_OPERATION_ID,
parent_operation_id=START_OPERATION_ID,
acquisition_id=ACQUISITION_ID,
action="stop",
identity=identity,
connection=original,
compatibility_profile_id=XGRIDS_K1_COMPATIBILITY_PROFILE_ID,
payload_sha256="2" * 64,
baseline_status=_status(
original,
"scanning",
observed_at_utc="2026-08-13T12:01:00.000Z",
),
)
ledger.mark_dispatching(FIRST_STOP_OPERATION_ID)
ledger.mark_observing(
FIRST_STOP_OPERATION_ID,
publish_call_returned=True,
packet_id=42,
)
ledger.mark_qos2_completed(FIRST_STOP_OPERATION_ID, packet_id=42)
ledger.record_application_response(
FIRST_STOP_OPERATION_ID,
PhysicalCommandApplicationResponse(
operation_id=FIRST_STOP_OPERATION_ID,
action="stop",
control_session_id=original.control_session_id,
host_path_epoch=original.host_path_epoch,
producer_generation=original.producer_generation,
result_code=PHYSICAL_COMMAND_APPLICATION_SUCCESS_CODE,
success=True,
payload_sha256="3" * 64,
observed_at_utc="2026-08-13T12:01:01.000Z",
),
)
service._snapshot_runtime_id = ( # noqa: SLF001
"snapshot-runtime-checkpoint-dispatched-stop-successor"
)
restarted = _connection(
control_session_id="checkpoint-dispatched-stop-restarted-control",
host_path_epoch=2,
producer_generation=2,
)
coordinator = service._physical_command_coordinator # noqa: SLF001
coordinator.application_response(
ApplicationMqttResponseEvidence(
operation_key="bootstrap:dispatched-stop-ready:DeviceInfoRequest",
response_topic="lixel/application/response/device_info",
payload_sha256="4" * 64,
modeling_action=None,
result_code=None,
success=None,
observed_at_utc="2026-08-13T12:02:00.000Z",
)
)
coordinator.bind_control_session(_runtime_binding(restarted))
coordinator.device_status(
ApplicationMqttDeviceStatusEvidence(
vendor_device_id_sha256=VENDOR_SHA256,
device_serial_sha256=SERIAL_SHA256,
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="2026-08-13T12:02:01.000Z",
)
)
control_snapshot = {
"state": "connection-ready",
"session_generation": 2,
"state_revision": 2,
"verified_control": _verified_control(restarted),
}
monkeypatch.setattr(
service._application_control_session, # noqa: SLF001
"snapshot",
lambda: dict(control_snapshot),
)
monkeypatch.setattr(
service._application_control_session, # noqa: SLF001
"validate_physical_reconciliation_binding",
lambda: None,
)
monkeypatch.setattr(
service,
"_settle_restart_checkpoint_after_verified_standby",
lambda **_kwargs: False,
)
with pytest.raises(ConnectionVerificationError):
asyncio.run(
service._reconcile_physical_command_after_verify_owned( # noqa: SLF001
verify_operation_id="checkpoint-dispatched-stop-ready-verify",
allow_receiver_rehydrate=False,
)
)
record = ledger.snapshot().record
assert record is not None
assert record.action == "stop"
assert record.resolution == "physical-standby-observed"
assert record.reconciliations[-1].kind == "ambiguous-outcome"
checkpoint = ActiveAcquisitionRecoveryCheckpointStore(tmp_path).snapshot().checkpoint
assert checkpoint is not None
assert checkpoint.state == "active"
# Simulate the exact live process boundary: the physical ledger fsync is
# durable, while checkpoint cessation did not commit in the prior process.
restarted_service = _service(tmp_path, monkeypatch)
assert restarted_service._active_acquisition_checkpoint_reason is None # noqa: SLF001
checkpoint = ActiveAcquisitionRecoveryCheckpointStore(tmp_path).snapshot().checkpoint
assert checkpoint is not None
assert checkpoint.state == "ceased"
def _published_point_cloud(sequence: int = 41) -> DecodedPointCloudView:
return DecodedPointCloudView(
context=ConsumerFrameContext(
@@ -1137,6 +1137,59 @@ def test_cease_active_reconciled_standby_atomically_opens_and_closes_gap(
restarted.cease_active_reconciled_standby(**stale)
def test_cease_active_reconciled_standby_accepts_ambiguous_stop_ready_proof(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
"""A dispatched STOP may receive its terminal READY only after restart."""
binding = _binding()
store = _store(tmp_path, monkeypatch)
_prepare(store, binding)
active = _activate(store, binding)
kwargs = _cease_active_reconciled_standby_kwargs(
active,
terminal_state="ready",
transition_id="transition-cease-active-ambiguous-stop-ready",
)
status = kwargs["cessation_status_proof"]
prior_physical = active.current_active_physical_proof
assert prior_physical is not None
ambiguous_stop = ActiveAcquisitionRecoveryPhysicalLineageProof(
ledger_schema_version=(
ACTIVE_ACQUISITION_RECOVERY_PHYSICAL_LEDGER_SCHEMA
),
ledger_revision=prior_physical.ledger_revision + 1,
proof_id="physical-ambiguous-stop-ready",
operation_id="operation-stop-ambiguous-ready",
original_start_operation_id=START_OPERATION_ID,
parent_operation_id=START_OPERATION_ID,
acquisition_id=ACQUISITION_ID,
action="stop",
resolution="physical-standby-observed",
payload_sha256=STOP_PAYLOAD_SHA256,
original_start_payload_sha256=START_PAYLOAD_SHA256,
reconciliation_kind="ambiguous-outcome",
reconciliation_resolution="physical-standby-observed",
status_message_sha256=status.status_message_sha256,
observed_session_state="ready",
binding=status.binding,
composite_complete=False,
edge_terminal=True,
late_start_excluded=True,
stop_fence="none",
observed_at_utc=status.observed_at_utc,
reconciliation_original_attempt_sha256="8" * 64,
)
kwargs["cessation_physical_proof"] = ambiguous_stop
ceased = store.cease_active_reconciled_standby(**kwargs)
assert ceased.state == "ceased"
assert ceased.cessation_status_proof == status
assert ceased.cessation_physical_proof == ambiguous_stop
def test_cease_active_reconciled_standby_atomically_closes_exact_open_gap(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,