15. Replace DetectorArmLogic with DetectorAcquireLogic and four lifecycle hooks#
Date: 2026-04-29
Status#
Accepted
Context#
DetectorArmLogic had three abstract methods:
arm()— start acquiring, called fromprepare(),kickoff(), ortrigger()wait_for_idle()— wait for idle after the final collectiondisarm(on_unstage: bool)— stop acquiring; the flag distinguishedstage()(reset before a new scan) fromunstage()(end-of-scan teardown)
The on_unstage flag was introduced in ADR 0014 to give implementations a way
to distinguish the two call sites, but the single method still forced those two
concerns into one place. More importantly, there was no hook at stage() time
that could perform different work from unstage(). A detector that should be
armed once at stage() and then triggered multiple times (e.g. an Eiger in
step-scan mode, or a continuously-acquiring detector) had no clean way to
express this; the closest workaround was to put the arm call inside disarm
and branch on on_unstage, which was confusing.
Decision#
DetectorArmLogic is renamed DetectorAcquireLogic and its interface is
replaced with four named hooks that map directly to the StandardDetector
lifecycle:
Hook |
Called from |
Purpose |
|---|---|---|
|
|
Put the detector into a known idle state before a scan. |
|
|
Start the detector acquiring. |
|
after final collection |
Wait for the detector to return to idle. |
|
|
Stop the detector and perform end-of-scan cleanup. |
ensure_ready has a concrete default that delegates to ensure_stopped. This
is correct for the common case where stage-time reset and scan-end teardown are
identical (e.g. calling stop_busy_record). Subclasses that need different
behaviour at stage time (such as arming the detector once and keeping it armed
across multiple kickoff/complete cycles) override ensure_ready independently.
AreaDetector.__init__ renames its arm_logic keyword argument to
acquire_logic for consistency.
Consequences#
All existing DetectorArmLogic subclasses must be updated:
rename the base class to
DetectorAcquireLogicrename
arm()tostart_acquiring()split
disarm(on_unstage)intoensure_stopped()(and optionally overrideensure_ready()if stage-time behaviour differs)
This is a clean breaking change; the library is in alpha and no compatibility shim is provided.