WIP agent step 4: plan device v4 migration
CI for superxas_bec / test (push) Successful in 1m29s

This commit is contained in:
2026-05-28 08:24:04 +02:00
parent 7d1e6d5bef
commit e42dc75c38
+129
View File
@@ -0,0 +1,129 @@
# SuperXAS device v4 migration plan
## Scope and source mapping
| Debye source | SuperXAS target |
| --- | --- |
| `debye_bec/debye_bec/devices/utils/utils.py` | `superxas_bec/superxas_bec/devices/utils/utils.py` |
| `debye_bec/debye_bec/devices/mo1_bragg/mo1_bragg.py` | `superxas_bec/superxas_bec/devices/mo1_bragg/mo1_bragg.py` |
| `debye_bec/debye_bec/devices/nidaq/nidaq.py` | `superxas_bec/superxas_bec/devices/nidaq/nidaq.py` |
The migration should preserve SuperXAS hardware naming, EPICS prefixes, enum
modules, and beamline-specific details. Only the scan metadata access pattern
should be changed to match the Debye v4 migration pattern.
## Shared helper
Add `superxas_bec/superxas_bec/devices/utils/utils.py` with Debye's
`fetch_scan_info(scan_info)` helper.
The helper should:
- read `scan_info.msg.info`
- convert list-valued `positions` back to `numpy.ndarray`
- validate the message as `bec_server.scan_server.scans.scan_base.ScanInfo`
- fall back for legacy scan messages by converting old `"fly"` scan type to
`"hardware_triggered"` and other old scan types to `"software_triggered"`
This keeps devices compatible during the migration window where both old and v4
scan status messages may still appear.
## `mo1_bragg` migration
Current SuperXAS behavior:
- reads the scan name from `self.scan_info.msg.scan_name`
- populates a local `ScanParameter` pydantic model from
`self.scan_info.msg.request_inputs["inputs"]` and `["kwargs"]`
- reads old-style parameters such as `scan_parameter.start`,
`scan_parameter.stop`, `scan_parameter.scan_time`, and
`scan_parameter.scan_duration`
Target v4 behavior:
- import `ScanInfo as ScanServerScanInfo`
- store `self.scan_parameters: ScanServerScanInfo | None`
- call `self.scan_parameters = fetch_scan_info(self.scan_info)` at the start of
`on_stage`
- validate the scan with `_check_if_scan_name_is_valid(self.scan_parameters)`
- read start/stop from `self.scan_parameters.positions`
- read scan arguments from
`self.scan_parameters.additional_scan_parameters`
For the scans migrated in step 2:
- `xas_simple_scan`
- required: `positions`, `scan_time`, `scan_duration`
- configure simple XAS settings
- disable trigger settings
- set scan-control mode to `ScanControlMode.SIMPLE`
- `xas_advanced_scan`
- required: `positions`, `scan_time`, `scan_duration`, `p_kink`, `e_kink`
- configure advanced XAS settings
- disable trigger settings
- set scan-control mode to `ScanControlMode.ADVANCED`
Keep SuperXAS-specific hardware behavior:
- keep the SuperXAS prefix and imports
- keep `set_trig_settings(...)` matching the current SuperXAS IOC API unless
XRD scan classes are reintroduced in the scan migration
- keep `convert_angle_energy(...)` available for the v4 scan's gonio centering
- consider adding `"convert_angle_energy"` to `USER_ACCESS`, matching Debye,
because the scan migration now relies on the method being callable through the
device container/device manager path
Remove or stop using `_update_scan_parameter()` and the old `ScanParameter`
model once all parameter reads come from `self.scan_parameters`.
## `nidaq` migration
Current SuperXAS behavior:
- checks scan validity through `self.scan_info.msg.scan_name`
- reads continuous scan settings from
`self.scan_info.msg.scan_parameters["scan_duration"]` and
`["compression"]`
- `_progress_update` also reads `self.scan_info.msg.scan_parameters`
Target v4 behavior:
- import `ScanInfo as ScanServerScanInfo`
- store `self.scan_parameters: ScanServerScanInfo | None`
- call `self.scan_parameters = fetch_scan_info(self.scan_info)` at the start of
`on_stage`
- change `_check_if_scan_name_is_valid(...)` to accept the normalized
`scan_parameters`
- read the scan name from `self.scan_parameters.scan_name`
- read continuous scan settings from
`self.scan_parameters.additional_scan_parameters`
- make `_progress_update` use
`self.scan_parameters.additional_scan_parameters.get("scan_duration")`
The Debye runtime behavior should be mirrored:
- invalid scan names return without touching the IOC
- non-continuous XAS scans stage NIDAQ as triggered, duration `0`,
compression enabled
- `nidaq_continuous_scan` stages NIDAQ as continuous and applies
`scan_duration` plus `compression`
- non-continuous XAS scans kick off during stage
- `nidaq_continuous_scan` waits for explicit scan-core kickoff
- `on_complete` stops the backend only for non-continuous scans
## Tests to migrate or add
Use Debye's NIDAQ device tests as the starting point and adapt imports to
SuperXAS:
- verify `fetch_scan_info` accepts v4 scan info and legacy fly scan info
- verify NIDAQ valid/invalid scan name checks
- verify NIDAQ pre-scan and complete behavior for XAS versus
`nidaq_continuous_scan`
- add a focused `mo1_bragg` staging test that feeds v4 scan info and asserts the
correct settings methods are called for `xas_simple_scan` and
`xas_advanced_scan`
Keep the test blast radius focused on metadata parsing and device decisions.
The EPICS signal behavior is already covered by existing device-level patterns.