From ac4a00c67dc4f96e007590d24de9faf6204c17b0 Mon Sep 17 00:00:00 2001 From: DCCONSTRUCTIONS Date: Thu, 20 Aug 2026 13:16:56 +0300 Subject: [PATCH] fix(k1): cease reset zero-dispatch checkpoint --- ...K1_OPERATOR_FLOW_INCREMENTAL_ACCEPTANCE.md | 9 +- src/k1link/device_plugins/xgrids_k1/facade.py | 26 +++++ .../test_xgrids_connection_scenario_reset.py | 98 +++++++++++++++++++ 3 files changed, 130 insertions(+), 3 deletions(-) diff --git a/docs/runbooks/K1_OPERATOR_FLOW_INCREMENTAL_ACCEPTANCE.md b/docs/runbooks/K1_OPERATOR_FLOW_INCREMENTAL_ACCEPTANCE.md index 127a1a4..6823260 100644 --- a/docs/runbooks/K1_OPERATOR_FLOW_INCREMENTAL_ACCEPTANCE.md +++ b/docs/runbooks/K1_OPERATOR_FLOW_INCREMENTAL_ACCEPTANCE.md @@ -81,9 +81,12 @@ Current violations observed on 2026-08-14: described below. - `K1-P0-RESET-CHECKPOINT`: an explicit local scenario reset resolved a zero-dispatch START as `not-dispatched`, but left its exact recovery - checkpoint revision 17 in `prepared`. No device/network command was sent; - the stale checkpoint blocks the next START and requires a local atomic - settlement fix before live acceptance continues. + checkpoint revision 17 in `prepared`. The reset now ceases that exact + checkpoint before publishing its replay marker; its reducer and the complete + scenario-reset suite are green. Live startup convergence is accepted: + checkpoint revision 18 is `ceased` against the unchanged physical + `not-dispatched` head, with no device/network command. Clean Bluetooth + selection and the next START remain to be accepted separately. - `K1-P1-STOP-STABILITY`: STOP authority visibly oscillated before the operator clicked. Not fixed in the checkpoint increment. - `K1-P1-PENDING-FEEDBACK`: reconnect/search/select/provision transitions replace diff --git a/src/k1link/device_plugins/xgrids_k1/facade.py b/src/k1link/device_plugins/xgrids_k1/facade.py index abe2cfd..cabcca2 100644 --- a/src/k1link/device_plugins/xgrids_k1/facade.py +++ b/src/k1link/device_plugins/xgrids_k1/facade.py @@ -8519,6 +8519,32 @@ class XgridsK1CompatibilityService: physical_preflight.get("record_revision"), ), ) + retired_physical_record = physical_retirement.get("record") + if ( + isinstance(retired_physical_record, Mapping) + and retired_physical_record.get("action") == "start" + and retired_physical_record.get("stage") == "resolved" + and retired_physical_record.get("resolution") == "not-dispatched" + ): + start_operation_id = retired_physical_record.get("operation_id") + start_acquisition_id = retired_physical_record.get("acquisition_id") + start_payload_sha256 = retired_physical_record.get("payload_sha256") + if not all( + isinstance(value, str) + for value in ( + start_operation_id, + start_acquisition_id, + start_payload_sha256, + ) + ): + raise ActiveAcquisitionRecoveryCheckpointError( + "scenario reset resolved START without exact checkpoint identity" + ) + self._cease_prepared_start_checkpoint_not_dispatched( + operation_id=cast(str, start_operation_id), + acquisition_id=cast(str, start_acquisition_id), + payload_sha256=cast(str, start_payload_sha256), + ) physical_disposition = str(physical_retirement.get("disposition") or "unknown") retired_physical_operation_id = physical_preflight.get("operation_id") with self._lock: diff --git a/tests/test_xgrids_connection_scenario_reset.py b/tests/test_xgrids_connection_scenario_reset.py index 84b3dc3..527a697 100644 --- a/tests/test_xgrids_connection_scenario_reset.py +++ b/tests/test_xgrids_connection_scenario_reset.py @@ -19,6 +19,12 @@ from k1link.device_plugins.xgrids_k1 import ( network_mutation_ledger as network_ledger_module, ) from k1link.device_plugins.xgrids_k1 import physical_command_ledger as ledger_module +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.facade import ( BleScanRequest, CompatibilityAttestationRequest, @@ -145,6 +151,58 @@ def _seed_resettable_physical_record( return record +def _seed_prepared_start_checkpoint( + service: XgridsK1CompatibilityService, + record: PhysicalCommandRecord, +) -> None: + store = service._active_acquisition_checkpoint # noqa: SLF001 + assert store is not None + project_name = "reset-prepared-checkpoint" + 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="reset-prepared-device", + 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, + ) + store.prepare( + transition_id=f"test-reset-prepare:{record.operation_id}", + predecessor_revision=0, + acquisition_id=record.acquisition_id, + original_start_operation_id=record.operation_id, + start_payload_sha256=record.payload_sha256, + identity=ActiveAcquisitionRecoveryIdentity( + logical_device_id="reset-prepared-device", + 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="reset-prepared-evidence", + duration_seconds=None, + requested_streams=("spatial.point-cloud.live",), + evidence_policy="required", + mount_type="handheld", + gnss_mode="none", + prepared_binding=binding, + ) + + def _install_exact_reset_scan( service: XgridsK1CompatibilityService, monkeypatch: pytest.MonkeyPatch, @@ -297,6 +355,46 @@ def test_cold_scenario_reset_is_local_only_and_exact_retry_converges( assert first["connection_policy"]["actions"]["scan-ble"]["allowed"] is True +def test_scenario_reset_ceases_exact_prepared_start_checkpoint( + monkeypatch: pytest.MonkeyPatch, + tmp_path: Path, +) -> None: + service = _service(monkeypatch, tmp_path) + record = _seed_resettable_physical_record(service, prepared_only=True) + _seed_prepared_start_checkpoint(service, record) + before = service._active_acquisition_checkpoint.snapshot() # type: ignore[union-attr] # noqa: SLF001 + assert before.status == "prepared" + + request = _reset( + mode="bridge", + revision=0, + reset_id="op-reset-prepared-checkpoint-01", + ) + reset = service.select_connection_mode(request) + + physical = service._physical_command_ledger.snapshot().record # noqa: SLF001 + checkpoint_snapshot = service._active_acquisition_checkpoint.snapshot() # type: ignore[union-attr] # noqa: SLF001 + checkpoint = checkpoint_snapshot.checkpoint + assert physical is not None + assert physical.stage == "resolved" + assert physical.resolution == "not-dispatched" + assert checkpoint_snapshot.status == "ceased" + assert checkpoint is not None + assert checkpoint.state == "ceased" + assert checkpoint.original_start_operation_id == record.operation_id + marker = reset["connection_scenario_reset"] + assert marker["physical_disposition"] == "not-dispatched" + assert marker["device_command_performed"] is False + assert marker["network_write_performed"] is False + + replayed = service.select_connection_mode(request) + assert replayed["connection_scenario_reset"] == marker + assert ( + service._active_acquisition_checkpoint.snapshot().checkpoint # type: ignore[union-attr] # noqa: SLF001 + == checkpoint + ) + + def test_reset_attempt_cutoff_uses_operation_identity_not_local_stage_sequence( monkeypatch: pytest.MonkeyPatch, tmp_path: Path,