Conversation
…ce enum Replace the implicit @chain_breaker decorator system with a declarative InputSource enum for explicit input source control in pipeline steps. This eliminates action-at-distance effects and provides cleaner, more predictable pipeline behavior. Changes by functional area: * Constants & Type System: Add InputSource enum with PREVIOUS_STEP (default) and PIPELINE_START (replaces @chain_breaker) strategies. Export through constants module for system-wide access. * Core Pipeline Architecture: Replace 50+ lines of complex chain_breaker detection logic in path planner with clean InputSource strategy resolution. Remove chain_breaker decorator definition entirely. Simplify path connectivity validation. * Step System Integration: Add input_source parameter to AbstractStep and FunctionStep constructors with InputSource.PREVIOUS_STEP default. Maintain backward compatibility while enabling explicit input source declaration. * Position Generation Functions: Remove @chain_breaker decorators from all 3 position generation functions (MIST, Ashlar CPU/GPU). Clean up imports across affected files. * Infrastructure & Utilities: Add UTF-8 logging support for emoji-based logging prefixes. Fix parameter editor widget to handle new step parameters gracefully. The new system provides explicit control over step input sources while maintaining functional equivalence with the previous @chain_breaker behavior. Steps now declare input_source=InputSource.PIPELINE_START instead of using the implicit decorator.
…ties Remove the requires_disk_input and requires_disk_output abstract properties from AbstractStep as they were redundant with the existing force_disk_output parameter and provided no meaningful functionality. Changes by functional area: * Core Step System: Remove abstract property definitions from AbstractStep and concrete implementations from FunctionStep. These properties always returned False and were not used for meaningful decision-making. * Pipeline Compiler: Simplify zarr backend selection logic to use only force_disk_output parameter instead of the unused requires_disk_output property. This maintains the same functionality with cleaner code. * Contract Validator: Remove validation checks for the removed properties and update error messages to reflect that only path planner validation remains. * Documentation: Update architecture documentation to remove references to the removed properties and clarify that force_disk_output is the primary control mechanism for disk materialization. The force_disk_output parameter provides all the functionality that was intended by these abstract properties, making this removal a pure simplification without functional impact. This aligns with the InputSource system cleanup goals of reducing unnecessary abstractions.
trissim
added a commit
that referenced
this pull request
Oct 4, 2025
Comprehensive documentation of all fixes: - Bug #1: OMERO data directory path (CRITICAL) - Bug #2: Docker Compose version warning - Bug #3: Execution server default path - Bug #4: Demo script path Includes: - Problem descriptions - Solutions implemented - Code changes - Technical details of dual-mode architecture - Migration guide - Testing status
popjell
pushed a commit
to popjell/openhcs
that referenced
this pull request
Oct 15, 2025
Comprehensive documentation of all fixes: - Bug OpenHCSDev#1: OMERO data directory path (CRITICAL) - Bug OpenHCSDev#2: Docker Compose version warning - Bug OpenHCSDev#3: Execution server default path - Bug OpenHCSDev#4: Demo script path Includes: - Problem descriptions - Solutions implemented - Code changes - Technical details of dual-mode architecture - Migration guide - Testing status
popjell
pushed a commit
to popjell/openhcs
that referenced
this pull request
Oct 15, 2025
Comprehensive documentation of all fixes: - Bug OpenHCSDev#1: OMERO data directory path (CRITICAL) - Bug OpenHCSDev#2: Docker Compose version warning - Bug OpenHCSDev#3: Execution server default path - Bug OpenHCSDev#4: Demo script path Includes: - Problem descriptions - Solutions implemented - Code changes - Technical details of dual-mode architecture - Migration guide - Testing status
trissim
added a commit
that referenced
this pull request
Oct 28, 2025
Three critical fixes for plate manager execution control:
**1. Fixed: UI never gets informed when pipeline execution completes**
Root Cause: QMetaObject.invokeMethod with positional arguments doesn't work
reliably in PyQt6. The completion poller thread was calling:
QMetaObject.invokeMethod(self, '_on_execution_complete',
Qt.QueuedConnection, result, ready_items)
But the slot handler was never being called, leaving execution_state stuck
in 'running' even though ZMQ server shows 'idle'.
Fix:
- Added internal signals: _execution_complete_signal, _execution_error_signal
- Connected signals to handlers in __init__
- Completion poller now emits signals instead of using QMetaObject.invokeMethod
- Signals are thread-safe and work reliably across threads
**2. Fixed: Stop button gets stuck in 'Terminating execution' state**
Root Cause: When completion handler wasn't called (due to issue #1), the
execution_state remained 'stopping' forever. Clicking stop again would fail
with 'plate isn't in run mode' error.
Fix: Completion handler now properly resets execution_state to 'idle' when
called via signal.
**3. Added: Force Kill mode for stop button**
User requirement: 'the button should change to Force Kill and act just like
the force kill button in the zmq browser'
Implementation:
- First click: Graceful shutdown (graceful=True), button changes to 'Force Kill'
- Second click: Force shutdown (graceful=False), kills immediately
- Added 'force_kill_ready' execution state
- Updated button state logic to show 'Force Kill' text when ready
- Graceful shutdown keeps button enabled for force kill option
- Force kill resets state to idle after completion
Result:
✅ UI properly updates when pipeline execution completes
✅ Execution state correctly transitions: running → idle
✅ Stop button works reliably without getting stuck
✅ Force Kill mode available after graceful shutdown attempt
✅ Matches ZMQ browser force kill behavior
trissim
added a commit
that referenced
this pull request
Nov 5, 2025
…all behavior This commit fixes three critical bugs in the parameter form manager related to nested configuration dataclasses, completing the context tree refactoring work. **Problem 1: Nested Config Edits Not Reflected in Sibling Placeholders** When editing nested config fields (e.g., well_filter_config.well_filter), the changes were visible in the nested manager but sibling configs (path_planning_config, step_well_filter_config, etc.) were not seeing the updated values in their placeholders. They continued to show 'Pipeline default' instead of inheriting the newly edited value. Root Cause: - Nested manager updated its own self.parameters correctly - Parent manager received the parameter_changed signal - But parent's self.parameters[parent_field_name] was NOT being updated - When siblings built their context stack via ConfigNode.get_live_instance(), they got the parent's stale nested dataclass values - Additionally, nested managers were registering as isolated root nodes in the tree registry instead of as children of the parent node Fixes: 1. Update parent's self.parameters[parent_field_name] when nested fields change (parameter_form_manager.py:1074) 2. Add parent_field_name to parent's _user_set_fields for save persistence (parameter_form_manager.py:1079) 3. Pass parent_node=self._config_node when creating nested managers so they register as children in the tree registry, not isolated roots (parameter_form_manager.py:622) **Problem 2: Nested Config Edits Not Saved to Disk** When editing nested config fields in PipelineConfig and saving, the changes were lost. On reopen, the fields reverted to their original values. This worked fine for GlobalPipelineConfig and StepConfig, but not PipelineConfig. Root Cause: - When nested fields changed, parent's self.parameters was updated (fix #1) - But parent's _user_set_fields was NOT updated - get_user_modified_values() only returns fields in _user_set_fields - So when saving, the modified nested configs were excluded from the save - Result: nested config changes were discarded Fix: - Add parent_field_name to self._user_set_fields in _on_nested_parameter_changed (parameter_form_manager.py:1079) **Problem 3: Reset All Button Doesn't Trigger Sibling Placeholder Updates** Clicking 'Reset All' on a nested config (e.g., well_filter_config) reset the fields correctly, but sibling configs didn't update their placeholders. Individual field resets and manual edits worked fine, only 'Reset All' was broken. Root Cause: - reset_all_parameters sets _block_cross_window_updates=True for performance - _on_nested_parameter_changed checks _should_skip_updates() which returns True when _block_cross_window_updates=True - This blocked not only cross-window signals (intended) but also local parent parameter updates and sibling placeholder refreshes (unintended bug) - The flag was being used too broadly Fix: - Change _on_nested_parameter_changed to only check _in_reset flag, not the full _should_skip_updates() check (parameter_form_manager.py:1033) - This allows local updates (parent parameters, sibling placeholders) while still preventing cross-window signal spam during bulk operations **Problem 4: Cleared Fields (None) Re-materialize on Save/Reopen** When clearing a field (setting to None), saving, and reopening, the None value would be materialized back to a concrete value. User explicitly cleared the field but it came back. Root Cause: - get_user_modified_values() correctly returned None for cleared fields - But reconstruct_nested_dataclasses() called the lazy dataclass constructor with None values: LazyWellFilterConfig(well_filter=None) - The constructor's __post_init__ method resolved the None against context, materializing a concrete value instead of preserving the None - This defeated the purpose of clearing the field Fix: - Separate None and non-None values in reconstruct_nested_dataclasses() - Create instance with only non-None values (let lazy resolution work normally) - Use object.__setattr__ to set None values directly, bypassing lazy resolution (dataclass_reconstruction_utils.py:47-77) **Architecture Context** These fixes complete the context tree refactoring described in plans/ui-anti-ducktyping/plan_01_context_tree.md. The tree registry provides hierarchical context resolution (Global→Plate→Step) with proper parent-child relationships for nested configs. Key insight: Nested configs are NOT separate tree nodes - they're part of the parent dataclass. But they have their own form managers for UI editing. The parent must track changes to nested fields and propagate them to siblings. Files Modified: - openhcs/pyqt_gui/widgets/shared/parameter_form_manager.py - openhcs/pyqt_gui/widgets/shared/services/dataclass_reconstruction_utils.py - openhcs/pyqt_gui/widgets/shared/services/placeholder_refresh_service.py
27 tasks
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.
Replace @chain_breaker Decorator with Declarative InputSource System
Summary
This PR replaces the implicit
@chain_breakerdecorator system with an explicitInputSourceenum strategy, providing cleaner and more predictable pipeline behavior.Changes Made
🎯 Core InputSource System
InputSourceenum withPREVIOUS_STEP(default) andPIPELINE_STARTstrategiesinput_sourceparameter🔧 Path Planner Simplification
diskfor PIPELINE_START)🧹 Function Migration
mist_compute_tile_positionsashlar_compute_tile_positions_cpuashlar_compute_tile_positions_gpuBenefits
✅ Declarative over Implicit
✅ Simplified Architecture
✅ Backward Compatible
PREVIOUS_STEPis default)input_sourceUsage Examples
Standard processing (unchanged):
Position generation (new explicit syntax):
Quality control accessing original data:
Technical Details
InputSource Enum Values
PREVIOUS_STEP = "previous"- Standard pipeline chaining (default)PIPELINE_START = "start"- Access original input data (replaces @chain_breaker)Path Planner Changes
Files Modified
openhcs/constants/input_source.py- New InputSource enumopenhcs/constants/__init__.py- Export InputSourceopenhcs/core/steps/abstract.py- Add input_source parameteropenhcs/core/steps/function_step.py- Pass through input_source parameteropenhcs/core/pipeline/path_planner.py- Replace chain_breaker logicopenhcs/core/pipeline/function_contracts.py- Remove chain_breaker decoratorTesting
Breaking Changes
None - This is a backward-compatible refactor that maintains all existing functionality while providing a cleaner interface.
Migration Guide
For Position Generation Functions
For Custom Chain Breaking
Future Enhancements
This declarative approach enables future enhancements such as:
SPECIFIC_STEP,CHECKPOINT)Architectural Impact
This change represents a significant improvement in OpenHCS's architectural clarity:
The InputSource system provides a solid foundation for future pipeline enhancements while maintaining full backward compatibility with existing code.