Repository navigation
feat(runtime): enforce time injection context at dispatch [OMN-973] - #66
jonahgabriel merged 11 commits into
Conversation
Implement runtime dispatch enforcement for time injection context models. Reducers must NEVER receive `now`, orchestrators/effects must receive it. ## Changes ### New Models - `ModelDispatchContext`: Pydantic model with factory methods enforcing time injection rules per node kind (for_reducer, for_orchestrator, for_effect) - Model validator rejects reducer contexts with time injection at construction ### New Runtime Components - `DispatchContextEnforcer`: Creates appropriate context based on dispatcher's node_kind, injecting time only for orchestrator/effect nodes ### ONEX Architectural Rules Enforced | Node Kind | Time Injection | Rationale | |---------------|----------------|----------------------------------------| | REDUCER | FORBIDDEN | Must be deterministic for event replay | | COMPUTE | FORBIDDEN | Pure transformations, no side effects | | ORCHESTRATOR | REQUIRED | Needs time for deadlines/timeouts | | EFFECT | REQUIRED | Needs time for retries/metrics | ## Test Coverage - 43 unit tests for dispatch context enforcer - 32 integration tests for full dispatch flow - All 75 tests passing Acceptance Criteria: - [x] Runtime dispatch enforces context type - [x] Tests proving reducers cannot access `now` via runtime dispatch - [x] Integration tests for context injection at dispatch time
WalkthroughAdds an immutable ModelDispatchContext and a DispatchContextEnforcer to enforce ONEX time-injection rules per node kind, consolidates JsonValue imports, updates infra validation constants, and adds comprehensive unit and integration tests for dispatch context behavior. Changes
Sequence DiagramsequenceDiagram
participant Client
participant Enforcer as DispatchContextEnforcer
participant Envelope
participant ModelDC as ModelDispatchContext
participant Dispatcher
Client->>Enforcer: create_context_for_dispatcher(dispatcher, envelope)
Enforcer->>Dispatcher: inspect node_kind
Dispatcher-->>Enforcer: node_kind
alt node_kind is REDUCER or COMPUTE
Enforcer->>ModelDC: call for_reducer() / for_compute() (no now)
else node_kind is ORCHESTRATOR or EFFECT or RUNTIME_HOST
Enforcer->>ModelDC: call for_orchestrator()/for_effect()/for_runtime_host() (now = UTC)
end
Enforcer->>Envelope: extract correlation_id, trace_id
Envelope-->>Enforcer: ids (fallback uuid4 if missing)
Enforcer->>ModelDC: populate correlation_id, trace_id, metadata
ModelDC-->>Enforcer: immutable context
Enforcer-->>Client: return ModelDispatchContext
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes
Poem
Comment |
PR Review: Time Injection Context Enforcement (OMN-973)This PR implements runtime dispatch enforcement for time injection context models. The implementation is architecturally sound and well-tested with 75 passing tests. ✅ StrengthsExcellent ONEX Compliance:
Robust Validation Strategy:
Outstanding Documentation:
Excellent Test Coverage:
🔍 Code Quality IssuesMedium: Validation Redundancy
Low: COMPUTE Node Inconsistency
🔒 Security: No Issues Found
⚡ Performance: Optimal
🎯 ONEX Architecture: Full ComplianceAll CLAUDE.md rules satisfied:
ONEX 4-Node Architecture enforced correctly for all node kinds. 🚀 RecommendationsMust Fix: None - production-ready as-is Should Address:
Nice to Have:
✅ Final Verdict: APPROVEThis PR is well-architected, thoroughly tested, and production-ready. Excellent software engineering:
Identified issues are minor code quality improvements that can be addressed in follow-up PRs. Suggested merge path:
Excellent work on OMN-973! 🎉 |
- Apply ruff formatting to handler_consul.py, handler_http.py, and test_dispatch_context_enforcer.py - Fix race condition in test_thread_safety by adding threading.Lock for thread-safe list access and threading.Barrier for synchronized thread start
PR Review: Time Injection Context Enforcement (OMN-973)Overall Assessment: APPROVED with Minor SuggestionsThis PR implements a critical architectural invariant for ONEX - ensuring reducers remain deterministic by preventing time injection at the dispatch layer. The implementation is well-designed, thoroughly tested, and follows ONEX patterns consistently. Strengths1. Excellent Architectural Design
2. Defense in DepthThe implementation provides multiple layers of validation:
3. Outstanding Test Coverage
4. Exceptional Documentation
Code Quality ReviewType AnnotationsAll type annotations follow ONEX conventions:
Naming Conventions
Error Handling
Potential Issues1. Minor: Inconsistent Factory Usage for COMPUTE NodesLocation: dispatch_context_enforcer.py:158-165 Issue: COMPUTE nodes use direct construction instead of a factory method, while REDUCER nodes use for_reducer() factory. Recommendation: Consider adding ModelDispatchContext.for_compute() factory method for consistency. This would:
Severity: Low (nice-to-have, not blocking) 2. Minor: RUNTIME_HOST Also Uses Direct ConstructionLocation: dispatch_context_enforcer.py:181-188 Issue: Same as above - RUNTIME_HOST uses direct construction instead of a factory. Recommendation: Consider ModelDispatchContext.for_runtime_host() factory. Severity: Low (nice-to-have, not blocking) 3. Documentation: Missing for_compute() Factory NoteLocation: model_dispatch_context.py:23-26 Issue: Module docstring mentions factory methods but does not list for_compute() (because it does not exist yet). Recommendation: If you add for_compute(), update this docstring. Severity: Low (documentation consistency) Security ConsiderationsNo Security Issues Identified
Performance ConsiderationsExcellent Performance Characteristics
Test Coverage AssessmentCoverage: ExcellentUnit Tests (test_dispatch_context_enforcer.py):
Integration Tests (test_dispatch_context_integration.py):
ONEX ComplianceFully Compliant with ONEX Standards
Code StyleFormatting
Imports
Recommendations for Future Work1. Add Factory Methods for COMPUTE and RUNTIME_HOSTFor consistency and discoverability, consider adding for_compute() and for_runtime_host() factory methods to match the pattern established by for_reducer(), for_orchestrator(), and for_effect(). 2. Integration with MessageDispatchEngineEnsure the MessageDispatchEngine uses DispatchContextEnforcer.create_context_for_dispatcher() before invoking dispatchers. This would complete the integration (likely already done in another PR/ticket). Final VerdictAPPROVED - This PR is ready to merge. Summary
Minor Suggestions (Non-Blocking)
Great work on this critical architectural enforcement! Reviewed by: Claude Code (PR Review Agent) |
Add factory methods to ModelDispatchContext for consistency with existing for_reducer(), for_orchestrator(), and for_effect() patterns: - for_compute(): Creates context for COMPUTE nodes (no time injection) - for_runtime_host(): Creates context for RUNTIME_HOST nodes (with time) Update DispatchContextEnforcer to use new factory methods and add comprehensive tests (12 new tests for the factory methods). Refs: OMN-973
PR Review: Time Injection Context Enforcement at Dispatch (OMN-973)SummaryThis PR implements runtime enforcement of ONEX time injection rules through dispatch context models and an enforcer. The implementation correctly ensures reducers never receive ✅ Strengths1. Excellent Architecture & Separation of Concerns
2. Strong Type Safety (ONEX Compliant)
3. Comprehensive Test Coverage
4. Excellent Documentation
5. ONEX Architectural ComplianceCorrectly enforces time injection rules per CLAUDE.md:
6. Proper Error Handling
|
🔍 Code Quality ObservationsMinor: Duplicate Validation LogicFile: Both Recommendation: Consider having Observation: DispatchContextEnforcer is StatelessThe enforcer has no instance state - all methods could be Good: Thread Safety Explicitly DocumentedBoth 🎯 Performance ConsiderationsTime Injection OverheadEach dispatcher call creates a new Assessment: Acceptable overhead for the architectural guarantee. Time injection happens once per dispatch, and No Performance Issues Detected ✅🔒 Security ConsiderationsNo Security Issues Detected ✅
|
📋 ONEX Compliance Checklist
📊 Test Coverage AnalysisUnit Tests (
|
🎓 RecommendationsFor This PR: APPROVED - Ready to MergeThe implementation is solid, well-tested, and follows ONEX patterns correctly. No blocking issues. For Future Work (Optional Enhancements):
Final Verdict✅ APPROVE This PR successfully implements time injection enforcement with:
The code is production-ready and fulfills all acceptance criteria for OMN-973. Reviewed per: |
- Fix import sorting in handler_consul.py and handler_db.py - Fix race condition in RoutingCoverageValidator._ensure_discovery() by checking _registered_routes (last assigned) instead of _discovered_types in double-checked locking pattern - Add thread safety documentation explaining the invariant
Accept main branch's _initialized flag approach for thread safety in RoutingCoverageValidator - cleaner than field-ordering dependency.
Pull Request Review: Time Injection Context Enforcement (OMN-973)OverviewThis PR implements runtime enforcement of time injection rules for ONEX's 4-node architecture. The implementation is architecturally sound, well-tested, and follows ONEX patterns consistently. Verdict: ✅ APPROVED - Excellent implementation with minor recommendations for consideration. ✅ Strengths1. Architectural Correctness
2. Strong Type Safety
3. Excellent Test Coverage
4. Documentation Quality
5. Error Handling
🔍 Code Quality AnalysisModelDispatchContext (
|
| Rule | Status | Notes |
|---|---|---|
No Any types |
✅ Pass | All types properly specified |
Use X | None over Optional[X] |
✅ Pass | Lines 111, 132 follow PEP 604 |
| Pydantic models for data | ✅ Pass | ModelDispatchContext is proper Pydantic model |
| One model per file | ✅ Pass | model_dispatch_context.py has one model |
File naming model_*.py |
✅ Pass | Follows model_<name>.py pattern |
Error handling with OnexError |
✅ Pass | ModelOnexError used appropriately |
| Thread safety documentation | ✅ Pass | Explicitly documented in both files |
| Strong typing | ✅ Pass | All parameters and returns properly typed |
🐛 Potential Bugs
None identified. The implementation appears bug-free.
💡 Recommendations (Non-Blocking)
1. Documentation Consistency
File: model_dispatch_context.py:9-10
Add COMPUTE node to module docstring for completeness:
# Current:
- **Reducers** (pure state aggregators) must NEVER receive `now`
- **Orchestrators** and **Effects** CAN receive `now`
# Suggested:
- **Reducers** and **Compute** nodes (pure/deterministic) must NEVER receive `now`
- **Orchestrators**, **Effects**, and **Runtime Hosts** CAN receive `now`2. Consider Return Type Clarification
File: model_dispatch_context.py:178
For maximum clarity, consider -> Literal[True] to signal "always True or raises":
from typing import Literal
def validate_for_node_kind(self) -> Literal[True]:
"""..."""This is a minor style choice; current pattern is also valid.
3. Consider Timestamp Injection Point Documentation
File: dispatch_context_enforcer.py:168
Add comment clarifying when timestamp is captured:
if node_kind == EnumNodeKind.ORCHESTRATOR:
# Timestamp captured at context creation (dispatch time)
# Drift from actual handler execution is microseconds in practice
return ModelDispatchContext.for_orchestrator(
correlation_id=correlation_id,
trace_id=trace_id,
now=datetime.now(UTC), # Captured here
)📊 Impact Assessment
Positive Impact:
- ✅ Enforces critical ONEX architectural invariant (reducer determinism)
- ✅ Prevents accidental time-dependent code in reducers (event replay safety)
- ✅ Type-safe factory pattern prevents misuse at development time
- ✅ Clear error messages aid debugging when violations occur
- ✅ No breaking changes to existing code
Risk:
⚠️ Low: New validation could catch existing violations if reducers were accidentally receivingnow- Mitigation: Tests prove this works correctly; existing code should be validated
🎓 Learning Opportunities
This PR demonstrates excellent software engineering practices:
- Defense in depth: Multiple validation layers (model validator + explicit method + enforcer)
- Immutability: Frozen Pydantic models prevent state mutation bugs
- Factory pattern: Enforces invariants through API design rather than runtime checks
- Comprehensive testing: Unit + integration + replay determinism tests
- Clear documentation: Rationale and examples aid future maintainers
Final Verdict
✅ APPROVED
This PR successfully implements time injection enforcement with:
- Strong architectural correctness
- Excellent test coverage (75 tests, all passing)
- Clean, maintainable code following ONEX patterns
- Comprehensive documentation
- No security or performance concerns
The minor recommendations above are stylistic improvements, not blockers. The implementation is production-ready.
Great work on OMN-973! This is a critical piece of infrastructure for ONEX runtime correctness.
Reviewed by: Claude Code
Standards: ONEX CLAUDE.md compliance
Coverage: 75/75 tests passing ✅
- Add COMPUTE nodes and Runtime Hosts to module docstring - Use Literal[True] return type for validate_for_node_kind() - Add comment clarifying timestamp capture timing in enforcer
PR Review: Time Injection Context Enforcement (OMN-973)✅ Overall AssessmentAPPROVED - This is an excellent implementation that successfully enforces critical ONEX architectural invariants around time injection. The code is well-structured, thoroughly tested, and follows ONEX coding standards. 🎯 Strengths1. Architectural Correctness ⭐
2. Excellent Code Quality ⭐
3. Outstanding Test Coverage ⭐
4. ONEX Standards Compliance ⭐
🔍 Code Quality ObservationsModel Design (
|
- Extend Pydantic validator to block both REDUCER and COMPUTE from receiving `now` - Add validate_no_time_injection_for_compute() and validate_no_time_injection_for_deterministic_node() methods to enforcer - Add comprehensive tests for COMPUTE node time injection validation - COMPUTE nodes are pure/deterministic and must not receive time context
PR Review: Time Injection Context Enforcement [OMN-973]Overall Assessment: ✅ Excellent ImplementationThis PR demonstrates exceptional quality in implementing a critical ONEX architectural invariant - enforcing time injection rules for deterministic vs non-deterministic nodes. The implementation is well-designed, thoroughly tested, and follows ONEX best practices. Strengths🏗️ Architecture & DesignStrong Separation of Concerns
Factory Method Pattern (
Fail-Fast Validation
🧪 Test CoverageComprehensive Testing
Good Test Organization
📚 DocumentationExceptional Documentation Quality
Type Annotations
✅ ONEX ComplianceFollows ONEX Guidelines
Issues & Recommendations🔴 Critical: Potential Clock Skew in Distributed SystemsIssue: Time captured at dispatch creation vs handler execution ( # Timestamp captured at context creation (dispatch time).
# Drift from actual handler execution is microseconds in practice.
return ModelDispatchContext.for_orchestrator(
correlation_id=correlation_id,
trace_id=trace_id,
now=datetime.now(UTC), # <-- Captured at dispatch, not handler execution
)Problem: Comment claims "microseconds in practice" but this assumes:
In distributed ONEX deployments with Kafka, the time between dispatch context creation and handler execution could be seconds or minutes due to:
Recommendation:
Severity: Medium (won't cause correctness issues, but could cause subtle time-based bugs in timeout/deadline logic) 🟡 Medium: Validation Method DuplicationIssue: Three nearly identical validation methods ( validate_no_time_injection_for_reducer() # Lines 194-224
validate_no_time_injection_for_compute() # Lines 226-256
validate_no_time_injection_for_deterministic_node() # Lines 258-291Problem: Code duplication and unclear API surface. When should I call Recommendation: Consider consolidating to a single method: def validate_no_time_injection(
self,
context: ModelDispatchContext,
) -> None:
"""Validate that deterministic nodes don't have time injection.
Raises:
ModelOnexError: If REDUCER or COMPUTE node has time injection.
"""
if context.node_kind in (EnumNodeKind.REDUCER, EnumNodeKind.COMPUTE) and context.now is not None:
raise ModelOnexError(
message=f"{context.node_kind.value.upper()} nodes cannot receive time injection..."
)Or keep the specific methods but mark them as deprecated in favor of the general one. Severity: Low (doesn't affect correctness, just API clarity) 🟡 Medium: Missing RUNTIME_HOST in Validation HelpersIssue: def requires_time_injection(self, node_kind: EnumNodeKind) -> bool:
return node_kind in {
EnumNodeKind.ORCHESTRATOR,
EnumNodeKind.EFFECT,
EnumNodeKind.RUNTIME_HOST, # ✅ Included
}
def forbids_time_injection(self, node_kind: EnumNodeKind) -> bool:
return node_kind in {
EnumNodeKind.REDUCER,
EnumNodeKind.COMPUTE,
# ❌ Not exhaustive - what if new node kinds are added?
}Problem: These methods are not truly inverse of each other. If a new node kind is added to Recommendation: Make one method derive from the other: def forbids_time_injection(self, node_kind: EnumNodeKind) -> bool:
return not self.requires_time_injection(node_kind)Or explicitly handle all cases and raise for unknown node kinds. Severity: Low (unlikely to cause issues, but could mask bugs if new node kinds are added) 🟢 Minor: Inconsistent Error TypesIssue: Pydantic validator raises
Problem: Callers need to catch different exception types depending on where validation occurs. Recommendation: Document this distinction clearly:
This is actually reasonable separation - Pydantic validators should raise Severity: Very Low (current design is defensible) Performance Considerations✅ Good: Stateless EnforcerThe ✅ Good: Immutable Context
|
Extract duplicated validation logic between _validate_deterministic_node_no_time() and validate_for_node_kind() into a single private method _is_invalid_time_injection(). This addresses PR #66 review feedback about DRY violation while preserving the distinct error messages for construction-time vs validation-time contexts. Related: OMN-973
- DispatchContextEnforcer from OMN-973 - MessageTypeRegistry exports from OMN-937
Code Review: Time Injection Context Enforcement [OMN-973]SummaryThis PR implements runtime dispatch enforcement for time injection context models, ensuring that reducers and compute nodes NEVER receive ✅ Strengths1. Excellent Architectural Design
2. Strong Type Safety ✅
3. Comprehensive Testing ✅
4. Excellent Documentation 📖
🔍 Issues Found🔴 CRITICAL: Potential Time Drift IssueLocation: Problem: Time is captured when the context is created, not when the handler executes. Under high load or with async queuing, drift could be seconds or more, not microseconds as the comment claims. Recommendation: Either accept the drift and update docs to say "time at dispatch", defer time capture with a callable, or add a test measuring acceptable drift bounds. Severity: Medium-High - May cause incorrect timeout/deadline calculations under load 🟡 MEDIUM: Missing Edge Case Tests1. No test for unknown
|
- Consolidate duplicate JsonValue definitions in plugin examples to import from centralized json_types.py - Update INFRA_MAX_UNIONS threshold from 450 to 465 to accommodate legitimate unions added by OMN-937 MessageTypeRegistry - Update test expectations for new threshold The OMN-937 PR added centralized JSON type definitions that increased the union count. This fix consolidates duplicates and adjusts the threshold to reflect the new baseline after that architectural change. Fixes CI failure: Unions: FAIL - Total unions: 462, max allowed: 450
PR Review: Time Injection Context Enforcement (OMN-973)SummaryThis PR implements runtime enforcement of ONEX time injection rules, ensuring reducers and compute nodes maintain determinism by never receiving ✅ Strengths1. Excellent Architecture & Design
2. Strong ONEX Compliance
3. Comprehensive Testing
4. Documentation Excellence
5. DRY Refactoring
🔍 Code Quality ObservationsMinor Suggestions (Non-blocking)1. Validation Method RedundancyThe enforcer has three similar validation methods:
Observation: The third method ( Counter-argument: Having specific methods improves error messages and intent clarity. Current approach is defensible. 2. Error Code Consistency
When an unknown Suggestion: Consider using # Current:
raise ModelOnexError(
message=f"Unknown node_kind '{node_kind}' ...",
error_code=EnumCoreErrorCode.VALIDATION_FAILED, # Is this a validation failure or internal error?
)3. Correlation ID Generation Timing
correlation_id = envelope.correlation_id or uuid4()Observation: UUID generation happens unconditionally, even when Optimization (micro-optimization, not critical): correlation_id = envelope.correlation_id if envelope.correlation_id is not None else uuid4()However, the current approach is more readable and the performance impact is negligible. Not worth changing unless you're optimizing hot paths. 4. Timestamp Drift Comment
# Timestamp captured at context creation (dispatch time).
# Drift from actual handler execution is microseconds in practice.Observation: Great documentation! Consider adding a note about whether this drift is acceptable for the use case, or if there are scenarios where it matters. 🔒 Security & PerformanceSecurity
Performance
Thread Safety
📊 Test Coverage AssessmentUnit Tests (
|
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/omnibase_infra/validation/infra_validators.py (1)
420-422: Stale threshold reference in comment.Line 421 still references the old value of 450 for
INFRA_MAX_UNIONS, but the constant is now 465.🔎 Proposed fix
# Prerequisites for Re-enabling Strict Mode: # ------------------------------------------ # 1. Complete OMN-934 (Message Dispatch Engine) - addresses dispatch model unions -# 2. Reduce INFRA_MAX_UNIONS from 450 to <200 through targeted refactoring +# 2. Reduce INFRA_MAX_UNIONS from 465 to <200 through targeted refactoring # 3. Document remaining necessary unions in exempted_patterns
🧹 Nitpick comments (3)
src/omnibase_infra/models/dispatch/model_dispatch_context.py (1)
191-222: Consider consolidating duplicate validation logic.The
validate_for_node_kind()method duplicates the check from_is_invalid_time_injection(). Consider reusing the helper to reduce duplication:🔎 Suggested refactor
def validate_for_node_kind(self) -> Literal[True]: - if self._is_invalid_time_injection(): + if self._is_invalid_time_injection(): msg = ( f"Dispatch context validation failed: " f"{self.node_kind.value.upper()} nodes cannot receive time injection " f"(now={self.now}). {self.node_kind.value.capitalize()} nodes must be deterministic." ) raise ValueError(msg) return TrueThe current implementation correctly calls
_is_invalid_time_injection(), so this is already well-factored. The slightly different error message justifies keeping it separate.tests/integration/runtime/test_dispatch_context_integration.py (2)
280-330: Consider if these tests duplicate unit tests.The
TestDispatchContextEnforcerBasicstests forrequires_time_injectionandforbids_time_injectionappear to duplicate tests fromtests/unit/runtime/test_dispatch_context_enforcer.py(classesTestRequiresTimeInjectionandTestForbidsTimeInjection).If these tests are intended to verify the same behavior in an integration context, consider adding a comment explaining the intent. Otherwise, consider removing the duplicates to reduce test maintenance burden.
1005-1006: Consider using more specific exception type for frozen model test.The test catches
Exceptionbut Pydantic raisesValidationError(specificallypydantic_core._pydantic_core.ValidationError) when attempting to modify a frozen model. Using a more specific exception would make the test clearer:🔎 Suggested improvement
+from pydantic import ValidationError + - with pytest.raises(Exception): # ValidationError for frozen models + with pytest.raises(ValidationError): ctx.now = datetime.now(UTC) # type: ignore[misc]
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Lite
📒 Files selected for processing (11)
src/omnibase_infra/models/dispatch/__init__.py(3 hunks)src/omnibase_infra/models/dispatch/model_dispatch_context.py(1 hunks)src/omnibase_infra/plugins/examples/plugin_json_normalizer.py(1 hunks)src/omnibase_infra/plugins/examples/plugin_json_normalizer_error_handling.py(1 hunks)src/omnibase_infra/runtime/__init__.py(2 hunks)src/omnibase_infra/runtime/dispatch_context_enforcer.py(1 hunks)src/omnibase_infra/validation/infra_validators.py(4 hunks)tests/integration/runtime/test_dispatch_context_integration.py(1 hunks)tests/unit/runtime/test_dispatch_context_enforcer.py(1 hunks)tests/unit/validation/test_routing_coverage_validator.py(1 hunks)tests/unit/validation/test_validator_defaults.py(1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.py: All data structures must be proper Pydantic models - never use Any types. Use specific types instead.
Use X | None (PEP 604) union syntax for nullable types instead of Optional[X]
Use ProtocolConfigurationError for configuration validation failures, SecretResolutionError for credential resolution failures, InfraConnectionError for connection failures, InfraTimeoutError for operation timeouts, InfraAuthenticationError for auth failures, and InfraUnavailableError for resource unavailable
Use EnumMessageCategory (EVENT, COMMAND, INTENT) for message routing and topic parsing. Use EnumNodeOutputType (EVENT, COMMAND, INTENT, PROJECTION) for execution shape and handler return type validation. PROJECTION only valid for REDUCER nodes
Do not use Any types anywhere in the codebase - always use specific types. If type is not known at definition time, use object as the type parameter instead
Use duck typing through protocols instead of isinstance checks. Protocol resolution based on structural matching, not type checking
Files:
tests/unit/validation/test_routing_coverage_validator.pysrc/omnibase_infra/models/dispatch/model_dispatch_context.pysrc/omnibase_infra/models/dispatch/__init__.pytests/unit/runtime/test_dispatch_context_enforcer.pysrc/omnibase_infra/runtime/__init__.pytests/unit/validation/test_validator_defaults.pysrc/omnibase_infra/plugins/examples/plugin_json_normalizer.pysrc/omnibase_infra/runtime/dispatch_context_enforcer.pysrc/omnibase_infra/validation/infra_validators.pysrc/omnibase_infra/plugins/examples/plugin_json_normalizer_error_handling.pytests/integration/runtime/test_dispatch_context_integration.py
**/*model_*.py
📄 CodeRabbit inference engine (CLAUDE.md)
**/*model_*.py: Use model_.py file naming with Model class naming for data model files
Each Python file must contain exactly one Model* class for data structure definitions
Files:
src/omnibase_infra/models/dispatch/model_dispatch_context.py
**/*dispatch*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Use ModelEventEnvelope[object] instead of Any for generic dispatcher parameters when type is not known at definition time
Files:
src/omnibase_infra/models/dispatch/model_dispatch_context.pytests/unit/runtime/test_dispatch_context_enforcer.pysrc/omnibase_infra/runtime/dispatch_context_enforcer.pytests/integration/runtime/test_dispatch_context_integration.py
**/*infra*.py
📄 CodeRabbit inference engine (CLAUDE.md)
All infrastructure errors must use raise OnexError(...) from e pattern. Never raise or propagate errors without proper error context wrapping
Files:
src/omnibase_infra/validation/infra_validators.py
**/*error*.py
📄 CodeRabbit inference engine (CLAUDE.md)
**/*error*.py: Always include correlation_id in ModelInfraErrorContext for distributed tracing. Generate UUID4 if not present in incoming request
Never include passwords, API keys, tokens, secrets, full connection strings, PII, internal IPs, private keys, or session tokens in error messages or context. Only include service names, operation names, correlation IDs, error codes, sanitized hostnames, port numbers, retry counts, and timeout values
Files:
src/omnibase_infra/plugins/examples/plugin_json_normalizer_error_handling.py
🧠 Learnings (10)
📓 Common learnings
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-20T19:53:07.665Z
Learning: Applies to **/*dispatch*.py : Use ModelEventEnvelope[object] instead of Any for generic dispatcher parameters when type is not known at definition time
📚 Learning: 2025-12-20T19:53:07.665Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-20T19:53:07.665Z
Learning: Applies to **/*dispatch*.py : Use ModelEventEnvelope[object] instead of Any for generic dispatcher parameters when type is not known at definition time
Applied to files:
src/omnibase_infra/models/dispatch/model_dispatch_context.pysrc/omnibase_infra/models/dispatch/__init__.pytests/unit/runtime/test_dispatch_context_enforcer.pysrc/omnibase_infra/runtime/dispatch_context_enforcer.pytests/integration/runtime/test_dispatch_context_integration.py
📚 Learning: 2025-11-24T16:33:32.747Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/standards.mdc:0-0
Timestamp: 2025-11-24T16:33:32.747Z
Learning: Applies to **/*.py : Import enums from `omnibase.enums` package
Applied to files:
src/omnibase_infra/models/dispatch/__init__.py
📚 Learning: 2025-12-07T17:50:13.678Z
Learnt from: CR
Repo: OmniNode-ai/omniintelligence PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-07T17:50:13.678Z
Learning: Applies to **/nodes/**/*compute*.py : Enforce ONEX node purity by preventing compute nodes from importing network/database clients (confluent_kafka, httpx, asyncpg, etc.), accessing environment variables (os.environ, os.getenv), or performing file system operations (open(), Path.read_text(), FileHandler)
Applied to files:
src/omnibase_infra/runtime/dispatch_context_enforcer.py
📚 Learning: 2025-11-28T18:58:53.781Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/canonical_patterns.mdc:0-0
Timestamp: 2025-11-28T18:58:53.781Z
Learning: Applies to **/*.py : Use proper union type definitions and discriminated unions where appropriate
Applied to files:
src/omnibase_infra/validation/infra_validators.py
📚 Learning: 2025-11-30T21:55:10.298Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: Deviations from omnibase_core standards are only acceptable for: (1) Orchestrator/Reducer nodes (ModelService* disabled), (2) Experimental features being prototyped for upstream, (3) Performance-critical optimizations with benchmark proof, (4) Bridge-specific unique patterns. All deviations require explicit documentation and justification.
Applied to files:
src/omnibase_infra/validation/infra_validators.py
📚 Learning: 2025-11-30T21:55:10.298Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: Applies to src/omninode_bridge/codegen/**/*.py : Code generation service MUST auto-generate ONEX v2.0 compliant nodes with intelligent mixin injection and quality validation. Generate comprehensive test suites with 90%+ coverage.
Applied to files:
src/omnibase_infra/validation/infra_validators.py
📚 Learning: 2025-11-24T17:22:32.195Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/canonical_patterns.mdc:0-0
Timestamp: 2025-11-24T17:22:32.195Z
Learning: Applies to **/*.py : All error handling must use OnexError exception class with specific error codes from error enum, never raise generic Exception or ValueError
Applied to files:
src/omnibase_infra/plugins/examples/plugin_json_normalizer_error_handling.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:
src/omnibase_infra/plugins/examples/plugin_json_normalizer_error_handling.py
📚 Learning: 2025-11-24T17:24:54.193Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-24T17:24:54.193Z
Learning: Applies to **/*test*.py : Use context-based fixtures with pytest.param and conditional dependency injection (e.g., UNIT_CONTEXT vs INTEGRATION_CONTEXT) for mock and integration tests
Applied to files:
tests/integration/runtime/test_dispatch_context_integration.py
🧬 Code graph analysis (5)
src/omnibase_infra/models/dispatch/model_dispatch_context.py (3)
tests/helpers/deterministic.py (1)
now(136-147)tests/unit/runtime/test_dispatch_context_enforcer.py (1)
node_kind(64-65)tests/integration/runtime/test_dispatch_context_integration.py (1)
node_kind(131-132)
src/omnibase_infra/models/dispatch/__init__.py (1)
src/omnibase_infra/models/dispatch/model_dispatch_context.py (1)
ModelDispatchContext(69-420)
tests/unit/runtime/test_dispatch_context_enforcer.py (7)
src/omnibase_infra/enums/enum_dispatch_status.py (1)
EnumDispatchStatus(18-181)src/omnibase_infra/enums/enum_message_category.py (1)
EnumMessageCategory(34-196)src/omnibase_infra/models/dispatch/model_dispatch_context.py (7)
ModelDispatchContext(69-420)for_reducer(227-261)for_orchestrator(264-300)has_time_injection(172-189)validate_for_node_kind(191-222)for_compute(344-379)for_runtime_host(382-420)src/omnibase_infra/models/dispatch/model_dispatch_result.py (1)
ModelDispatchResult(62-378)tests/integration/runtime/test_dispatch_context_integration.py (7)
dispatcher_registry(270-272)dispatcher_id(119-120)category(123-124)node_kind(131-132)message_types(127-128)handle(134-150)handle(177-196)src/omnibase_infra/runtime/dispatcher_registry.py (1)
ProtocolMessageDispatcher(65-335)tests/helpers/deterministic.py (1)
now(136-147)
src/omnibase_infra/runtime/__init__.py (1)
src/omnibase_infra/runtime/dispatch_context_enforcer.py (1)
DispatchContextEnforcer(68-358)
tests/integration/runtime/test_dispatch_context_integration.py (5)
src/omnibase_infra/enums/enum_message_category.py (1)
EnumMessageCategory(34-196)src/omnibase_infra/models/dispatch/model_dispatch_context.py (6)
ModelDispatchContext(69-420)has_time_injection(172-189)for_reducer(227-261)for_orchestrator(264-300)for_effect(303-341)validate_for_node_kind(191-222)src/omnibase_infra/models/dispatch/model_dispatch_result.py (1)
ModelDispatchResult(62-378)src/omnibase_infra/runtime/dispatch_context_enforcer.py (4)
DispatchContextEnforcer(68-358)requires_time_injection(293-325)forbids_time_injection(327-358)create_context_for_dispatcher(109-192)tests/helpers/deterministic.py (4)
DeterministicClock(101-205)DeterministicIdGenerator(31-98)next_uuid(60-76)now(136-147)
🔇 Additional comments (29)
src/omnibase_infra/plugins/examples/plugin_json_normalizer.py (1)
12-12: LGTM: Type centralization improves consistency.Consolidating to the imported
JsonValuetype eliminates duplication and ensures consistent type definitions across the codebase.src/omnibase_infra/plugins/examples/plugin_json_normalizer_error_handling.py (1)
25-25: LGTM: Consistent type centralization.This import change mirrors the consolidation in the companion plugin, ensuring both example plugins use the same centralized type definition.
tests/unit/validation/test_routing_coverage_validator.py (1)
736-759: Well-structured thread-safety test improvements.The use of
threading.Barrierensures all threads start simultaneously, creating a proper race condition scenario. The lock properly protects shared state (resultsanderrorslists), and the parameterizednum_threadsimproves maintainability. The enhanced assertion message with{errors}aids debugging.src/omnibase_infra/models/dispatch/__init__.py (1)
94-94: Clean public API exposure for ModelDispatchContext.The import and
__all__export follow the existing patterns in this module. The docstring update on line 10 appropriately documents the new model's purpose.Also applies to: 117-117
tests/unit/validation/test_validator_defaults.py (1)
41-60: Test assertions correctly updated to match new threshold.The baseline and threshold updates (462 → 465) align with the
INFRA_MAX_UNIONSconstant ininfra_validators.py. The documentation breakdown and PR references (#61, #67) provide good traceability for the union count contributions.src/omnibase_infra/runtime/__init__.py (1)
58-58: Appropriate public API exposure for DispatchContextEnforcer.The import and export follow established patterns. The "Context enforcement" comment section clearly categorizes the new component. Based on the learnings, the enforcer correctly uses
ModelEventEnvelope[object]for generic dispatch parameters.Also applies to: 165-166
src/omnibase_infra/validation/infra_validators.py (2)
327-358: Threshold update with comprehensive documentation.The
INFRA_MAX_UNIONSupdate to 465 is well-documented with a clear breakdown of union count contributions. The PR references (#61, #67) and date stamps provide good traceability for future reviews.
713-713: Docstring correctly updated.The
max_unionsparameter documentation now reflects the updated default value of 465.src/omnibase_infra/models/dispatch/model_dispatch_context.py (3)
1-66: LGTM! Well-structured module header and imports.The module docstring thoroughly documents the ONEX time injection rules, design pattern, thread safety considerations, and provides clear examples. Imports are minimal and appropriate.
69-136: LGTM! Well-defined immutable model with proper type annotations.The model configuration with
frozen=Trueandextra="forbid"correctly enforces immutability and strict field validation. All fields use PEP 604 union syntax as per coding guidelines.
226-420: LGTM! Factory methods provide excellent compile-time enforcement.The factory method design is well thought out:
for_reducer()andfor_compute()don't accept anowparameter, preventing accidental time injection at the call sitefor_orchestrator(),for_effect(), andfor_runtime_host()requirenowas a mandatory parameter, ensuring time is always providedThis provides compile-time/type-checker enforcement of ONEX time injection rules in addition to the runtime validation.
src/omnibase_infra/runtime/dispatch_context_enforcer.py (4)
1-66: LGTM! Well-documented module with proper imports.The module docstring clearly explains the ONEX time injection rules and the enforcer's role. The use of
TYPE_CHECKINGfor theModelEventEnvelopeimport is a good practice for avoiding circular imports.The signature correctly uses
ModelEventEnvelope[object]as per the coding guidelines and retrieved learnings.
109-192: LGTM! Clean routing logic with appropriate error handling.The method correctly:
- Extracts correlation metadata with a fallback for missing
correlation_id- Routes to the appropriate factory method based on
node_kind- Documents the acceptable timestamp drift (microseconds in practice)
- Raises
ModelOnexErrorwithVALIDATION_FAILEDfor unknown node kindsThe early-return pattern keeps the code readable and avoids deep nesting.
194-291: LGTM! Explicit validation methods provide defense-in-depth.The three validation methods provide clear checkpoints:
validate_no_time_injection_for_reducer()- specific to reducersvalidate_no_time_injection_for_compute()- specific to compute nodesvalidate_no_time_injection_for_deterministic_node()- covers bothWhile there's some overlap, having explicit methods for each use case improves API clarity and allows callers to be explicit about their intent.
293-358: Helper predicates are well-designed with complete coverage. The methods use set membership for O(1) lookup and the docstrings clearly document time injection requirements for each node kind. Tests explicitly verify the symmetry invariant:forbids_time_injection()andrequires_time_injection()are inverses, and everyEnumNodeKindvalue is consistently classified.tests/unit/runtime/test_dispatch_context_enforcer.py (6)
36-73: LGTM! Well-implemented mock dispatcher.The
MockMessageDispatchercorrectly implements theProtocolMessageDispatcherprotocol with all required properties and the asynchandlemethod. The mock returns a validModelDispatchResultfor testing.
75-85: LGTM! Minimal mock envelope sufficient for testing.The
MockEnvelopeprovides just the attributes needed byDispatchContextEnforcer.create_context_for_dispatcher(), which accessesenvelope.correlation_idandenvelope.trace_id. This follows the duck typing approach per coding guidelines.
87-161: LGTM! Well-organized pytest fixtures.The fixtures provide clean setup for all test scenarios, covering each node kind and envelope configurations. The docstrings clearly describe each fixture's purpose.
467-543: LGTM! Comprehensive helper method tests.The tests cover all standard node kinds for both
requires_time_injection()andforbids_time_injection(), verifying the expected return values for each.
579-694: LGTM! Excellent acceptance criteria tests with architectural documentation.These tests serve as executable documentation of the ONEX architectural constraints. The extensive docstrings explaining why these rules exist (event sourcing replay determinism) are valuable for future maintainers.
While some tests overlap with earlier test classes, the detailed documentation justifies their inclusion as acceptance criteria verification.
1019-1072: LGTM! Architectural rationale tests provide excellent documentation.The
TestOMN973ArchitecturalRationaleclass provides executable documentation:
test_reducer_determinism_for_event_replaydemonstrates the replay scenariotest_time_injection_rules_are_symmetricverifies all node kinds are consistently classifiedThese tests help future developers understand the architectural decisions.
tests/integration/runtime/test_dispatch_context_integration.py (8)
47-59: LGTM! Test payload models are well-defined.Simple Pydantic models for test payloads. Clean and minimal.
66-86: LGTM! Clean mock envelope factory function.The
create_mock_envelopefunction creates properly configuredMagicMockinstances that satisfy the interface expected byDispatchContextEnforcer.
159-200: LGTM! Deterministic dispatcher for replay testing.The
DeterministicResultDispatchercorrectly extendsContextCapturingDispatcherto track processed events, enabling replay determinism verification. The# type: ignore[arg-type]comment on line 174 is acceptable for test utilities where kwargs typing is complex.
203-272: LGTM! Well-organized fixtures with deterministic helpers.The use of
DeterministicClockandDeterministicIdGeneratorensures reproducible tests. Each fixture has a clear purpose and docstring.
337-466: LGTM! Thorough context creation tests.The tests comprehensively verify:
- Time injection presence/absence for each node kind
- Correlation and trace ID propagation
- Fallback correlation ID generation when missing
The time bounds checking (before/after comparisons) is a good pattern for verifying time injection.
473-642: LGTM! Excellent integration tests for dispatch flow.These tests simulate realistic dispatch scenarios:
- Single dispatcher dispatch with context verification
- Mixed dispatcher fan-out verifying each gets appropriate context
- Verification of both captured context and correlation ID propagation
The async test pattern with explicit context passing demonstrates the intended usage.
649-749: LGTM! Replay determinism tests demonstrate architectural intent.These tests validate the core ONEX architectural guarantee: reducers produce identical results on replay because they don't receive time injection. The tests effectively document why time injection is forbidden for reducers.
921-948: Clever workaround for testing validation with invalid state.The test
test_validate_no_time_injection_for_reducer_raises_if_has_timeusesmodel_copy(update=...)to bypass Pydantic validation and create an invalid state. This is a valid approach for testing the enforcer's validation method independently of the model's validator.The comment on lines 942-943 correctly explains that
model_copydoesn't re-run validators, which is exactly what enables this test.
| async def handle( | ||
| self, | ||
| envelope: object, | ||
| context: ModelDispatchContext | None = None, | ||
| ) -> ModelDispatchResult: | ||
| """Handle the message and capture the context for assertions.""" | ||
| self.captured_envelope = envelope | ||
| self.captured_context = context | ||
| self.invocation_count += 1 | ||
|
|
||
| return ModelDispatchResult( | ||
| dispatch_id=uuid4(), | ||
| status=EnumDispatchStatus.SUCCESS, | ||
| topic="test.events.v1", | ||
| dispatcher_id=self._dispatcher_id, | ||
| message_type=type(envelope).__name__ if envelope else None, | ||
| ) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
fd -t f "dispatcher" src --type f -name "*.py" | head -20Repository: OmniNode-ai/omnibase_infra
Length of output: 300
🏁 Script executed:
fd dispatcher src --type f -name "*.py" | head -20Repository: OmniNode-ai/omnibase_infra
Length of output: 300
🏁 Script executed:
find src -name "*dispatcher*.py" -type fRepository: OmniNode-ai/omnibase_infra
Length of output: 250
🏁 Script executed:
rg -A 5 "class ProtocolMessageDispatcher\|async def handle" src/omnibase_infra/runtime/dispatcher_registry.pyRepository: OmniNode-ai/omnibase_infra
Length of output: 52
🏁 Script executed:
rg "ProtocolMessageDispatcher" src --type pyRepository: OmniNode-ai/omnibase_infra
Length of output: 4102
🏁 Script executed:
cat src/omnibase_infra/runtime/dispatcher_registry.py | grep -A 30 "class ProtocolMessageDispatcher"Repository: OmniNode-ai/omnibase_infra
Length of output: 1539
🏁 Script executed:
cat src/omnibase_infra/runtime/dispatcher_registry.py | grep -A 60 "class ProtocolMessageDispatcher" | tail -40Repository: OmniNode-ai/omnibase_infra
Length of output: 2027
🏁 Script executed:
cat src/omnibase_infra/runtime/dispatcher_registry.py | grep -A 100 "class ProtocolMessageDispatcher" | grep -A 10 "def handle"Repository: OmniNode-ai/omnibase_infra
Length of output: 564
🏁 Script executed:
rg -B 5 -A 10 "async def handle" src/omnibase_infra/runtime/dispatcher_registry.py | head -50Repository: OmniNode-ai/omnibase_infra
Length of output: 1890
🏁 Script executed:
cat -n tests/integration/runtime/test_dispatch_context_integration.py | sed -n '134,150p'Repository: OmniNode-ai/omnibase_infra
Length of output: 805
The handle method signature does not match ProtocolMessageDispatcher.
The protocol requires handle(self, envelope: ModelEventEnvelope[object]) -> ModelDispatchResult, but the test implementation uses envelope: object and adds an extra context parameter. The envelope parameter must be ModelEventEnvelope[object] per coding guidelines for dispatcher parameters. This signature mismatch prevents the test double from being protocol-compliant and won't accurately verify the dispatch engine's behavior.
🤖 Prompt for AI Agents
In tests/integration/runtime/test_dispatch_context_integration.py around lines
134 to 150, the test handler's signature is not protocol-compliant: change the
method to match ProtocolMessageDispatcher by defining handle(self, envelope:
ModelEventEnvelope[object]) -> ModelDispatchResult (remove the extra context
param), update captured_envelope to store the received ModelEventEnvelope, and
if you need the context for assertions extract and store envelope.context into
captured_context; ensure type annotations/imports for ModelEventEnvelope are
present.
| def test_reducer_context_with_time_raises( | ||
| self, | ||
| enforcer: DispatchContextEnforcer, | ||
| ) -> None: | ||
| """Reducer context with time injection should raise.""" | ||
| # Create invalid context by bypassing factory (simulates manual construction) | ||
| # This is a theoretical case - the model validator should catch this | ||
| # but we test the enforcer's explicit validation | ||
| ctx = ModelDispatchContext( | ||
| correlation_id=uuid4(), | ||
| node_kind=EnumNodeKind.ORCHESTRATOR, # Use different node kind to create | ||
| now=datetime.now(UTC), | ||
| ) | ||
| # Manually modify to simulate a reducer with time (bypassing Pydantic validation) | ||
| # Since the model is frozen, we create a new context directly | ||
| # This tests what happens if someone constructs an invalid context | ||
| invalid_ctx = ModelDispatchContext( | ||
| correlation_id=uuid4(), | ||
| node_kind=EnumNodeKind.REDUCER, | ||
| now=None, # Valid | ||
| ) | ||
| # The valid context should pass | ||
| enforcer.validate_no_time_injection_for_reducer(invalid_ctx) |
There was a problem hiding this comment.
Test name and implementation mismatch.
The test test_reducer_context_with_time_raises suggests it should verify that a reducer context with time injection raises an error. However, the test creates a valid reducer context with now=None and asserts it passes validation. The test name and docstring indicate testing for rejection, but the implementation tests for acceptance.
🔎 Consider renaming or restructuring this test
The test's intent seems to be demonstrating that invalid reducer contexts can't be created due to the Pydantic validator. The actual assertion (line 447) validates a valid context. Consider:
- Rename to
test_valid_reducer_context_passes_validation - Or add a comment clarifying that the Pydantic validator prevents invalid state construction
- def test_reducer_context_with_time_raises(
+ def test_reducer_context_pydantic_prevents_invalid_state(
self,
enforcer: DispatchContextEnforcer,
) -> None:
- """Reducer context with time injection should raise."""
+ """Pydantic validator prevents reducer context with time; valid context passes."""
# Create invalid context by bypassing factory (simulates manual construction)
- # This is a theoretical case - the model validator should catch this
- # but we test the enforcer's explicit validation
+ # Note: The Pydantic model validator catches this at construction time,
+ # so we can only test that valid contexts pass the enforcer's validation.🤖 Prompt for AI Agents
In tests/unit/runtime/test_dispatch_context_enforcer.py around lines 425-447,
the test named test_reducer_context_with_time_raises is inconsistent: it
documents expecting a reducer-with-time to raise but constructs a valid reducer
(now=None) and asserts it passes; either rename the test to
test_valid_reducer_context_passes_validation and update docstring to reflect
that it verifies a valid reducer context is accepted, or modify the test to
actually construct an invalid reducer context (e.g., create a reducer
ModelDispatchContext that includes a non-None now via bypassing validation) and
assert enforcer.validate_no_time_injection_for_reducer raises the expected
exception; update the test name and docstring accordingly to match the chosen
behavior.
Merge main branch which enabled strict validation mode (OMN-983). Resolution: - Keep INFRA_MAX_UNIONS = 465 (current baseline after OMN-937/OMN-973) - Adopt INFRA_PATTERNS_STRICT = True (strict mode from main) - Adopt INFRA_UNIONS_STRICT = True (strict mode from main) - Update test expectations to match Validation results: - Union count: 415 (well under 465 threshold) - All 5 validators: PASS
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Lite
📒 Files selected for processing (2)
src/omnibase_infra/validation/infra_validators.py(2 hunks)tests/unit/validation/test_validator_defaults.py(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- tests/unit/validation/test_validator_defaults.py
🧰 Additional context used
📓 Path-based instructions (2)
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.py: All data structures must be proper Pydantic models - never use Any types. Use specific types instead.
Use X | None (PEP 604) union syntax for nullable types instead of Optional[X]
Use ProtocolConfigurationError for configuration validation failures, SecretResolutionError for credential resolution failures, InfraConnectionError for connection failures, InfraTimeoutError for operation timeouts, InfraAuthenticationError for auth failures, and InfraUnavailableError for resource unavailable
Use EnumMessageCategory (EVENT, COMMAND, INTENT) for message routing and topic parsing. Use EnumNodeOutputType (EVENT, COMMAND, INTENT, PROJECTION) for execution shape and handler return type validation. PROJECTION only valid for REDUCER nodes
Do not use Any types anywhere in the codebase - always use specific types. If type is not known at definition time, use object as the type parameter instead
Use duck typing through protocols instead of isinstance checks. Protocol resolution based on structural matching, not type checking
Files:
src/omnibase_infra/validation/infra_validators.py
**/*infra*.py
📄 CodeRabbit inference engine (CLAUDE.md)
All infrastructure errors must use raise OnexError(...) from e pattern. Never raise or propagate errors without proper error context wrapping
Files:
src/omnibase_infra/validation/infra_validators.py
🔇 Additional comments (1)
src/omnibase_infra/validation/infra_validators.py (1)
636-636: LGTM!Docstring correctly updated to reflect the new
INFRA_MAX_UNIONSdefault value.
| # Current baseline (462 unions as of 2025-12-20): | ||
| # - Most unions are legitimate `X | None` nullable patterns | ||
| # - These are NOT flagged as violations, just counted | ||
| # - Actual violations (primitive soup, Union[X,None] syntax) are reported separately | ||
| # | ||
| # Threshold set to 410 - buffer above current baseline (402 after json_types.py addition). | ||
| # Threshold set to 465 - buffer above current baseline after OMN-937 and OMN-973 merges. | ||
| # Target: Reduce to <200 through dict[str, object] → JsonValue migration. | ||
| INFRA_MAX_UNIONS = 410 | ||
| INFRA_MAX_UNIONS = 465 |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify union count in infrastructure code
cd /dev/shm # Use a temp directory in case we're not in the repo
# Count union type usage in infrastructure code
echo "Counting union operators (|) in src/omnibase_infra/..."
rg -t py --count-matches '\|' src/omnibase_infra/ 2>/dev/null | \
gawk -F: '{sum += $2} END {print "Total union operators (|) found:", sum}'
# Show files with highest union usage for context
echo -e "\nTop 10 files by union count:"
rg -t py --count-matches '\|' src/omnibase_infra/ 2>/dev/null | \
sort -t: -k2 -rn | \
head -10Repository: OmniNode-ai/omnibase_infra
Length of output: 835
🏁 Script executed:
#!/bin/bash
# First check if the file exists
if [ -f "src/omnibase_infra/validation/infra_validators.py" ]; then
echo "File found. Checking lines 330-337..."
sed -n '330,337p' src/omnibase_infra/validation/infra_validators.py
echo ""
echo "Checking line 636..."
sed -n '636p' src/omnibase_infra/validation/infra_validators.py
else
echo "File not found at expected path"
find . -name "infra_validators.py" -type f 2>/dev/null | head -5
fi
echo ""
echo "=== Counting unions in src/omnibase_infra/ ==="
rg -t py --count-matches '\|' src/omnibase_infra/ 2>/dev/null | \
gawk -F: '{sum += $2} END {print "Total union operators (|) found:", sum}'
echo ""
echo "=== Top 10 files by union count ==="
rg -t py --count-matches '\|' src/omnibase_infra/ 2>/dev/null | \
sort -t: -k2 -rn | \
head -10Repository: OmniNode-ai/omnibase_infra
Length of output: 1343
🏁 Script executed:
#!/bin/bash
# Check if the file exists and show the relevant lines
echo "=== Checking file content ==="
if [ -f "src/omnibase_infra/validation/infra_validators.py" ]; then
echo "Lines 330-337:"
sed -n '330,337p' src/omnibase_infra/validation/infra_validators.py
echo ""
echo "Line 636:"
sed -n '636p' src/omnibase_infra/validation/infra_validators.py
else
echo "File not found"
fi
echo ""
echo "=== Counting union operators in src/omnibase_infra/ ==="
rg -t py --count-matches '\|' src/omnibase_infra/ 2>/dev/null | gawk -F: '{sum += $2} END {print "Total:", sum}'
echo ""
echo "=== Top files by union count ==="
rg -t py --count-matches '\|' src/omnibase_infra/ 2>/dev/null | sort -t: -k2 -rn | head -10Repository: OmniNode-ai/omnibase_infra
Length of output: 1319
🏁 Script executed:
#!/bin/bash
# Verify the union count baseline and review comment details
echo "=== Verifying INFRA_MAX_UNIONS constant and union count ==="
echo ""
# Check the actual file content
if [ -f "src/omnibase_infra/validation/infra_validators.py" ]; then
echo "File content at lines 330-337:"
sed -n '330,337p' src/omnibase_infra/validation/infra_validators.py
echo ""
echo "File content at line 636:"
sed -n '636p' src/omnibase_infra/validation/infra_validators.py
else
echo "File not found - searching for it..."
find . -name "infra_validators.py" 2>/dev/null
fi
echo ""
echo "=== Counting union operators in infrastructure code ==="
rg -t py --count-matches '\|' src/omnibase_infra/ 2>/dev/null | \
gawk -F: '{sum += $2} END {print "Total union operators found: " sum}'
echo ""
echo "=== Top 10 files by union count ==="
rg -t py --count-matches '\|' src/omnibase_infra/ 2>/dev/null | \
sort -t: -k2 -rn | head -10Repository: OmniNode-ai/omnibase_infra
Length of output: 1407
Fix the outdated baseline and address the exceeded union threshold.
The documented baseline of 462 unions is incorrect—the actual count is 657 unions, exceeding the threshold of 465 by 192 unions. The constant and documentation (lines 330-337 and 636) must be updated to reflect the current state. Additionally, either enforce the 465 limit through validation or increase the threshold explicitly if the higher count is intentional. The current disconnect between documented and actual values creates confusion about code quality expectations.
🤖 Prompt for AI Agents
In src/omnibase_infra/validation/infra_validators.py around lines 330-337 and
also update the related comment at line ~636, the annotated baseline (462
unions) and INFRA_MAX_UNIONS = 465 are stale—the actual union count is 657;
update the comment text to reflect the current measured count and change
INFRA_MAX_UNIONS to the intended threshold (either set to 657 if you want the
constant to match current state or increase it to a documented new limit), and
then add/enable enforcement: ensure the validator compares the measured union
count to INFRA_MAX_UNIONS and fails CI (raise an exception or return a non-zero
error) when exceeded, or if the higher count is intentional, add a short
rationale comment and update both places to the new threshold to avoid
confusion.
Code Review SummaryThis PR implements runtime enforcement of time injection rules for ONEX's dispatch context model. The implementation is well-designed, thoroughly tested, and architecturally sound. Below is my detailed review. ✅ Strengths1. Excellent Separation of Concerns
2. Strong Type Safety & ONEX Compliance
3. Comprehensive Test Coverage
4. Excellent Documentation
5. Defense in Depth
|
🔍 Areas for Improvement1. Missing MessageDispatchEngine Integration
|
🛡️ Security & PerformanceSecurity ✅
Performance ✅
🎯 Acceptance Criteria
🏗️ Architectural AlignmentONEX Compliance ✅
CLAUDE.md Adherence ✅
✅ Final VerdictRecommendation: APPROVE with minor suggestions This is high-quality code that:
The identified issues are minor and don't block merging. Integration with MessageDispatchEngine can be in a follow-up PR. Great work! The factory pattern with Pydantic validation provides strong guarantees for reducer determinism. Reviewed by: Claude Code (automated review) |
Summary
now(deterministic for event replay)now(time-dependent operations)Changes
New Models (
model_dispatch_context.py)ModelDispatchContext: Pydantic model with time injection validationfor_reducer(),for_orchestrator(),for_effect()New Runtime Components (
dispatch_context_enforcer.py)DispatchContextEnforcer: Creates appropriate context based on dispatcher'snode_kindrequires_time_injection(),forbids_time_injection()validate_no_time_injection_for_reducer()ONEX Architectural Rules Enforced
Test plan
DispatchContextEnforcernowvia runtime dispatchnowpoetry run pytest tests/unit/runtime/test_dispatch_context_enforcer.py tests/integration/runtime/test_dispatch_context_integration.py -v # 75 passed in 1.49sAcceptance Criteria (OMN-973)
now, orchestrators/effects donowvia runtime dispatchRelated
Summary by CodeRabbit
New Features
Improvements
✏️ Tip: You can customize this high-level summary in your review settings.