fix(gui): gate mount auto-centering on in-flight /scan/auto, not queue flag
CI / lint (push) Skipped
CI / test (3.12) (push) Skipped
CI / test (3.13) (push) Skipped
CI / test-with-beamline-plugins (pxi_bec) (push) Skipped
CI / test-with-beamline-plugins (pxii_bec) (push) Skipped
CI / test-with-beamline-plugins (pxiii_bec) (push) Skipped
CI / lint (pull_request) Failing after 31s
CI / test-with-beamline-plugins (pxiii_bec) (pull_request) Failing after 32s
CI / test-with-beamline-plugins (pxii_bec) (pull_request) Failing after 31s
CI / test-with-beamline-plugins (pxi_bec) (pull_request) Failing after 30s
CI / test (3.14) (pull_request) Failing after 32s
CI / test-with-coverage (pull_request) Failing after 35s
CI / coverage-analysis (pull_request) Skipped
CI / test (3.13) (pull_request) Failing after 40s
CI / test (3.12) (pull_request) Successful in 1m19s

Pause flips the queue's running flag while the current sample is still
being processed, so a mount seen after Pause armed a centering on an
already handled sample. Track the /scan/auto request instead; a counter
because the queue sends the next scan before the done signal reaches us.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
duan_jandClaude Opus 5.5 committed 2026-09-29 11:25:11 +02:00
1 parent f49f34cd27
commit 039c56a9e9
3 files changed
+32 -16

No files matched your search

+2 -3
View File
@@ -745,9 +745,6 @@ class MainWindow(QMainWindow):
self.automation_progress_panel.set_running
)
self.job_list_panel.automation_running_changed.connect(self._on_automation_running_changed)
self.job_list_panel.automation_running_changed.connect(
self.data_collection.set_automation_running
)
self.automation_progress_panel.set_samples_in_queue(
len(self.job_list_panel.table_model.samples)
@@ -1027,6 +1024,7 @@ class MainWindow(QMainWindow):
)
self.job_list_panel.auto_scan.connect(self.daq.automated_scan)
self.job_list_panel.auto_scan.connect(self.data_collection.auto_scan_started)
self.job_list_panel.unmount.connect(self.daq.unmount)
self.job_list_panel.unmount_then_park_and_dry.connect(self.daq.unmount_then_park_and_dry)
@@ -1151,6 +1149,7 @@ class MainWindow(QMainWindow):
self.daq.automated_scan_done.connect(self.job_list_panel.automated_scan_done)
self.daq.automated_scan_done.connect(self._mark_scan_result)
self.daq.automated_scan_done.connect(self.data_collection.auto_scan_finished)
self.daq.automation_critical_failure.connect(self._on_automation_critical_failure)
self.daq.manual_collection_critical_failure.connect(
self._on_manual_collection_critical_failure
+16 -10
View File
@@ -197,7 +197,7 @@ class DataCollectionSettings(QFrame):
self._status_seen = False
# Set on mount, fired once the hw lock frees (see _track_sample).
self._center_after_mount_pending = False
self._automation_running = False
self._auto_scans_in_flight = 0
self._tab_bar.currentChanged.connect(self._stack.setCurrentIndex)
self._tab_bar.currentChanged.connect(self._on_tab_changed)
@@ -261,7 +261,7 @@ class DataCollectionSettings(QFrame):
self._center_after_mount_pending = (
self._status_seen
and self.auto_center_after_mount.isChecked()
and not self._automation_running
and not self._auto_scans_in_flight
)
self._status_seen = True
# The server publishes the new sample while the mount still holds the
@@ -273,14 +273,20 @@ class DataCollectionSettings(QFrame):
# main_window) instead of a second signal path.
self.find_tip.click()
@Slot(bool)
def set_automation_running(self, running: bool):
# Queue automation centers each sample itself and frees the hw lock
# between samples; a GUI centering in that gap could steal the lock
# from the next /scan/auto and stop the queue.
self._automation_running = running
if running:
self._center_after_mount_pending = False
# Queue automation centers each sample itself and frees the hw lock
# between samples; a GUI centering in that gap could steal the lock from
# the next /scan/auto. Tracks the request, not the queue's running flag,
# because Pause flips that flag while the current sample is still running.
# A counter, since the queue sends the next scan before the settings panel
# sees the previous one's done signal.
@Slot()
def auto_scan_started(self):
self._auto_scans_in_flight += 1
self._center_after_mount_pending = False
@Slot()
def auto_scan_finished(self):
self._auto_scans_in_flight = max(0, self._auto_scans_in_flight - 1)
@Slot(int)
def _on_tab_changed(self, idx: int):
@@ -376,7 +376,7 @@ def test_auto_center_waits_for_mount_to_release_hw_lock(settings_panel):
assert len(clicks) == 1
def test_auto_center_skipped_during_queue_automation(settings_panel):
def test_auto_center_skipped_while_auto_scan_in_flight(settings_panel):
# Automation centers itself and frees the lock between samples; a GUI
# centering there could steal the lock from the next /scan/auto.
clicks = []
@@ -384,14 +384,25 @@ def test_auto_center_skipped_during_queue_automation(settings_panel):
settings_panel.auto_center_after_mount.setChecked(True)
settings_panel._track_sample(1)
settings_panel.set_automation_running(True)
# Queue sends the next scan before the settings panel sees the previous one
# finish (signal order in main_window): must still count as in flight.
settings_panel.auto_scan_started()
settings_panel.auto_scan_started()
settings_panel.auto_scan_finished()
settings_panel._track_sample(2, busy=True)
settings_panel._track_sample(2, busy=False)
assert not clicks
settings_panel.set_automation_running(False)
# Pause mid-sample: the current scan still runs to completion, so no
# centering until its request is done and a later manual mount happens.
settings_panel._track_sample(3, busy=True)
settings_panel.auto_scan_finished()
settings_panel._track_sample(3, busy=False)
assert not clicks
settings_panel._track_sample(None)
settings_panel._track_sample(4, busy=True)
settings_panel._track_sample(4, busy=False)
assert len(clicks) == 1