Commit Graph
912 Commits
Author SHA1 Message Date
x01dcandClaude Sonnet 5 4ada8e85ce docs/document tomo_queue_reacquire and tomo_queue_resume
Add both to the tomo-queue command reference in flomni.md and
lamni.md: tomo_queue_resume() as an alias for tomo_queue_execute(),
and tomo_queue_reacquire(job_index, projection_number) for reopening
a job (including an already-"done" one) at an earlier projection and
cascading later jobs to pending, mirroring the code added in the
previous commit.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-21 03:20:55 +02:00
x01dcandClaude Sonnet 5 abc2a3d041 feat/tomo queue reacquire from an earlier projection
Add tomo_queue_reacquire(job_index, projection_number) to the shared
TomoQueueMixin: reopens any queue job (even an already-"done" one) at
an earlier projection than its own recorded progress, and resets every
job queued after it -- tomo and command jobs alike -- to "pending", so
a following tomo_queue_resume() (a new alias for tomo_queue_execute(),
added for naming symmetry with tomo_scan_resume()) re-runs everything
from there forward in order. Reuses the existing tomo_scan_resume()
machinery by writing the requested resume point into the shared
progress global var, rather than adding new parameters to
tomo_scan()/tomo_queue_execute(). Guards against clobbering another
job's progress if one is already "incomplete"/"running" elsewhere in
the queue.

A flat projection number is used as the resume-point unit for all
three tomo_types, including type 1 (8 equally-spaced sub-tomograms),
via a new per-setup _resolve_type1_projection() that maps it to
(subtomo_start, start_angle). flomni's version reuses its existing
_subtomo_angle_plan(); lamni's inline angle math in sub_tomo_scan() was
extracted into an analogous _subtomo_angle_plan() static method first
(behavior-preserving -- verified against the existing angle-math test
suite) so both setups share the same pattern.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-20 22:00:22 +02:00
x01dcandClaude Sonnet 5 80f6972a31 feat/show at_each_angle_hook in lamni tomo_parameters()
flomni's tomo_parameters() CLI printout already showed the active
at_each_angle_hook; lamni's didn't, making it easy to have a custom
per-projection hook active without noticing from the parameter dump.
Added the identical guarded print, reusing the shared
TomoQueueMixin._describe_active_hook() helper both classes already
inherit. Also switched lamni's tomo_scan() end-of-scan summary to use
that same helper instead of the raw attribute, matching flomni's
equivalent block and correctly flagging a stale/unregistered hook name.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-20 21:37:51 +02:00
x01dcandClaude Sonnet 5 382e325093 feat/print constant shift alongside per-projection corrections
Correction 1, correction 2, and the x-ray-eye correction were already
printed for every projection, but the manual/constant shift
(manual_shift_x/manual_shift_y) applied in the same offset math wasn't
-- added on both setups, right after the existing correction calls in
lamni's tomo_scan_projection() and flomni's tomo_scan_projection() /
tomo_acquire_at_angle().

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-20 21:27:42 +02:00
x01dcandClaude Sonnet 5 cdfc02335d fix/tomo queue tooltip hides fields irrelevant to a job's tomo_type
Hovering a queue entry showed every snapshotted param unconditionally,
including golden-ratio settings on a type-1 (non-golden) job -- and
vice versa, type-1-only fields (angle range, zero-deg reference) on a
golden-ratio job. Reuses _update_type_visibility()'s existing
per-tomo_type section/field gating (already used for the live edit
form) to filter _job_tooltip()'s params list the same way, for both
flomni and lamni jobs.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-20 21:19:10 +02:00
x01dcandClaude Sonnet 5 6c3d60306d feat/lamni tomogram timing overview + repeat-on-interruption
Port two flomni tomo_scan() behaviors lamni was missing: an end-of-scan
timing overview (total time, time excluding gaps, time lost to gaps,
sample/hook info) printed and written to scilog, and automatic repeat
of an entire projection when the beamline interlock trips mid-scan.

