Стабильное подключение в идеальных условиях K1
This commit is contained in:
@@ -1791,6 +1791,9 @@ class XgridsK1CompatibilityService:
|
||||
scanning_observer=self._observe_application_scanning_checkpoint,
|
||||
connection_path_validator=self._validate_application_connection_path,
|
||||
connection_binding_validator=self._validate_application_connection_binding,
|
||||
connection_binding_snapshot_validator=(
|
||||
self._validate_application_connection_binding_snapshot
|
||||
),
|
||||
connection_dispatch_lease=self._acquire_application_dispatch_lease,
|
||||
physical_command_coordinator=self._physical_command_coordinator,
|
||||
)
|
||||
@@ -3092,6 +3095,18 @@ class XgridsK1CompatibilityService:
|
||||
"""Authorize one command only for the exact live DeviceInfo route epoch."""
|
||||
|
||||
self._validate_application_connection_path(binding)
|
||||
self._validate_application_connection_binding_snapshot(binding)
|
||||
|
||||
def _validate_application_connection_binding_snapshot(
|
||||
self,
|
||||
binding: ApplicationConnectionBinding,
|
||||
) -> None:
|
||||
"""Validate retained control authority without another native route probe.
|
||||
|
||||
This guard is used only around session checkpoints. The MQTT
|
||||
transport's dispatch lease still calls the full path validator under
|
||||
the command gate immediately before every physical publish.
|
||||
"""
|
||||
|
||||
# The session validates its retained MQTT transport before invoking
|
||||
# this callback. Project a strictly newer remote proof revision into
|
||||
@@ -11526,6 +11541,25 @@ class XgridsK1CompatibilityService:
|
||||
and connection.producer_generation == binding.producer_generation
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _physical_reconciliation_belongs_to_record(
|
||||
reconciliation: PhysicalCommandReconciliation,
|
||||
record: PhysicalCommandRecord,
|
||||
) -> bool:
|
||||
"""Reject append-only reconciliation history from an older command."""
|
||||
|
||||
attempt = reconciliation.original_attempt
|
||||
return bool(
|
||||
attempt.operation_id == record.operation_id
|
||||
and attempt.parent_operation_id == record.parent_operation_id
|
||||
and attempt.acquisition_id == record.acquisition_id
|
||||
and attempt.action == record.action
|
||||
and attempt.identity == record.identity
|
||||
and attempt.connection == record.connection
|
||||
and attempt.compatibility_profile_id == record.compatibility_profile_id
|
||||
and attempt.payload_sha256 == record.payload_sha256
|
||||
)
|
||||
|
||||
def _active_checkpoint_allows_physical_stop_successor(
|
||||
self,
|
||||
*,
|
||||
@@ -13082,6 +13116,10 @@ class XgridsK1CompatibilityService:
|
||||
record is not None
|
||||
and record.resolution == "not-dispatched"
|
||||
and reconciliation is not None
|
||||
and self._physical_reconciliation_belongs_to_record(
|
||||
reconciliation,
|
||||
record,
|
||||
)
|
||||
and reconciliation.kind == "prepared-stop-classification"
|
||||
)
|
||||
dispatched_then_observed_standby = bool(
|
||||
@@ -13457,6 +13495,10 @@ class XgridsK1CompatibilityService:
|
||||
)
|
||||
use_reconciliation = bool(
|
||||
reconciliation is not None
|
||||
and self._physical_reconciliation_belongs_to_record(
|
||||
reconciliation,
|
||||
record,
|
||||
)
|
||||
and reconciliation.kind
|
||||
in {
|
||||
"ambiguous-outcome",
|
||||
|
||||
@@ -186,6 +186,7 @@ class InteractiveApplicationControlSession:
|
||||
scanning_observer: ScanningObserver | None = None,
|
||||
connection_path_validator: ConnectionPathValidator | None = None,
|
||||
connection_binding_validator: ConnectionBindingValidator | None = None,
|
||||
connection_binding_snapshot_validator: ConnectionBindingValidator | None = None,
|
||||
connection_dispatch_lease: ConnectionDispatchLease | None = None,
|
||||
physical_command_coordinator: PhysicalCommandCoordinator | None = None,
|
||||
) -> None:
|
||||
@@ -199,6 +200,14 @@ class InteractiveApplicationControlSession:
|
||||
# DeviceInfo proof produced by this dialogue.
|
||||
self._connection_path_validator = connection_path_validator or connection_binding_validator
|
||||
self._connection_binding_validator = connection_binding_validator
|
||||
# Operator/worker checkpoint checks must still reject a revoked
|
||||
# intent, epoch or control proof, but they must not repeat the native
|
||||
# CoreWLAN/kernel probe already owned by the transport dispatch lease.
|
||||
# Falling back to the full validator preserves compatibility for
|
||||
# integrations which have not split these two proof strengths yet.
|
||||
self._connection_binding_snapshot_validator = (
|
||||
connection_binding_snapshot_validator or connection_binding_validator
|
||||
)
|
||||
self._connection_dispatch_lease = connection_dispatch_lease
|
||||
self._physical_command_coordinator = physical_command_coordinator
|
||||
self._scanning_observer_errors = 0
|
||||
@@ -357,7 +366,7 @@ class InteractiveApplicationControlSession:
|
||||
raise ApplicationAcceptanceError(
|
||||
"read-only inspection has not completed its Verify boundary"
|
||||
)
|
||||
self._validate_connection_binding("workspace-entry-operator-preflight")
|
||||
self._validate_connection_binding_snapshot("workspace-entry-operator-preflight")
|
||||
with self._lock:
|
||||
# The binding check deliberately runs outside the session lock.
|
||||
# Re-check the exact browser checkpoint after it returns so a
|
||||
@@ -438,7 +447,7 @@ class InteractiveApplicationControlSession:
|
||||
expected_state_revision=expected_state_revision,
|
||||
)
|
||||
self._require_phase_locked("workspace-ready")
|
||||
self._validate_connection_binding("project-prompt-operator-preflight")
|
||||
self._validate_connection_binding_snapshot("project-prompt-operator-preflight")
|
||||
with self._lock:
|
||||
self._require_checkpoint_locked(
|
||||
expected_session_generation=expected_session_generation,
|
||||
@@ -463,7 +472,7 @@ class InteractiveApplicationControlSession:
|
||||
) -> dict[str, object]:
|
||||
confirmation.checklist(ModelingAction.START)
|
||||
if self._physical_command_coordinator is not None:
|
||||
self._validate_connection_binding("start-prepare-preflight")
|
||||
self._validate_connection_binding_snapshot("start-prepare-preflight")
|
||||
with self._start_prepare_gate:
|
||||
with self._lock:
|
||||
self._require_checkpoint_locked(
|
||||
@@ -572,7 +581,7 @@ class InteractiveApplicationControlSession:
|
||||
dispatch_admission_deadline_reached
|
||||
)
|
||||
if self._physical_command_coordinator is not None:
|
||||
self._validate_connection_binding("stop-prepare-preflight")
|
||||
self._validate_connection_binding_snapshot("stop-prepare-preflight")
|
||||
self._require_stop_dispatch_deadline_open(
|
||||
dispatch_admission_deadline_reached
|
||||
)
|
||||
@@ -923,25 +932,25 @@ class InteractiveApplicationControlSession:
|
||||
self._set_phase("scanning")
|
||||
else:
|
||||
if inspection_only:
|
||||
self._validate_connection_binding(
|
||||
self._validate_connection_binding_snapshot(
|
||||
"inspection-promotion-pre-dispatch"
|
||||
)
|
||||
binding = executor.complete_connection_stage(
|
||||
orchestrator,
|
||||
expected_binding=binding,
|
||||
)
|
||||
self._validate_connection_binding(
|
||||
self._validate_connection_binding_snapshot(
|
||||
"inspection-promotion-post-response"
|
||||
)
|
||||
self._validate_connection_binding("workspace-entry-pre-dispatch")
|
||||
self._validate_connection_binding_snapshot("workspace-entry-pre-dispatch")
|
||||
executor.run_workspace_entry_stage(
|
||||
orchestrator,
|
||||
workspace,
|
||||
dispatch_guard=lambda: self._validate_connection_binding(
|
||||
dispatch_guard=lambda: self._validate_connection_binding_snapshot(
|
||||
"workspace-entry-dispatch"
|
||||
),
|
||||
)
|
||||
self._validate_connection_binding("workspace-entry-post-response")
|
||||
self._validate_connection_binding_snapshot("workspace-entry-post-response")
|
||||
self._set_phase("workspace-ready")
|
||||
|
||||
project = executor.wait_for_operator_checkpoint(
|
||||
@@ -949,15 +958,15 @@ class InteractiveApplicationControlSession:
|
||||
self._project_requested.is_set,
|
||||
)
|
||||
assert project is not None
|
||||
self._validate_connection_binding("project-prompt-pre-dispatch")
|
||||
self._validate_connection_binding_snapshot("project-prompt-pre-dispatch")
|
||||
binding = executor.run_project_prompt_stage(
|
||||
orchestrator,
|
||||
project,
|
||||
dispatch_guard=lambda: self._validate_connection_binding(
|
||||
dispatch_guard=lambda: self._validate_connection_binding_snapshot(
|
||||
"project-prompt-dispatch"
|
||||
),
|
||||
)
|
||||
self._validate_connection_binding("project-prompt-post-response")
|
||||
self._validate_connection_binding_snapshot("project-prompt-post-response")
|
||||
self._set_phase("project-ready")
|
||||
|
||||
start_checkpoint = executor.wait_for_operator_checkpoint(
|
||||
@@ -969,7 +978,7 @@ class InteractiveApplicationControlSession:
|
||||
start_permit = PhysicalAcceptancePermit(
|
||||
start_confirmation.checklist(ModelingAction.START)
|
||||
)
|
||||
self._validate_connection_binding("start-pre-dispatch")
|
||||
self._validate_connection_binding_snapshot("start-pre-dispatch")
|
||||
self._set_phase("initializing")
|
||||
executor.execute_canonical_start(
|
||||
start_command,
|
||||
@@ -978,11 +987,11 @@ class InteractiveApplicationControlSession:
|
||||
binding=binding,
|
||||
permit=start_permit,
|
||||
checkpoint=start_checkpoint,
|
||||
dispatch_guard=lambda: self._validate_connection_binding(
|
||||
dispatch_guard=lambda: self._validate_connection_binding_snapshot(
|
||||
"start-dispatch"
|
||||
),
|
||||
)
|
||||
self._validate_connection_binding("start-post-response")
|
||||
self._validate_connection_binding_snapshot("start-post-response")
|
||||
if coordinator is not None:
|
||||
coordinator.resolve("start")
|
||||
with self._scanning_transition_gate:
|
||||
@@ -1014,7 +1023,7 @@ class InteractiveApplicationControlSession:
|
||||
self._require_stop_dispatch_deadline_open(
|
||||
stop_dispatch_admission_deadline_reached
|
||||
)
|
||||
self._validate_connection_binding("stop-pre-dispatch")
|
||||
self._validate_connection_binding_snapshot("stop-pre-dispatch")
|
||||
self._require_stop_dispatch_deadline_open(
|
||||
stop_dispatch_admission_deadline_reached
|
||||
)
|
||||
@@ -1022,12 +1031,14 @@ class InteractiveApplicationControlSession:
|
||||
executor.execute_canonical_stop(
|
||||
stop_command,
|
||||
stop_permit,
|
||||
dispatch_guard=lambda: self._validate_connection_binding("stop-dispatch"),
|
||||
dispatch_guard=lambda: self._validate_connection_binding_snapshot(
|
||||
"stop-dispatch"
|
||||
),
|
||||
dispatch_admission_deadline_reached=(
|
||||
stop_dispatch_admission_deadline_reached
|
||||
),
|
||||
)
|
||||
self._validate_connection_binding("stop-post-response")
|
||||
self._validate_connection_binding_snapshot("stop-post-response")
|
||||
self._set_phase("awaiting-standby-confirmation")
|
||||
executor.maintain_post_stop_until_standby()
|
||||
if coordinator is not None:
|
||||
@@ -1468,11 +1479,33 @@ class InteractiveApplicationControlSession:
|
||||
return True
|
||||
|
||||
def _validate_connection_binding(self, stage: str) -> None:
|
||||
with self._lock:
|
||||
validator = self._connection_binding_validator
|
||||
self._validate_connection_binding_with_validator(stage, validator)
|
||||
|
||||
def _validate_connection_binding_snapshot(self, stage: str) -> None:
|
||||
"""Check retained authority without another native host-path sample.
|
||||
|
||||
The reviewed MQTT transport still acquires the full connection
|
||||
dispatch lease immediately before every publish. This lighter guard
|
||||
is only for the surrounding operator/worker checkpoints where a
|
||||
second CoreWLAN process would add latency without narrowing the actual
|
||||
publish race.
|
||||
"""
|
||||
|
||||
with self._lock:
|
||||
validator = self._connection_binding_snapshot_validator
|
||||
self._validate_connection_binding_with_validator(stage, validator)
|
||||
|
||||
def _validate_connection_binding_with_validator(
|
||||
self,
|
||||
stage: str,
|
||||
validator: ConnectionBindingValidator | None,
|
||||
) -> None:
|
||||
with self._lock:
|
||||
binding = self._connection_binding
|
||||
live_control_binding = self._live_control_binding
|
||||
transport = self._transport
|
||||
validator = self._connection_binding_validator
|
||||
if transport is not None:
|
||||
if live_control_binding is None:
|
||||
raise ApplicationConnectionBindingLost(
|
||||
|
||||
Reference in New Issue
Block a user