Стабильное подключение в идеальных условиях K1
This commit is contained in:
@@ -1823,6 +1823,27 @@ def test_chained_stop_facade_cessation_uses_real_ledger_ancestry(
|
||||
assert ancestry is not None
|
||||
assert ancestry.head_parent_operation_id == FIRST_STOP_OPERATION_ID
|
||||
|
||||
# Reconciliations are append-only and a successor inherits its parent's
|
||||
# audit history. Even an otherwise valid standby reconciliation remains
|
||||
# owned by its original STOP and cannot prove the current STOP.
|
||||
stale_reconciliation = replace(
|
||||
first_reconciliation_proof,
|
||||
resolution="physical-standby-observed",
|
||||
observation=_status(
|
||||
first_rebind,
|
||||
"ready",
|
||||
source="explicit-read-only-reconciliation",
|
||||
observed_at_utc="2026-08-13T12:01:05.500Z",
|
||||
),
|
||||
)
|
||||
assert stale_reconciliation.original_attempt.operation_id == (
|
||||
FIRST_STOP_OPERATION_ID
|
||||
)
|
||||
assert not service._physical_reconciliation_belongs_to_record( # noqa: SLF001
|
||||
stale_reconciliation,
|
||||
final_record,
|
||||
)
|
||||
|
||||
service._application_control_session.snapshot = lambda: { # type: ignore[method-assign]
|
||||
"verified_control": _verified_control(first_rebind)
|
||||
}
|
||||
|
||||
@@ -500,6 +500,182 @@ def test_canonical_stages_require_operator_events_but_device_standby_does_not(
|
||||
]
|
||||
|
||||
|
||||
def test_session_checkpoints_do_not_repeat_native_dispatch_proof(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
"""Slow host-path proof belongs to the exact publish lease, not UI checkpoints."""
|
||||
|
||||
class DispatchingExecutor(FakeExecutor):
|
||||
def _dispatch_one_packet(self) -> None:
|
||||
guard = self.transport.dispatch_guard
|
||||
assert guard is not None
|
||||
release = guard()
|
||||
try:
|
||||
self.transport.publish_attempts += 1
|
||||
finally:
|
||||
if callable(release):
|
||||
release()
|
||||
|
||||
def run_workspace_entry_stage(
|
||||
self,
|
||||
orchestrator: object,
|
||||
checkpoint: object,
|
||||
*,
|
||||
dispatch_guard: Callable[[], None] | None = None,
|
||||
) -> LiveDeviceControlBinding:
|
||||
if dispatch_guard is not None:
|
||||
dispatch_guard()
|
||||
self._dispatch_one_packet()
|
||||
return super().run_workspace_entry_stage(
|
||||
orchestrator,
|
||||
checkpoint,
|
||||
dispatch_guard=None,
|
||||
)
|
||||
|
||||
def run_project_prompt_stage(
|
||||
self,
|
||||
orchestrator: object,
|
||||
checkpoint: object,
|
||||
*,
|
||||
dispatch_guard: Callable[[], None] | None = None,
|
||||
) -> LiveDeviceControlBinding:
|
||||
if dispatch_guard is not None:
|
||||
dispatch_guard()
|
||||
self._dispatch_one_packet()
|
||||
return super().run_project_prompt_stage(
|
||||
orchestrator,
|
||||
checkpoint,
|
||||
dispatch_guard=None,
|
||||
)
|
||||
|
||||
def execute_canonical_start(self, *_args: object, **kwargs: object) -> object:
|
||||
dispatch_guard = kwargs.get("dispatch_guard")
|
||||
if callable(dispatch_guard):
|
||||
dispatch_guard()
|
||||
self._dispatch_one_packet()
|
||||
return super().execute_canonical_start(*_args, **kwargs)
|
||||
|
||||
def execute_canonical_stop(self, *_args: object, **kwargs: object) -> object:
|
||||
dispatch_guard = kwargs.get("dispatch_guard")
|
||||
if callable(dispatch_guard):
|
||||
dispatch_guard()
|
||||
self._dispatch_one_packet()
|
||||
return super().execute_canonical_stop(*_args, **kwargs)
|
||||
|
||||
FakeExecutor.records = []
|
||||
monkeypatch.setattr(
|
||||
session_module,
|
||||
"PhysicalAcceptanceDialogueExecutor",
|
||||
DispatchingExecutor,
|
||||
)
|
||||
initial_path_proofs: list[ApplicationConnectionBinding] = []
|
||||
full_binding_proofs: list[ApplicationConnectionBinding] = []
|
||||
snapshot_proofs: list[ApplicationConnectionBinding] = []
|
||||
dispatch_proofs: list[ApplicationConnectionBinding] = []
|
||||
dispatch_releases: list[ApplicationConnectionBinding] = []
|
||||
|
||||
def acquire_dispatch_proof(
|
||||
binding: ApplicationConnectionBinding,
|
||||
_deadline_reached: Callable[[], bool] | None,
|
||||
) -> Callable[[], None]:
|
||||
dispatch_proofs.append(binding)
|
||||
return lambda: dispatch_releases.append(binding)
|
||||
|
||||
transport = FakeTransport("192.168.1.20")
|
||||
session = InteractiveApplicationControlSession(
|
||||
FakeAuthorityLoader(),
|
||||
transport_factory=lambda _host: transport, # type: ignore[arg-type]
|
||||
connection_path_validator=lambda binding: initial_path_proofs.append(binding),
|
||||
connection_binding_validator=lambda binding: full_binding_proofs.append(binding),
|
||||
connection_binding_snapshot_validator=lambda binding: snapshot_proofs.append(binding),
|
||||
connection_dispatch_lease=acquire_dispatch_proof,
|
||||
)
|
||||
session.open(
|
||||
host="192.168.1.20",
|
||||
timezone_name="Europe/Moscow",
|
||||
confirmation=_confirmation(),
|
||||
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="TEST001", confirmation=_confirmation())
|
||||
_wait_phase(session, "scanning")
|
||||
session.request_stop(confirmation=_confirmation())
|
||||
_wait_phase(session, "completed")
|
||||
|
||||
assert initial_path_proofs == [_connection_binding()]
|
||||
assert full_binding_proofs == []
|
||||
assert len(snapshot_proofs) >= 12
|
||||
assert dispatch_proofs == [_connection_binding()] * 4
|
||||
assert dispatch_releases == dispatch_proofs
|
||||
|
||||
|
||||
def test_exact_publish_lease_still_rejects_epoch_drift_after_snapshot_check(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
"""A cheap checkpoint pass can never bypass the final physical route fence."""
|
||||
|
||||
class DispatchRejectedExecutor(FakeExecutor):
|
||||
def run_workspace_entry_stage(
|
||||
self,
|
||||
orchestrator: object,
|
||||
checkpoint: object,
|
||||
*,
|
||||
dispatch_guard: Callable[[], None] | None = None,
|
||||
) -> LiveDeviceControlBinding:
|
||||
if dispatch_guard is not None:
|
||||
dispatch_guard()
|
||||
guard = self.transport.dispatch_guard
|
||||
assert guard is not None
|
||||
guard()
|
||||
return super().run_workspace_entry_stage(
|
||||
orchestrator,
|
||||
checkpoint,
|
||||
dispatch_guard=None,
|
||||
)
|
||||
|
||||
FakeExecutor.records = []
|
||||
monkeypatch.setattr(
|
||||
session_module,
|
||||
"PhysicalAcceptanceDialogueExecutor",
|
||||
DispatchRejectedExecutor,
|
||||
)
|
||||
snapshot_proofs: list[ApplicationConnectionBinding] = []
|
||||
|
||||
def reject_dispatch(
|
||||
_binding: ApplicationConnectionBinding,
|
||||
_deadline_reached: Callable[[], bool] | None,
|
||||
) -> Callable[[], None]:
|
||||
raise ApplicationConnectionBindingLost("test host-path epoch changed")
|
||||
|
||||
session = InteractiveApplicationControlSession(
|
||||
FakeAuthorityLoader(),
|
||||
transport_factory=lambda host: FakeTransport(host), # type: ignore[arg-type]
|
||||
connection_path_validator=lambda _binding: True,
|
||||
connection_binding_validator=lambda _binding: True,
|
||||
connection_binding_snapshot_validator=lambda binding: snapshot_proofs.append(binding),
|
||||
connection_dispatch_lease=reject_dispatch,
|
||||
)
|
||||
session.open(
|
||||
host="192.168.1.20",
|
||||
timezone_name="Europe/Moscow",
|
||||
confirmation=_confirmation(),
|
||||
connection_binding=_connection_binding(),
|
||||
)
|
||||
_wait_phase(session, "connection-ready")
|
||||
session.enter_workspace()
|
||||
failed = _wait_phase(session, "failed")
|
||||
|
||||
assert snapshot_proofs
|
||||
assert "workspace:7" not in FakeExecutor.records
|
||||
assert failed["failure"]["reason_code"] == ( # type: ignore[index]
|
||||
ApplicationConnectionBindingLost.reason_code
|
||||
)
|
||||
|
||||
|
||||
def test_read_only_device_info_open_does_not_require_physical_acceptance(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
|
||||
Reference in New Issue
Block a user