The latter needed two pieces together: enabling
bec.builtin_actors.scan_interlock at tomo_scan() start (previously
never enabled for lamni), and wrapping _tomo_scan_at_angle in
@scan_repeat so the resulting ScanRestart (or any other transient
exception) redoes the whole projection instead of aborting the scan.
A new LamNIError marks the one non-retryable case (unregistered
at_each_angle_hook), replacing a plain ValueError there.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-20 21:13:21 +02:00
x01dc 55f6f944f7 fix/improve doc
CI for csaxs_bec / test (push) Successful in 1m34s
2026-07-20 14:37:00 +02:00
x01dc c0fdba0e6c feat/smaract_show_all
CI for csaxs_bec / test (push) Successful in 1m35s
2026-07-20 14:35:09 +02:00
x01dc 6f07c636ad remove data10 references 2026-07-20 14:31:15 +02:00
x01dc f7a1bf4a98 update/docs 2026-07-20 14:22:53 +02:00
x01dc cdc4ae02b5 fix/delays after newpar. lamni needs more time
CI for csaxs_bec / test (push) Successful in 1m35s
2026-07-20 14:18:26 +02:00
x01dc 3c46555df4 fix/increase delay after NEWPAR in FES
CI for csaxs_bec / test (push) Successful in 1m38s
2026-07-20 14:04:20 +02:00
x01dc 64170812a9 config adjustments 2026-07-20 14:04:00 +02:00
x01dcandholler 2863cd51c4 fix(bec_widgets): require sample owner in sample-storage widget
Read the Docs Deploy Trigger / trigger-rtd-webhook (push) Successful in 2s
CI for csaxs_bec / test (push) Successful in 2m3s
The owner prompt was labeled and treated as optional, but an occupied
slot must always have an owner recorded. Both the rename and new-sample
dialogs now validate the owner the same way the name field already is:
cancelling or leaving it empty aborts the write instead of silently
falling back to a blank/previous owner.
2026-07-16 16:28:12 +02:00
x01dcandholler d6c0c85a60 fix(bec_widgets): use cached device reads for sample-storage & slit polling
Both widgets' polling loops were issuing live EPICS round-trips every
2s even though the underlying signals are auto_monitor=True and BEC
already keeps a fresh monitored value locally. Switching to
read(cached=True) removes that redundant hardware traffic; for the
slit widget this also makes the old round-robin "selected slit every
tick, others in rotation" strategy unnecessary, so it now polls all
six slits every tick.
2026-07-16 16:28:12 +02:00
x01dcandClaude Sonnet 5 5421c95d26 fix(flomni): unpack sample owner on the status webpage
CI for csaxs_bec / test (pull_request) Successful in 1m31s
Read the Docs Deploy Trigger / trigger-rtd-webhook (push) Successful in 2s
CI for csaxs_bec / test (push) Successful in 1m36s
FlomniWebpageGenerator._collect_setup_data() read the raw
flomni_samples.sample_names.sample0 DESC signal directly, so once
7e8e807 started packing "name | owner" into that same field (there's
no separate PV for owner), the status page showed the raw
delimiter-joined string as the sample name instead of unpacking it --
same gap FlomniSampleStorage.get_sample_name_and_owner()/show_all()
already handle correctly. Now unpacks via sample_desc_codec.unpack_desc()
and appends "(owner: ...)" when set, mirroring show_all()'s own format.

Lamni has no equivalent gap: it has no automatic sample changer or
storage, so its sample_name global var was never given an owner field.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-16 15:40:14 +02:00
x01dcandClaude Sonnet 5 940d1c5d75 feat(lamni,flomni): finish lamni webpage generator, share base via OMNY_shared
Extracts WebpageGeneratorBase, HttpUploader, LocalHttpServer, and
make_webpage_generator() out of flomni_webpage_generator.py into
OMNY_shared/webpage_generator_base.py, mirroring the tomo_queue_mixin
precedent, then finishes LamNI_webpage_generator.py (fixes its broken
import, corrects TOMO_TYPES to match lamni's real 3-mode tomo_scan(),
enables HAS_TOMO_QUEUE now that the queue mixin backs it, adds lamni's
own TQ_PARAM_DISPLAY, implements _collect_setup_data()) and wires it
into LamNI.__init__.

Also fixes a real bug surfaced by running two setups against the same
shared status-page directory: each setup's logo is now copied to its
own filename (e.g. flOMNI.png / LamNI.png) instead of a shared
logo.png, since a fixed filename let a browser serve a stale, cached
logo from the other instrument's prior session.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-16 15:36:39 +02:00
x01dcandClaude Sonnet 5 6744908983 docs(lamni): mark flomni-to-lamni migration status, only webpage left
CI for csaxs_bec / test (pull_request) Successful in 2m34s
Read the Docs Deploy Trigger / trigger-rtd-webhook (push) Successful in 2s
CI for csaxs_bec / test (push) Successful in 1m50s
FLOMNI_TO_LAMNI_COMPARISON.md was written before any porting work started
and read as a stale plan once the tomo-queue backend and tomo-params GUI
were both done. Add a status pointer at the top so a fresh session can
find what's actually left (the webpage generator) without re-deriving it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-16 14:22:45 +02:00
x01dcandClaude Sonnet 5 46cadc8894 fix(lamni): show progress GUI on scan start, clear busy heartbeat on exit
Mirrors two fixes already made to Flomni.tomo_scan(): LamNI.tomo_scan()
never opened the progress GUI automatically, and left a stale "busy"
heartbeat for up to 120s after a scan had already finished (or crashed),
since it was only ever reset at the start of the next scan.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-16 14:21:45 +02:00
x01dcandClaude Sonnet 5 f3c90c5b91 fix(lamni): fix three real tomo_scan() crashes, mirroring flomni's fixes
bec.active_account.decode() crashed on every real tomo_scan() call --
active_account is a plain str, not bytes. Flomni's equivalent never had
the .decode() call and already guards an empty active_account (e.g. a
dev/sim session) by skipping sample-database registration instead of
crashing. Same bug fixed in DataDrivenLamNI.tomo_scan() (extra_tomo.py),
which had an identical inline copy.

