The detector_distance_mm sent to JFJoch and written to the DB came from the
live detector readback (diffraction.dtz_mm) captured before the detector
finished moving, so a scan requested at e.g. 100 mm could be recorded at the
old position (e.g. 800 mm).
- JFJoch + DB now read the validated request target (request.dtz) instead of
the live diffraction.dtz_mm; diffraction.dtz_mm stays live for the
local-contact readout.
- jfjoch: raise if request.dtz is unset (setup_datacollection must validate it
first) instead of silently falling back to the live readback.
- raster + rotation services: wait for the detector to reach request.dtz
(set_dtz wait=True) right before triggering the scan, since the sa2dc move is
non-blocking. (Raster setup-before-measure reorder landed earlier in daq.py.)
- tests: request.dtz now required in jfjoch/aaredb tests; xtal-snapshot exposure
assertion updated to 1 ms.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Commit 071b4ab made mount() return SUCCESS as soon as it saw the intermediate
TELL "state"/Busy event, before the later "Gripper detection" event is read,
so an empty-gripper mount completed silently with no MountingFailed/pop-up.
check_command_ok blocks (wait_not_busy) until the mount sequence finishes, so
after it returns the robot's own record is authoritative: if get_mounted_sample()
is None the gripper was empty -> return NO_PIN_IN_GRIPPER, which the mounting
service maps to MountingFailed("No Pin in Gripper"). Covers manual and automation.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>