Repository navigation
Replay scrubber, concurrent wash monitoring, run-sequence editing, softer imager check - #19
Merged
Merged
Conversation
Reusing an imager (notably initial_imager re-listed in the exchange rounds) previously raised a hard ValidationError, blocking the legitimate case of deliberately redundant imaging rounds (e.g. for testing). Downgrade it to a soft advisory: add ExchangeExperiment.design_warnings() + a module-level design_warnings() collector, surfaced non-blocking in the Experiment Design tab on Save/Translate. Plain repeats within the imagers list (ordinary Exchange-PAINT) are deliberately NOT warned about. Also lands check_runnable() in protocol_schema (orphan-wait + deadlock-cycle detection) ahead of the sequence-editing work that gates on it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tion Operators can now add/duplicate/delete/move Run Sequence steps from the Run Sequence tab (edit toolbar operating on the selected list/row). Any structural edit flags the run as modified: the run metadata records sequence_modified and suffixes experiment_type with -modified (build_experiment_payload, threaded through live_run), and a '⚠ modified sequence' badge shows in the tab. Editing can introduce a deadlock, so ExperimentService.check_runnable() (over schemas.check_runnable) detects orphan waits and circular cross-subsystem waits, mirroring the orchestrator's (target,value) matching incl. the legacy '<target> <value>' prefix. It runs inline after each edit (non-blocking hint) and as a hard Start gate — scoped to hand-edited sequences so un-edited/legacy protocols keep their existing behavior. Tests: test_protocol_schema (new) for check_runnable; service modified-flag + start-gate scoping; headless GUI add/delete/move + inline-deadlock; payload modified flag. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add an opt-in (Exchange design: monitor_fluid, monitor_t_exp, monitor_margin_s)
that, for each per-round imager injection and inter-round wash, acquires a
short movie CONCURRENTLY with the fluid step so the operator can watch washing/
flushing efficiency live. create_stepset_monitor emits a fluid 'monitor-start'
signal before the injection, raises the laser to acquisition power via illu
('monitor-power'), and sizes the img movie from the estimated flush duration
(protocols.timing) + margin — the following acquisition's fluid_wait resyncs.
Monitoring acquires are tagged (monitoring: True, '(wash monitor)' name): the
Run Sequence tab excludes them from the exchange-round count/goto (_is_monitoring,
mirroring _is_dark) and live_run flags the FOV so monitoring movies aren't
mistaken for scientific datasets.
Tests: builder monitor insertion + paired signals + frame scaling +
check_runnable clean + off-by-default; GUI round-count exclusion.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Record a run's live streams to a JSONL timeline and scrub them afterwards. ReplayRecorder taps the live seam (thumbnails carry image bytes + boxes, so no extra capture) and polls progress + fluid-state at 0.5 s; ReplayController loads the timeline and, on seek, reconstructs each stream as of time T and pushes it to sinks. The Run Sequence tab's Progress group gains a '▶ Replay run' toggle that reveals a timeline slider + play/speed controls; scrubbing re-emits recorded LiveUpdates through the real live panels (image + boxes), drives the fluid schematic (live poll suspended), and highlights the active run-sequence step. main_window owns the recorder lifecycle (start on run start, finalize + offer replay on finish) and wires the controller sinks across tabs. Webcam replay (per-round .avi clips already on disk) is a documented follow-up. Tests: test_replay (codec round-trip, recorder, controller seek semantics); headless GUI scrubber drives the step highlight + re-emits live updates. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ager-check Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Defensively finalize any still-open recording at the top of _start_replay_recording so a prior run or a failed recorder start cannot leave a stale _replay_hub_client that _stop_replay_recording would later remove from the wrong hub. (code-review follow-up) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Complete the replay feature's webcam leg. The recorder now stamps a wall-clock anchor (t0_utc) in the timeline's meta header; WebcamReplaySource (monitoring/webcam_replay.py) discovers the run's per-round .avi clips, maps each clip's UTC-stamped filename to a run-relative ms position, and — on seek — decodes the composite frame on screen at that moment (pure-Python AVI reader, no OpenCV) via a one-clip cache. ReplayController gains a set_webcam sink (driven with the scrub time); the Webcams tab gains show_replay_frame + set_replay_mode (live preview suspended). main_window aligns the clips using the monitoring controller's new output_dir/fps accessors and wires the sink. Also fixes a latent F841 (unused var) in the sequence-edit GUI test. Tests: WebcamReplaySource discovery/alignment/seek over real AVI clips written by RawAviWriter; controller webcam-sink dispatch; webcams-tab replay display. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Editing a finished run's sequence (add/delete/move) desyncs the step lists from the recorded timeline, so a subsequent scrub would highlight the wrong steps. Clear the replay controller on any structural edit (exits replay mode, disables the button). (code-review follow-up) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
black 25.9.0 flagged these under 'black --check .'; my local pre-commit checks used 'black --check -q … | tail' which hid the 'would reformat' output and masked the non-zero exit through the pipe. Reformatted; 'black --check .' and 'flake8 .' now pass repo-wide. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The replay slider was already a free seek (drag to any moment; the speed combo only sets autoplay rate). Add protocol-position jumping: in replay mode, clicking a step or picking a round seeks the timeline to when that step/round became active, via ReplayController.first_time_reaching(system, index) over the recorded progress snapshots. Editing stays available in replay (and still clears the stale replay). Tests: controller step->time mapping (incl. never-reached -> None); GUI click-a-step jumps the slider to the recorded time. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replay was limited to the just-finished run (everything in memory). Make a run self-contained and reopenable: - The recorder embeds the run's compiled protocol in the timeline's meta header (alongside t0_utc + run_id), so a *_replay.jsonl file alone reconstructs both the timeline and the step lists. ReplayController exposes run_id + protocol. - 'Open past run…' in the Run Sequence tab picks a saved *_replay.jsonl (its run id disambiguates multiple runs in one save_dir), loads the embedded protocol into the view, and enters replay. main_window.open_past_run wires it. - WebcamReplaySource.from_run finds the run's clips under the file's folder and its fluidics_cam[_N] subfolders, filtered by (sanitized) run id so clips from other runs in the same folder are not mixed in; from_dir gained a run_id filter. Tests: recorder embeds protocol; controller exposes run_id/protocol; from_run subfolder search + run-id filter; headless open_past_run loads protocol + enters replay + shows a webcam frame. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
During replay the overall + steps-in-round bars and the Round-k/N status line showed stale live state; only the step lists were shaded. Factor the bar rendering out of _poll_progress into shared helpers (_set_overall_bar, _set_step_status, _current_round_counts) and have replay_set_progress drive the same bars from the scrubbed progress — without the live-only side effects (round stopwatch, substep bars, finish detection). So scrubbing now moves the progress bars to the run's position at time T, matching the live display. Tests: replay scrubber asserts the overall bar/count reflect the scrubbed progress. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The replay transport lived inside the Run Sequence tab, so scrubbing was only possible while on that tab. Extract it into a ReplayBar widget (gui/widgets/replay_bar.py) placed above the QTabWidget, so a finished (or opened-from-disk) run can be scrubbed while viewing ANY tab's data — the controller's sinks already drive the live view / webcam / fluid schematic / step-highlight regardless of which tab is in front. The Run Sequence tab keeps only its replay responsibilities: replay_set_progress (the progress sink) and routing step/round clicks back to the bar as timeline jumps (on_replay_seek_step) plus dropping a stale replay on edit (on_sequence_edited). main_window owns the bar, wires its sinks across the tabs, and set_replay_active tells the tab when clicks should jump the timeline. Tests updated to drive w.replay_bar. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…itoring-seqedit # Conflicts: # CHANGELOG.md
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.
Summary
Four operator-facing features for the PycroFlow GUI, each as its own tested commit.
1 · Post-run replay (master scrubber). A run's live streams are recorded to a
*_replay.jsonltimeline (seam thumbnail/metrics/state/log — thumbnails already carry image bytes + detection boxes, so no extra capture — plus 0.5 s polls of run-sequence progress and fluidics state). The Run Sequence tab's Progress group gains a ▶ Replay run toggle revealing a timeline slider + play/speed controls; scrubbing re-emits recordedLiveUpdates through the real live panels (image + boxes), drives the fluid schematic (live poll suspended), highlights the active run-sequence step, and replays the fluidics webcam — per-round.aviclips aligned to the timeline via a wall-clock anchor, decoded with the pure-Python AVI reader (no OpenCV) and shown in the Webcams tab.2 · Concurrent wash/flush monitoring (opt-in). Exchange designs gain
monitor_fluid(+monitor_t_exp/monitor_margin_s). When on, the builder acquires a short movie concurrently with each per-round imager injection and inter-round wash (monitor-start→ illumination to acq power → movie sized from the estimated flush duration + margin; the following acquisition'sfluid_waitresyncs). Monitoring acquisitions are flagged, excluded from the exchange-round count, and tagged on the registry FOV.3 · Run-sequence editing. Add / duplicate / delete / move steps from the Run Sequence tab. Any structural edit flags the run as modified (registry records
sequence_modified,experiment_typesuffixed-modified, badge shown) and runs a consistency check (schemas.check_runnable) that detects orphan waits and circular deadlocks — inline hint after each edit, hard Start gate for edited sequences.4 · Softer imager verification. Reusing an imager (notably
initial_imagerre-listed in the rounds) no longer hard-errors — redundant imaging rounds are legitimate (e.g. for testing). Now a non-blocking advisory (design_warnings) on Save/Translate; ordinary repeats in the imagers list aren't flagged.Branch note
Forked from
feature/ibidi-liveint-bundle, which is already merged intodevelop, so this PR is a clean 8-commit diff (just this work). It targetsdevelopdirectly because its integration branch has already been promoted — not the usual mid-flight integration-branch flow.New modules
live_analysis/replay_recorder.py,live_analysis/replay_player.py,monitoring/webcam_replay.py,schemas/protocol_schema.check_runnable,protocols/builder.create_stepset_monitor.Testing
test_replay.py,test_protocol_schema.py, plus additions to protocols/design/services/GUI suites). The one failure,test_placeholder_when_monet_absent, is pre-existing and environmental (monet installed in this dev container — fails on the base branch too).🤖 Generated with Claude Code