write_pdf_report() read a nonexistent "mokev" device; the real device is
ccm_energy. Reads it for real now, wrapped in a broad try/except falling
back to "N/A" if unavailable, rather than a hardcoded placeholder.

write_pdf_report()'s logbook/scilog write crashed when scilog isn't
configured -- lamni.py already had this exact tolerance pattern one
method over, in write_to_scilog(); applied the same try/except here.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-16 13:59:12 +02:00
x01dcandClaude Sonnet 5 bac3fa8754 feat(lamni,bec_widgets): generalize tomo-params GUI to lamni, fix two sub_tomo_scan angle bugs
Generalize TomoParamsWidget to lamni via a SETUP_PROFILES mechanism
(setup detection, per-setup field lists/order, a new Offsets section,
a setup-agnostic "Duplicate job" queue button), fixing two latent
TomoQueueDialog bugs that silently mishandled lamni jobs along the way.

While verifying the GUI's projection-count preview against the CLI,
found two real, pre-existing bugs in LamNI.sub_tomo_scan() unrelated
to the GUI itself: a duplicate closing angle every sub-tomogram
(360=0 degrees), and a phase offset computed from the raw stepsize
instead of the achievable one, breaking the equally-spaced-when-
combined guarantee for sub-tomogram pairs/quads/the full set. Both
fixed to mirror Flomni's existing, correct equivalents.

Also fills in lamni's user documentation with the queue/command-job/
at-each-angle-hook system, which it previously lacked entirely,
mirroring flomni.md's coverage.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-16 13:39:08 +02:00
x01dcandClaude Sonnet 5 95d46c9d49 feat(flomni,lamni): port tomo-queue backend to lamni via shared mixin
CI for csaxs_bec / test (push) Successful in 1m29s
Extract the tomo-queue/at-each-angle-hook backend (job proxy, hook
registry, command-job dispatch) out of flomni.py into a new shared
TomoQueueMixin (OMNY_shared/tomo_queue_mixin.py) so it can be reused
instead of duplicated, avoiding the same param-name-mirror drift
already flagged for tomo_params.py. Flomni's refactor is behavior-
preserving; LamNI is the new consumer, with its own param names
(tomo_circfov, lamni_stitch_x/y, ...) and no 180-degree/single-point
concepts, since lamni doesn't have them. Also adds LamNI.tomo_scan_resume(),
required for tomo_queue_execute()'s resume-after-crash path but not
previously present.

Verified via a new unit test suite (test_lamni_tomo_queue.py) plus live
checks against the running simulated flomni and lamni deployments,
documented in LamNI/AI_docs/TOMO_QUEUE_PORT.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-15 14:17:51 +02:00
x01dcandClaude Sonnet 5 24b1633f04 feat(flomni,bec_widgets): also hard-stop the optics Galil controller
CI for csaxs_bec / test (pull_request) Successful in 3m0s
Read the Docs Deploy Trigger / trigger-rtd-webhook (push) Successful in 2s
CI for csaxs_bec / test (push) Successful in 1m28s
The abort button only stopped ftransy's controller (the sample-transfer
board). foptx/fopty sit on a physically separate Galil controller (a
different socket port), so motion there kept running through an abort.

