Repository navigation
feat(dispatch): wire context models into handler dispatch path [OMN-984] - #225
Conversation
Integrates context models from OMN-948 (PR #224) into MessageDispatchEngine so handlers receive appropriate context during execution. Changes: - Add ProtocolHandlerContext protocol for common context interface - Update register_handler() to require node_kind parameter - Add _build_handler_context() factory for context creation - Update _execute_handler() to pass context to handlers - Reject RUNTIME_HOST as handler node_kind Context types by node_kind: - EFFECT: ModelEffectContext (with now, retry_attempt) - COMPUTE: ModelComputeContext (no now - pure function) - REDUCER: ModelReducerContext (no now - pure function) - ORCHESTRATOR: ModelOrchestratorContext (with now) Breaking change: register_handler() now requires node_kind, handlers must accept (envelope, context) signature.
|
Warning Rate limit exceeded@jonahgabriel has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 12 minutes and 54 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (1)
WalkthroughThe PR adds a new ProtocolHandlerContext protocol that standardizes handler execution context with correlation and tracing fields. The message dispatch engine is updated to construct node-specific context objects and pass them to handlers during invocation, enabling context propagation across EFFECT, COMPUTE, REDUCER, and ORCHESTRATOR node types. Changes
Sequence DiagramsequenceDiagram
participant Client
participant DispatchEngine as Message<br/>Dispatch Engine
participant ContextBuilder as Context<br/>Builder
participant Handler
Client->>DispatchEngine: dispatch(envelope)
activate DispatchEngine
DispatchEngine->>DispatchEngine: lookup handler + node_kind
DispatchEngine->>ContextBuilder: _build_handler_context(envelope, node_kind)
activate ContextBuilder
ContextBuilder->>ContextBuilder: select context type<br/>(EFFECT/COMPUTE/REDUCER/ORCHESTRATOR)
ContextBuilder->>ContextBuilder: map envelope fields<br/>(correlation_id, trace_id, etc.)
ContextBuilder-->>DispatchEngine: context: ProtocolHandlerContext
deactivate ContextBuilder
DispatchEngine->>Handler: invoke(envelope, context)
activate Handler
Handler->>Handler: process with context
Handler-->>DispatchEngine: result
deactivate Handler
DispatchEngine-->>Client: result
deactivate DispatchEngine
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
Comment |
PR Review: Context Models Integration into Message DispatchOverall AssessmentLGTM with minor suggestions ✅ This is an excellent implementation that cleanly integrates the node-specific context models from PR #224 into the message dispatch path. The design is architecturally sound, well-tested, and follows ONEX conventions. Strengths 💪1. Architectural Soundness
2. Code Quality
3. Test Coverage
4. ONEX Conventions Compliance
Suggestions for Improvement 🔍1. Correlation ID Fallback (Minor)Location: Current implementation generates a fallback UUID when correlation_id is None. Consider logging a warning for observability, as missing correlation IDs could indicate upstream issues in production. 2. RUNTIME_HOST Rejection - Error Code Choice (Nitpick)Location: The defensive check uses INVALID_STATE, but INVALID_PARAMETER might be more semantically accurate. Low impact since this code path should never execute. 3. Test Coverage - Retry Attempt MappingI don't see explicit tests verifying that 4. Protocol Compliance Verification (Nice-to-Have)Consider adding a runtime assertion in Security & Performance ✅Security
Performance
Breaking Changes - Migration Path 📋Impact: All existing handlers must update signature from Recommendations:
Final VerdictThis PR represents high-quality engineering:
The minor suggestions above are optional improvements - this PR is ready to merge as-is. Recommendation: APPROVE ✅ Testing Note: Verify all 73 dispatch engine tests pass in CI before merge. Great work! 🎉 |
…ntext building [OMN-984] - Add warning log when correlation_id is None and fallback UUID is generated - Change error code from INVALID_STATE to INVALID_PARAMETER for RUNTIME_HOST rejection - Add runtime assertion for protocol compliance verification (debug-only) - Refactor _build_handler_context to use single return point - Add test verifying retry_count → retry_attempt mapping for EFFECT handlers
Code Review: Context Models Integration (PR #225)SummaryThis PR successfully integrates node-specific context models into the message dispatch path. The implementation is well-architected, follows ONEX conventions, and includes comprehensive test coverage. ✅ Strengths1. Excellent Architecture & Design
2. Strong Documentation
3. Robust Error Handling
4. Comprehensive Test Coverage
5. Type Safety
🔍 Issues FoundCRITICAL: Missing
|
… tests [OMN-984] - Add max(0, retry_count) validation to prevent Pydantic ge=0 constraint violation - Add test verifying context fields propagate correctly from envelope - Add test for null trace_id/span_id handling in context propagation
PR Review: feat(dispatch): wire context models into handler dispatch path [OMN-984]SummaryThis PR successfully integrates context models from PR #224 into the MessageDispatchEngine, enabling handlers to receive appropriate execution context based on their node_kind. The implementation is well-designed and follows ONEX architecture principles. ✅ Strengths1. Excellent Protocol DesignThe
2. Type Safety & Validation# Strong validation at registration time (lines 435-454)
if node_kind == EnumNodeKind.RUNTIME_HOST:
raise ModelOnexError(
message="Cannot register handler with node_kind RUNTIME_HOST...",
error_code=EnumCoreErrorCode.INVALID_PARAMETER,
)
# Runtime assertion during development (lines 1402-1406)
if __debug__:
assert isinstance(context, ProtocolHandlerContext), ...3. Defensive Programming
4. Comprehensive Test Coverage634+ lines of test additions covering:
5. Breaking Change CommunicationClear documentation of breaking changes:
🔍 Code Quality ObservationsMinor: Potential Optimization OpportunityFile: retry_attempt = max(0, envelope.retry_count)Question: Is Suggestion (optional): retry_attempt = envelope.retry_count
if retry_attempt < 0:
self._logger.warning(
"Envelope has negative retry_count=%d (envelope_id=%s), clamping to 0",
retry_attempt, envelope.envelope_id
)
retry_attempt = 0Minor: Import OrganizationFile: The imports are getting dense. Consider grouping by category for better readability: # Enums
from omnibase_core.enums.enum_core_error_code import EnumCoreErrorCode
from omnibase_core.enums.enum_dispatch_status import EnumDispatchStatus
from omnibase_core.enums.enum_execution_shape import EnumMessageCategory
from omnibase_core.enums.enum_node_kind import EnumNodeKind
# Context Models
from omnibase_core.models.compute.model_compute_context import ModelComputeContext
from omnibase_core.models.effect.model_effect_context import ModelEffectContext
from omnibase_core.models.reducer.model_reducer_context import ModelReducerContext
from omnibase_core.models.orchestrator.model_orchestrator_context import ModelOrchestratorContext
# Dispatch Models
from omnibase_core.models.dispatch.model_dispatch_metrics import ModelDispatchMetrics
...🛡️ Security & Thread Safety✅ Thread-Safe DesignAll context models use
This ensures immutability after creation, making them safe for concurrent handler execution per CLAUDE.md guidelines. ✅ No Security Concerns
📊 Performance Considerations✅ Minimal Overhead
✅ Executor Pattern PreservedLine 1442: Sync handlers still run in executor to avoid blocking event loop return await loop.run_in_executor(None, handler, envelope, context)🧪 Test QualityExcellent CoverageThe test suite demonstrates:
Test Statistics
📝 Documentation Quality✅ Excellent Docstrings
✅ Architecture AlignmentThe PR correctly maps context types to node kinds per ONEX Four-Node Architecture:
This design enforces architectural purity at the type level. 🎯 Recommendations✅ Ready to MergeThis PR is high-quality and ready for merge with no blocking issues. The optional suggestions above are for future consideration. Post-Merge Actions
🔬 Mypy & Type CheckingThe PR maintains strict type safety:
Per CLAUDE.md requirement: "Strict Type Checking: 100% mypy strict mode compliance (0 errors across 1865 source files)" - this PR adheres to that standard. Final VerdictLGTM! 🚀 This is a well-architected, thoroughly tested feature that strengthens the ONEX framework's type safety and handler execution model. The breaking changes are necessary and well-communicated. The code quality, documentation, and test coverage all meet the project's high standards. Recommended Action: Approve and merge Reviewed by: Claude Code (Sonnet 4.5) |
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/omnibase_core/runtime/message_dispatch_engine.py (1)
419-427: Stale error message references old handler signature.The error message on line 424 still references the old handler signature without the context parameter:
Expected signature: (envelope: ModelEventEnvelope[Any]) -> AnyThis should be updated to reflect the new signature with context.
🔎 Proposed fix
if handler is None or not callable(handler): raise ModelOnexError( message=( f"Handler for '{handler_id}' must be callable (function or async function). " f"Got {type(handler).__name__}. " - f"Expected signature: (envelope: ModelEventEnvelope[Any]) -> Any" + f"Expected signature: (envelope: ModelEventEnvelope[Any], context: ProtocolHandlerContext) -> Any" ), error_code=EnumCoreErrorCode.INVALID_PARAMETER, )
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
src/omnibase_core/protocols/__init__.py(2 hunks)src/omnibase_core/protocols/handler/__init__.py(1 hunks)src/omnibase_core/protocols/handler/protocol_handler_context.py(1 hunks)src/omnibase_core/runtime/message_dispatch_engine.py(9 hunks)tests/unit/runtime/test_message_dispatch_engine.py(39 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.py: Always call super().init(container) in node class constructors to initialize base class boilerplate
Use ModelOnexError with EnumCoreErrorCode for all error handling instead of generic Exception
Use protocol names with container.get_service() for dependency injection, never use concrete class names
Use PEP 604 union syntax (str | None) instead of Optional or Union types
Use @standard_error_handling decorator from omnibase_core.decorators.error_handling to eliminate try/catch boilerplate
Do NOT share node instances across threads - use thread-local instances or separate instances per thread
ORCHESTRATOR nodes CANNOT return typed results - they can only emit events and intents, with result=None required
Use EnumNodeKind for architectural role classification (EFFECT, COMPUTE, REDUCER, ORCHESTRATOR, RUNTIME_HOST) and EnumNodeType for implementation type discovery
Use FileRegistry.load() or FileRegistry.load_all() for contract loading with proper error handling for FILE_NOT_FOUND, FILE_READ_ERROR, CONFIGURATION_PARSE_ERROR, CONTRACT_VALIDATION_ERROR, DUPLICATE_REGISTRATION, DIRECTORY_NOT_FOUND
Use ModelONEXContainer in node constructors for dependency injection, never use ModelContainer[T]
Use duck typing with protocols for service resolution - do not use isinstance checks
Files:
src/omnibase_core/protocols/handler/__init__.pysrc/omnibase_core/protocols/handler/protocol_handler_context.pysrc/omnibase_core/protocols/__init__.pytests/unit/runtime/test_message_dispatch_engine.pysrc/omnibase_core/runtime/message_dispatch_engine.py
tests/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Use pytest markers @pytest.mark.unit, @pytest.mark.integration, @pytest.mark.slow, @pytest.mark.smoke, @pytest.mark.performance to classify tests
Files:
tests/unit/runtime/test_message_dispatch_engine.py
🧠 Learnings (2)
📚 Learning: 2025-12-20T04:09:41.822Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-20T04:09:41.822Z
Learning: Applies to **/*.py : Use EnumNodeKind for architectural role classification (EFFECT, COMPUTE, REDUCER, ORCHESTRATOR, RUNTIME_HOST) and EnumNodeType for implementation type discovery
Applied to files:
tests/unit/runtime/test_message_dispatch_engine.pysrc/omnibase_core/runtime/message_dispatch_engine.py
📚 Learning: 2025-12-20T04:09:41.822Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-20T04:09:41.822Z
Learning: Applies to **/*.py : Use ModelOnexError with EnumCoreErrorCode for all error handling instead of generic Exception
Applied to files:
tests/unit/runtime/test_message_dispatch_engine.pysrc/omnibase_core/runtime/message_dispatch_engine.py
🧬 Code graph analysis (4)
src/omnibase_core/protocols/handler/__init__.py (2)
tests/unit/runtime/test_message_dispatch_engine.py (16)
handler(263-266)handler(324-327)handler(352-355)handler(372-375)handler(420-423)handler(441-444)handler(512-515)handler(565-569)handler(699-702)handler(735-738)handler(830-833)handler(1082-1085)handler(1189-1192)handler(1298-1301)handler(1482-1485)handler(1528-1535)src/omnibase_core/protocols/handler/protocol_handler_context.py (1)
ProtocolHandlerContext(34-85)
src/omnibase_core/protocols/handler/protocol_handler_context.py (1)
src/omnibase_core/models/metadata/model_metadata_field_info.py (1)
uuid(157-176)
src/omnibase_core/protocols/__init__.py (2)
tests/unit/runtime/test_message_dispatch_engine.py (16)
handler(263-266)handler(324-327)handler(352-355)handler(372-375)handler(420-423)handler(441-444)handler(512-515)handler(565-569)handler(699-702)handler(735-738)handler(830-833)handler(1082-1085)handler(1189-1192)handler(1298-1301)handler(1482-1485)handler(1528-1535)src/omnibase_core/protocols/handler/protocol_handler_context.py (1)
ProtocolHandlerContext(34-85)
src/omnibase_core/runtime/message_dispatch_engine.py (6)
src/omnibase_core/enums/enum_node_kind.py (1)
EnumNodeKind(13-118)src/omnibase_core/models/compute/model_compute_context.py (1)
ModelComputeContext(37-104)src/omnibase_core/models/effect/model_effect_context.py (1)
ModelEffectContext(51-123)src/omnibase_core/models/orchestrator/model_orchestrator_context.py (1)
ModelOrchestratorContext(51-120)src/omnibase_core/models/reducer/model_reducer_context.py (1)
ModelReducerContext(31-96)src/omnibase_core/protocols/handler/protocol_handler_context.py (5)
ProtocolHandlerContext(34-85)correlation_id(68-70)envelope_id(73-75)trace_id(78-80)span_id(83-85)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: claude-review
🔇 Additional comments (13)
src/omnibase_core/protocols/handler/protocol_handler_context.py (1)
1-88: Well-designed protocol with clear documentation.The
ProtocolHandlerContextprotocol is well-structured with:
- Appropriate use of
@runtime_checkablefor duck typing support- PEP 604 union syntax (
UUID | None) per coding guidelines- Comprehensive docstrings covering thread safety and design rationale
- Clean, minimal interface with only the necessary causality tracking fields
The decision to keep node-specific fields (like
now,retry_attempt) on concrete types rather than the protocol is sound for maintaining separation of concerns.src/omnibase_core/protocols/__init__.py (1)
123-127: LGTM - Clean public API export.The
ProtocolHandlerContextis correctly imported from the handler subpackage and added to__all__. The placement follows the existing organizational pattern with a dedicated "Handler Module Exports" section.Also applies to: 294-297
src/omnibase_core/protocols/handler/__init__.py (1)
1-11: LGTM - Standard package initializer.Clean re-export pattern that makes
ProtocolHandlerContextavailable at the package level.tests/unit/runtime/test_message_dispatch_engine.py (5)
30-37: LGTM - Imports updated correctly.New imports for
EnumNodeKindandProtocolHandlerContextare correctly added and follow the existing import organization.
2343-2392: Well-structured context injection tests.The
TestContextInjectionclass provides comprehensive coverage for the new context injection functionality. The test for reducer context correctly verifies thatModelReducerContextis received and that thenowattribute is absent (preserving purity).
2443-2501: Critical test for retry_attempt mapping.This test correctly validates the mapping from
envelope.retry_counttoModelEffectContext.retry_attempt. The explicit assertion on line 2499-2500 is valuable for documenting this mapping behavior.
2641-2721: Comprehensive tracing field propagation test.Excellent test coverage for verifying all causality tracking fields (
correlation_id,trace_id,span_id,envelope_id) propagate correctly from the envelope to the handler context. The detailed assertion messages will be helpful for debugging failures.
2786-2805: RUNTIME_HOST rejection test.Good boundary test verifying that
RUNTIME_HOSTis explicitly rejected with the correct error code (INVALID_PARAMETER). This aligns with the design decision thatRUNTIME_HOSTis for infrastructure, not message handlers.src/omnibase_core/runtime/message_dispatch_engine.py (5)
90-107: LGTM - Imports organized correctly.New imports for
EnumNodeKind, all context model types, andProtocolHandlerContextare properly added. The grouping follows the existing import organization pattern.
130-134: Breaking change: Handler signature now includes context.The
HandlerFunctype alias update reflects the new handler signature(envelope, context). This is a documented breaking change per PR objectives.
438-456: Proper validation for node_kind parameter.The validation correctly:
- Checks that
node_kindis anEnumNodeKindinstance- Explicitly rejects
RUNTIME_HOSTwith a clear error message- Uses
ModelOnexErrorwithEnumCoreErrorCode.INVALID_PARAMETERper coding guidelines
1303-1408: Well-implemented context factory method.The
_build_handler_contextmethod correctly:
- Extracts causality IDs from the envelope with a fallback for missing
correlation_id- Protects against negative
retry_countwithmax(0, envelope.retry_count)- Creates the appropriate context model based on
node_kind- Includes a debug-only assertion for protocol compliance
The defensive logging for missing
correlation_id(lines 1338-1343) helps identify upstream issues without failing the dispatch.
1410-1442: Context injection works for both sync and async handlers.The updated
_execute_handlercorrectly:
- Builds the context once via
_build_handler_context- Passes both
envelopeandcontextto async handlers- Passes both arguments to sync handlers via
run_in_executorThe sync handler path on line 1442 correctly passes both positional arguments to the executor.
…-984] Replace silent max(0, retry_count) with explicit check and warning log to alert operators of potential data corruption when envelope has negative retry_count values.
Code Review - PR #225: Context Model IntegrationSummaryThis PR successfully integrates the context models from PR #224 into the message dispatch pipeline. The implementation is well-designed, thoroughly tested, and follows ONEX architectural principles. I recommend approval with minor suggestions below. ✅ Strengths1. Excellent Protocol Design
2. Strong Type Safety
3. Comprehensive Test Coverage
4. Defensive Programming
5. Breaking Change Handled Well
🔍 Areas for Improvement1. Missing Import in
|
🔄 Correction to Previous ReviewI need to correct an error in my previous review: ✅ uuid4 Import is PresentI incorrectly stated that from uuid import uuid4 # Line 85 - PRESENTThis is NOT a blocking issue. The import is correct. Updated RecommendationAPPROVE - All critical issues from my previous review were incorrect. The code is production-ready as-is. The "Areas for Improvement" I mentioned are all optional enhancements, not blockers:
This PR is well-implemented and ready to merge. My apologies for the confusion in the first review. Correction posted by Claude Code |
Summary
MessageDispatchEnginenode_kindProtocolHandlerContextprotocol for type-safe context handlingChanges
New Protocol (
protocols/handler/protocol_handler_context.py):correlation_id,envelope_id,trace_id,span_idMessageDispatchEngine Updates:
register_handler()now requiresnode_kindparameter_build_handler_context()factory creates context based onnode_kind_execute_handler()passes context to handlersRUNTIME_HOSTrejected as handler node_kindContext Types by Node Kind:
nowretry_attemptBreaking Changes
register_handler()now requiresnode_kind: EnumNodeKindparameter(envelope, context)signatureTest Plan
Summary by CodeRabbit
Release Notes
New Features
Breaking Changes
✏️ Tip: You can customize this high-level summary in your review settings.