Repository navigation
Beam suspender: replace the plain SuspendFloor with one that checks the ring's operating mode - #93
Merged
Anthony Sligar (sligara7) merged 3 commits intoOct 12, 2026
Conversation
…is in maintenance or shutdown Per Jakub's review of the startup-only guard (a8feb5c / d35b1c9): checking the ring's operating mode once at profile load means a mode change later in the session is never seen, and a ring in maintenance at startup leaves no suspender at all once operations resume. SuspendFloorUnlessOpsMode (hextools.suspenders) subscribes to the operating mode and checks it every time it is evaluated: low beam in MAINTENANCE/SHUTDOWN does not suspend; entering such a mode releases a tripped suspender; returning to operations with beam still low trips it. Until the mode is read it behaves like a plain SuspendFloor. The profile installs it unconditionally. Verification: mock - tests/test_suspenders.py (6 tests; the 4 mode tests were observed failing against a plain SuspendFloor first). Full suite: 125 passed, the same 9 failures as main. Assisted-by: copilot:claude-opus-4-8
Contributor
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Legacy ophyd signals are reevaluated using the wrong callback form, and the PR description conflicts with the base diff.
Review effort: Balanced
Findings: 1
Open (2)
What changed in this PR
Adds mode-aware beam-current suspension that reacts to storage-ring mode changes.
Changes:
- Adds
SuspendFloorUnlessOpsMode. - Installs it in the collection profile.
- Adds mode-transition tests.
| File | Description |
|---|---|
src/hextools/suspenders.py |
Implements mode-aware suspension. |
src/hextools/profiles/collection.py |
Configures the new suspender. |
tests/test_suspenders.py |
Tests current and mode transitions. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…th value= PR 93 review. Measured with new tests using ophyd Signals: a legacy beam signal already worked (SuspenderBase.__call__ takes value positionally), but a legacy ops-mode signal failed with AttributeError, because install/remove assumed the mode signal has subscribe_reading/clear_sub. The mode signal now follows the same two callback styles SuspendFloor supports for its own signal (Subscribable -> subscribe_reading on the RE loop; otherwise subscribe(run=True)/unsubscribe(cid)). Re-evaluation passes value= by keyword. test_legacy_ophyd_signals[mode|both] observed failing before the fix; 9/9 suspender tests pass; full suite 128 passed, same 9 failures as main. Assisted-by: copilot:claude-opus-4-8
A ring-mode change re-evaluated the suspender by reading _last_value and replaying it outside any lock. A beam reading arriving on another thread in between (mixed ophyd / ophyd-async signals call back on different threads) was overwritten by the stale replay, so the next mode change judged the wrong beam current. Both paths now hold a subclass-owned RLock. The base SuspenderBase._lock is a plain Lock, and _set_mode calls back into __call__, so taking that lock here would deadlock. Verified with mock tests: test_beam_update_during_mode_change_is_not_lost forces the interleaving and failed before this change. Assisted-by: copilot:claude-opus-4-8
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Replaces the plain beam-current suspender in the profile with a mode-aware one that checks the storage ring's operating mode every time it is evaluated, so low beam does not suspend the RunEngine while the ring is in maintenance or shutdown.
Why
maininstallsSuspendFloor(storage_ring.beam_current, 100, resume_thresh=390)unconditionally, so scans suspend on low beam even when the ring is down for maintenance or shutdown. An earlier approach (on a working branch, not onmain) instead read the mode once at startup and skipped installing the suspender; that never sees a mode change later in the session. Per Jakub's review, the check now lives inside the suspender.Changes
hextools.suspenders.SuspendFloorUnlessOpsMode: aSuspendFloorthat also subscribes to the ring's operating mode and folds it into_should_suspend/_should_resume:MAINTENANCE/SHUTDOWN: low beam does not suspend, and entering one of these modes releases a tripped suspender;SuspendFloor;SuspendFloorallows.profiles/collection.py: installs it in place of the plainSuspendFloor, withskip_modes=(MAINTENANCE, SHUTDOWN).How it was verified: mock
tests/test_suspenders.py(9 tests, mockNSLS2StorageRingand ophydSignals): trips on low beam in operations; ignores low beam in maintenance and in shutdown; releases when the ring enters maintenance while tripped; trips when operations resume with beam still low; resumes on beam recovery; works with ophyd-style beam, mode, or both. The mode tests and the ophyd-style mode tests were each observed failing before their fix.main(60acf66), so CI will show them here too.Assisted-by: copilot:claude-opus-4-8