Adds an optional extra_hard_stop_device_name to ConsoleButtonsWidget,
wired to "foptx" for flomni. It calls .controller.stop_all_axes()
rather than hard_abort_and_restore_positioning_mode(): the latter's
#POSMODE/mntmod handling is specific to the sample-transfer/mount
program that only runs on ftransy's controller, so the plain
stop_all_axes() (XQ#STOP,1) is the correct generic stop for any other
board. Each device is stopped and logged independently so a failure on
one doesn't skip the other.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-15 12:01:47 +02:00
x01dcandClaude Sonnet 5 de6a219674 fix(bec_widgets): stop gating the hard-stop button on a live device check
_hard_stop_available() re-resolved hard_stop_device_name against the
device manager and disabled the button if that lookup failed, checked
once at construction with no way to recover for the widget's lifetime.
In practice this disabled the button even for ftransy confirmed
present and enabled from the CLI. Since _on_abort() already resolves
the device and calls its controller inside its own try/except, the
live pre-check was redundant and its false negatives cost more than
they protected. The button is now enabled whenever a
hard_stop_device_name was configured at all; a name that doesn't
actually resolve fails safely (logged, no-op) at click time instead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-15 11:55:55 +02:00
x01dcandClaude Sonnet 5 194602176c fix(flomni): warn and confirm instead of crashing when fttrx1 is missing
CI for csaxs_bec / test (push) Successful in 3m8s
feye_in() called umv(dev.fttrx1, ...) unconditionally, so a config
without fttrx1 crashed instead of degrading gracefully. Mirrors the
existing feye_out() guard: warn that fttrx1 can't be moved and that
skipping it risks a hardware collision on the real beamline, then ask
yesno before continuing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-15 11:20:58 +02:00
x01dcandClaude Sonnet 5 1eb324aad3 fix(flomni): reuse the same phase table for 360deg tomo instead of two
Supersedes the complementary even/odd-eighths tables from 900c810 with
a single shared phase_eighths table used in both 180 and 360 mode, so
subtomo N carries the same phase-tier role regardless of
tomo_angle_range. The complementary property of the low/high phase
sets now falls out as a consequence of the original table's structure
instead of needing a separately derived table.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-15 11:18:37 +02:00
x01dcandClaude Sonnet 5 aebfccc5f3 fix(flomni): clear busy heartbeat on scan end, fix duplicated tomo math
Two independent fixes:

- GUI "beamline busy" indicators (TomoParamsWidget's banner,
  FlomniWebpageGenerator's status page) purely wait for
  progress["heartbeat"] to go stale (120s / 90s respectively) - there was
  no explicit "scan finished" signal to react to instead, since
  tomo_scan() wrote a heartbeat at the start of every projection but
  never cleared it on exit. Wrapped the scan loop in try/finally so
  heartbeat is cleared on every exit path (normal completion, exception,
  or interrupt/abort), not just at the next scan's start - both
  busy-detectors now see this on their very next poll instead of waiting
  out the timeout. Live-verified: heartbeat is None immediately after
  tomo_scan() returns.

- Found while investigating a related report ("angular step of the final
  combined tomogram shown different between 180 and 360 mode, although
  it has to be identical" + "GUI shows projection count doubling when
  switching 180->360"): TomoParamsWidget's _compute_type1()/
  _requested_to_stepsize() (tomo_params.py) and the generated status
  webpage's calcProjections() JS (flomni_webpage_generator.py) are both
  independent, un-synced duplicates of the exact old N=int(angle_range/
  stepsize) formula fixed in flomni.py's own _tomo_type1_actual_grid()
  two commits ago - they were never updated when that fix landed, so the
  GUI and webpage kept reporting double the projection count for 360
  mode. Fixed both to match flomni.py: N/step/total are always computed
  against a fixed 180 degrees, independent of angle_range. Also fixed
  the "angular step of the final (combined) tomogram" CLI/wizard lines
  in flomni.py itself, which used tomo_angle_range/total_projections
  (correct for 180 mode by coincidence, wrong for 360 mode - the true
  combined resolution is always 180/total_projections, identical
  between modes). Added a regression test asserting the widget's
  formulas match flomni.py's for both modes, to catch this exact kind of
  drift if it recurs. Live-verified against the running sim: both modes
  now report identical total_projections and combined-tomogram step for
  the same stepsize.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-15 10:18:38 +02:00
x01dcandClaude Sonnet 5 278364e650 docs(flomni): simplify 360deg tomo CLI output to a plain no-duplicates note
Drop the "effective (mod-180) reconstruction resolution" line added in
the previous commit -- the projection count already says everything
that matters; a derived resolution figure just adds noise. Replaced
with a plain "There are no duplicate angles." note in both display
spots (tomo_parameters() and the interactive wizard).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-15 09:52:38 +02:00
x01dcandClaude Sonnet 5 900c810111 fix(flomni): use complementary phases for 360deg tomo, not adjacent pairs
The previous commit's 360-degree phase assignment gave the low and high
halves the SAME phase per pair (1,2)/(3,4)/(5,6)/(7,8), so each pair
concatenated into one continuous evenly-spaced range -- but that means
every low-half angle is exactly 180deg from a high-half angle, which is
exactly the redundant-measurement bug this was supposed to fix, just
reintroduced between subtomos instead of within one.

Corrected: the low half (subtomos 1,4,5,8) now uses the even eighths of
the original 8-way phase_eighths table, and the high half (2,3,6,7) uses
the odd eighths -- complementary, not shared. Folded mod 180, the two
halves interleave into exactly the same 8-way, step/8 grid that 180-mode
itself produces: every position is measured exactly once, using its full
0-360 physical range, with zero redundant measurements anywhere. Total
projection count is unchanged (still identical to 180 mode for a given
tomo_angle_stepsize).

Verified: pure-math unit tests confirm the 360-mode combined set, folded
mod 180, is an exact set match (same count, no repeated residue) against
180-mode's own set. Live-verified against the running flomni sim: real
motor motion for both modes, folding the observed 360-mode angles mod
180 exactly reproduces the observed 180-mode angles.

Also updated the two "angular step of the final combined tomogram"
CLI/parameter-wizard print statements to additionally report the
effective mod-180 reconstruction resolution for 360 mode, since it's
now finer than the raw per-half spacing they already printed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-15 07:28:24 +02:00
x01dcandClaude Sonnet 5 7e8e807adc fix(flomni): stop duplicate 360deg tomo angles, add sample owner, fix abort crash
Three independent fixes:

- sub_tomo_scan(): in 360-degree tomo_type-1 mode, every sub-tomogram used
  to sweep the full 0-360 range, so each one's own fine grid contained
  angle pairs exactly 180deg apart -- redundant tomographic information.
  Sub-tomograms now each cover a 180deg span, split into low/high halves
  by subtomo_number % 4 with a bit-reversal-of-4 phase table, so adjacent
  pairs (1,2)/(3,4)/(5,6)/(7,8), either quartet, and all 8 combined each
  independently form a complete, evenly-spaced 360deg tomogram at
  successively finer spacing. Total projection count for a given
  tomo_angle_stepsize is now identical between 180 and 360 mode (same N,
  no longer doubled). Updated the 4 other consumers of the old N/step
  formula (zero-deg reference gating, _tomo_type1_actual_grid, the
  parameter wizard, the PDF report) to match. 180-degree mode is
  unchanged. Live-verified against the running flomni sim: real motor
  motion traces the expected boustrophedon path with no duplicate or
  180deg-apart angles.

- Sample storage: added an owner field, packed into the same EPICS DESC
  field as the sample name ("name | owner", via new sample_desc_codec.py)
  since there's no separate PV for it. Wired through
  FlomniSampleStorage, the CLI (flomni_modify_storage_non_interactive,
  ftransfer_modify_storage), the two transfer routines that forward a
  raw DESC value across a gripper move (now unpacked/repacked so owner
  survives the move instead of being dropped or double-packed), and
  SampleStorageWidget. Scoped to flomni only this session; OMNY's
  storage/transfer mixin is unchanged.

- ConsoleButtonsWidget's ABORT button used to send SIGINT then, 500ms
  later, a stop_devices() broadcast to ALL devices with no stop_id --
  an un-suppressed error from that broadcast landing on a queue-tracked
  instruction could kill the scan worker thread outright, requiring a
  full BEC restart. Replaced with: queue.request_scan_abortion() (safe
  no-op if idle, but registers a stop_id so expected errors are
  suppressed), then SIGINT, then a direct, immediate Galil hard stop via
  new GalilController.hard_abort_and_restore_positioning_mode() -- the
  same method ftransfer_abort() now delegates to, so the CLI and GUI
  paths can't drift apart again. SIGINT is sent before the hard stop:
  live testing showed that if the hard stop's mntprgs-clearing side
  effect lands first, a same-session polling loop can mistake it for
  normal completion and fall through into ensure_gripper_up(), which
  must not happen mid-transfer -- sending SIGINT first (near-instant)
  gives that loop's own KeyboardInterrupt handler a head start before
  the hard stop's own multi-step sequence completes. The button is
  labeled per beamline (e.g. "Flomni Motion Stop") and disabled rather
  than silently inert when no hard-stop device is configured/enabled.
  Scoped to flomni only this session (OMNY/LamNI wiring deferred).
  Live-verified against the running sim, including the exact
  stop-lands-mid-queued-instruction scenario that previously crashed
  the scan worker.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-15 07:09:40 +02:00
x01dcandClaude Sonnet 5 9eedfa4d52 docs(flomni): mark the tomo queue GUI checklist fully validated
CI for csaxs_bec / test (pull_request) Successful in 1m37s
CI for csaxs_bec / test (push) Successful in 3m15s
Read the Docs Deploy Trigger / trigger-rtd-webhook (push) Successful in 4s
Rewrites both status headers (plan doc + GUI test checklist) now that
every item (1-55) has been clicked through live and passes. Fixes two
remaining stale "not yet click-tested" references in section 1 (items
9/10) left over from before sections 6c/6d were tested. No open
checklist items remain; section 7's known limitations are scope cuts,
not bugs, and are the documented starting point for future work.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-14 15:41:56 +02:00
x01dcandClaude Sonnet 5 fd5fc84867 docs(flomni): record 6c-6e pass results and document the add-to-queue warning
CI for csaxs_bec / test (push) Successful in 3m4s
GUI test checklist: sections 6c/6d/6e (items 37-52) all passed
real-session testing, including the stale-"running" override fixing
an actual stuck job found live -- status line and section 1 items
updated. New section 6f (items 53-55) for the "Add current params to
queue" mid-edit warning, plus section 1 item 13.

Plan doc section 6.1: records the second live-vs-unsaved-edit
confusion (a second window, not just the panel's own button) and why
it's a warning, not a block, unlike Submit.

User manual: new paragraph distinguishing the params panel's "Add to
queue" from the queue window's "Add current params to queue", and
when the warning fires.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-14 13:17:17 +02:00
x01dcandClaude Sonnet 5 9aeacefbf0 fix(bec_widgets): warn before "Add current params to queue" during an edit
Real footgun: edit a value in the params panel but don't click its own
"Add to queue" (or Submit) -- then use the *separate* Queue control
window's "Add current params to queue" button, expecting it to queue
what was just typed. It doesn't: that button reads live global vars
(TOMO_QUEUE_COMMAND_JOBS_PLAN.md section 6.1's rule -- only the panel's
own Add-to-queue reads the form), so it silently queues the stale,
pre-edit values with no indication anything's off. Now checks the
parent params panel's edit-mode state and, if an edit is in progress,
warns explicitly and points at the correct button before proceeding
-- a warning rather than a hard block, since queuing the live params
alongside an unrelated in-progress edit elsewhere is still a
legitimate thing to want.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-14 13:15:27 +02:00
x01dcandClaude Sonnet 5 d8b7737cc7 docs(flomni): document the declined-scan and stale-running-job fixes
CI for csaxs_bec / test (push) Successful in 1m44s
User manual: notes that declining the fermat-scan confirmation now
fails the job instead of silently skipping a projection, plus how to
recover a job stuck at "running" (tomo_queue_delete has no status
guard; update_by_id to fix the status directly; the GUI's staleness
override).

AI_docs: plan section 3.4 records the second real incident (declined
confirmation silently returning) and its fix; section 6.3 records the
stale-"running" GUI guard fix. GUI test checklist gets section 6e
(test steps 48-52) and section 1 item 12, status line updated to flag
6c/6d/6e as not yet clicked through.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-14 13:03:24 +02:00
x01dcandClaude Sonnet 5 ee036873cd fix(bec_widgets): let delete/clear escape a stale "running" queue job
Real incident: a job got stuck at status "running" after its process
died mid-scan (Ctrl-C during a repeated confirmation-prompt loop, a
separate bug fixed alongside this one) with no live process behind it
-- and the GUI's delete/clear guard treated "running" as an absolute
block, with no way to escape from the GUI at all (the CLI's
tomo_queue_delete() has no such guard and already worked, but that's
not obvious/discoverable from the GUI).

Adds a staleness check using the same tomo_progress heartbeat signal
TomoParamsWidget._is_tomo_running() already uses: if a "running" job's
heartbeat is missing or older than 120s, it's very likely orphaned,
not actively executing. Delete/clear now offer an explicit
confirmation ("looks stale -- proceed anyway?") in that case instead
of an unconditional refusal; a genuinely fresh heartbeat still blocks
outright as before.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-14 13:00:08 +02:00
x01dcandClaude Sonnet 5 778c953f2e fix(flomni): raise instead of silently returning when a fermat scan is declined
tomo_scan_projection() always runs a Fermat scan; when
single_point_instead_of_fermat_scan is on and _internal isn't passed,
it asks "Run a fermat scan anyway?" and, on "no", used to just print
"Aborted." and return -- no exception. Real incident: a custom
at_each_angle hook called this without _internal=True, got asked at
every projection angle, declining silently skipped each one, and the
eventual Ctrl-C (KeyboardInterrupt, which tomo_queue_execute()'s
`except Exception` does not catch) left the job stuck at status
"running" forever with no live process behind it. Declining now raises
FlomniError, which (with the earlier scan_repeat exc_handler fix)
isn't retried and correctly fails the job, marking it "incomplete" and
pausing the queue -- the crash-resume contract tomo_queue_execute()
already documents, instead of silent data loss followed by an
untraceable stuck state. Sim-verified: direct decline raises with a
clear message; through the queue via a hook missing _internal=True,
the job ends up "incomplete", not stuck "running" or silently "done".

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-14 12:59:54 +02:00
x01dcandClaude Sonnet 5 7fbfee7c36 docs(flomni): document "Load into editor"
CI for csaxs_bec / test (push) Successful in 1m50s
User manual: new paragraph in the queueing section explaining the
button and that Submit/"Add to queue" still gate the actual write.

AI_docs: plan section 6.8 records the design (not a third write path,
confirm-before-discard, button-eligibility gating) and the
_enter_edit_mode_with() refactor; GUI test checklist gets section 6d
(test steps 42-47) and a new section 1 item 11, with the status line
updated to flag 6c/6d as not yet clicked through.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-14 12:46:17 +02:00
x01dcandClaude Sonnet 5 97ac0acde9 feat(bec_widgets): add "Load into editor" to reuse a queued job's settings
Select a single tomo job (command jobs have no params, so they're
excluded) in the queue dialog and click "Load into editor" to enter
edit mode on the params panel populated from that job's saved
snapshot instead of the live backend. Reuses the existing edit-mode
machinery (_enter_edit_mode_with(), factored out of enter_edit_mode())
so the operator reviews/tweaks and then uses the normal Submit or "Add
to queue" paths -- no new write path, nothing touches live params or
the queue itself just by loading. If an edit is already in progress,
confirms before discarding it. The button is disabled outside a
single-tomo-job selection and during sort mode, and re-evaluated on
selection change and on every table refresh.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-14 12:44:28 +02:00
x01dcandClaude Sonnet 5 8dc4a56b91 docs(flomni): document hook reporting fixes and record real-session test results
CI for csaxs_bec / test (push) Successful in 3m2s
User manual: notes that the hook (name + source, when registered)
appears in tomo_parameters(), the scilog entry, the PDF report, and
the progress-ring label, and clarifies that unregistering a hook does
not clear at_each_angle_hook -- confirmed expected behavior.

AI_docs test checklist: records that sections 3-6b passed real-session
testing (updating the stale "not yet clicked through" status), adds
section 6c (test steps 37-41) for the fixes found during that testing,
and updates section 1's summary (new item 10).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-14 12:20:47 +02:00
x01dcandClaude Sonnet 5 436c3f0137 fix(bec_widgets): drop the redundant row-number gutter in the queue table
Qt's own vertical header (1-based) sat to the left of the dialog's own
0-based "#" column (which matches the CLI's indices -- tomo_queue_show(),
tomo_queue_delete(), tomo_queue_move()) -- two differently-based
indices next to each other read as confusing/wrong. Hides Qt's
gutter, keeping only the one that actually means something.

Also shows a tomo job's active at_each_angle_hook in the Details
column (e.g. "hook: name" or "hook: name (not registered)", checked
against the published tomo_at_each_angle_hooks list) -- previously
Details was always blank for tomo jobs, so a hook-driven queued job
looked identical to a plain one without expanding the row tooltip.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-14 12:19:04 +02:00
x01dcandClaude Sonnet 5 4c2282912e feat(flomni): show the active hook in the ring progress bar
flomnigui_show_progress()'s center label now includes a "Hook: name"
line when at_each_angle_hook is set, same condition/wording as
tomo_parameters()'s CLI note -- an operator watching the progress GUI
during an unattended queue run can tell a hook is active without
switching to a CLI session.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-14 12:18:57 +02:00
x01dcandClaude Sonnet 5 1ef95c6e2d feat(flomni): surface the active hook (name + source) in reports and CLI
Adds _describe_active_hook() (flags a name that isn't currently
registered, e.g. after unregister_at_each_angle_hook() while
at_each_angle_hook still references it -- confirmed this is expected:
unregistering only removes it from the runtime dict, the property
itself is untouched) and _active_hook_source() (inspect.getsource(),
None if unavailable). Wired into:
- tomo_parameters()'s printed hook line, now flags "NOT registered"
- the end-of-scan scilog entry (name in the printed/scilog text,
  source code appended to the scilog text only, not the console)
- write_pdf_report() (name as a report line, source appended to both
  the PDF file and the scilog entry it sends)
So a hook-driven measurement's actual behavior is part of the
permanent record, not just inferable from a name that might not even
resolve anymore. Sim-verified all six states (unset, registered,
unregistered) for both helpers.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-14 12:18:50 +02:00
x01dcandClaude Sonnet 5 9df9253c84 docs(flomni): add test step 36 for the single-point warning label/print
CI for csaxs_bec / test (push) Successful in 1m31s
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 22:28:07 +02:00
x01dcandClaude Sonnet 5 ca8178fff3 docs(flomni): note the single-point warning fires on the off->on transition
CI for csaxs_bec / test (push) Successful in 1m32s
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 22:07:31 +02:00
x01dcandClaude Sonnet 5 13ad8bbf7a feat(flomni): fire the single-point acquisition warning on the off->on transition
Previously the tomo_acquire_at_angle()-vs-tomo_scan_projection()
reminder only printed when tomo_parameters() happened to be called
afterward -- easy to miss if you just flip
single_point_instead_of_fermat_scan directly. Its setter now prints
the same note immediately when the value transitions False->True.
Gated on the transition (checked via the property's own getter before
the write) so restoring an already-True value across consecutive
queued jobs doesn't reprint it every time -- sim-verified: silent on
False->False, True->True (repeat), and True->False; prints exactly
once per False->True flip.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 22:07:00 +02:00
x01dcandClaude Sonnet 5 a23e9557a9 docs(flomni): clarify hook re-registration and the two acquisition methods
CI for csaxs_bec / test (push) Successful in 1m32s
Two additions to the at_each_angle hook writeup: registering a hook
stores the function object at that moment, not a live link to its
name, so editing the function later requires calling
register_at_each_angle_hook() again -- redefining it alone does
nothing. And tomo_scan_projection()/tomo_acquire_at_angle() are not
interchangeable (Fermat vs single-point); the example hook now calls
tomo_scan_projection() plainly (no more confusing _internal=True in
user-facing code) with a clear note on when to use the other one
instead, matching the new CLI/GUI warnings.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 21:58:00 +02:00
x01dcandClaude Sonnet 5 7054bf9858 feat(bec_widgets): mirror the single-point acquisition-method warning in the GUI
Adds a wrapped, styled warning label under "Random shift max" in the
params panel, shown whenever "Single-point scan" is checked and hidden
otherwise -- same reminder tomo_parameters() now prints on the CLI
side: use tomo_acquire_at_angle(angle), not tomo_scan_projection(angle),
when single-point mode is on. Toggled from the existing
_on_single_point_changed() handler, so it updates on both a live edit
and every params-panel refresh (the widget's checkbox state already
drives this handler either way).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 21:57:50 +02:00
x01dcandClaude Sonnet 5 6f8623fee8 feat(flomni): warn in tomo_parameters() when single-point mode needs a different call
tomo_scan_projection() always runs a Fermat scan and tomo_acquire_at_angle()
always runs a single-point acquisition -- they aren't interchangeable, and
calling tomo_scan_projection() directly while single_point_instead_of_fermat_scan
is on triggers an interactive confirmation prompt that would hang an
unattended queue run. tomo_parameters() now prints a reminder of which one
to call (including inside a custom at_each_angle hook) whenever single-point
mode is enabled, surfacing this proactively instead of only at the point of
the runtime prompt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 21:57:39 +02:00
x01dcandClaude Sonnet 5 25a6b89b92 docs(flomni): document the at_each_angle hook GUI dropdown and webpage display
CI for csaxs_bec / test (push) Successful in 1m35s
User manual: explains the new "At-each-angle hook" dropdown and its
"None (default)"/"(not registered in this session)" states, plus that
an active hook shows on the status webpage.

AI_docs: updates section 3.4 (GUI widget added, webpage display
added, extended sim-validation note for the global-var publishing and
webpage payload) and the plan's top status line. GUI test checklist
gets a new section 6b (test steps 28-35: dropdown population/refresh,
Submit vs Add-to-queue behaviour, the "not registered" label, and the
webpage's queue-detail + Current-measurement rendering) and an updated
section 1 item 9 + top status line noting none of this is click-tested
yet.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 21:26:44 +02:00
x01dcandClaude Sonnet 5 08e1122230 feat(flomni): show the active at_each_angle hook on the status webpage
TQ_PARAM_DISPLAY (the queue job detail table) and _CURRENT_PARAM_KEYS
(the live 'Current measurement' section) are both hardcoded mirrors of
which tomo params to render -- at_each_angle_hook wasn't in either, so
a hook-driven job wouldn't crash the page but also wouldn't show that
anything non-standard was running. Adds at_each_angle_hook to
_CURRENT_PARAM_KEYS (Python side, gates inclusion in the JSON payload
on the value actually being set) and a conditional row in
buildParamRows() (JS side, only rendered when the value is present --
deliberately left out of TQ_PARAM_DISPLAY so a normal job doesn't grow
a "-" row nobody needs). Sim-validated: current_params includes
at_each_angle_hook when set and omits it when not.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-13 21:24:52 +02:00