Repository navigation
refactor(runtime): add ONEXContainer injection and rename HealthServer to ServiceHealth [OMN-529] - #117
Conversation
… to services/ [OMN-529] Add ModelONEXContainer dependency injection to RuntimeHostProcess and ServiceHealth per ONEX compliance requirements. Changes: - RuntimeHostProcess: Add optional container parameter with async handler registry resolution from container - ServiceHealth: Add optional container parameter, make runtime optional, add create_from_container() async factory method - Rename HealthServer → ServiceHealth per ONEX naming conventions - Move service_health.py from runtime/ to services/ directory - Use lazy import in kernel.py to avoid circular import - Update all imports and tests The container parameter is optional for backwards compatibility - existing code continues to work unchanged.
|
Warning Rate limit exceeded@jonahgabriel has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 12 minutes and 14 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 (16)
📝 WalkthroughWalkthroughRemoves HealthServer from runtime exports, introduces ServiceHealth (moved to services) with container-aware initialization, adds container-based DI to RuntimeHostProcess (async registry resolution and degraded wiring), updates kernel bootstrap and tests to use ServiceHealth and container-aware flows. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Client
participant Kernel
participant Container as ModelONEXContainer
participant RHP as RuntimeHostProcess
participant Registry as ProtocolBindingRegistry
participant Health as ServiceHealth
Client->>Kernel: bootstrap(container)
Kernel->>Container: read container
Kernel->>RHP: construct RuntimeHostProcess(container=container, config=..., handler_registry=?)
Kernel->>Health: construct ServiceHealth(container=container, runtime=RHP, port, version)
Client->>RHP: process_envelope(envelope)
RHP->>RHP: await _get_handler_registry()
alt container has service_registry
RHP->>Container: access container.service_registry
Container-->>Registry: return ProtocolBindingRegistry
else explicit registry provided
RHP->>Registry: use provided handler_registry
else fallback
RHP->>Registry: get_handler_registry() singleton
end
RHP->>RHP: cache registry
RHP->>RHP: _populate_handlers_from_registry() (async)
RHP->>RHP: validate and handle envelope
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
Comment |
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_infra/runtime/kernel.py (1)
805-810: ServiceHealth violates mandatory dependency injection signature requirement from coding guidelines.ServiceHealth must follow the required signature:
def __init__(self, container: ModelONEXContainer)The current signature accepts optional
containerandruntimeparameters. This violates the principle that all services must depend onModelONEXContainerfor dependency resolution, with no hardcoded dependency injection patterns.Additionally, the
__init__implementation stores bothcontainerandruntimewithout any resolution logic. The container parameter is never used to resolve dependencies—it's merely stored for compliance with OMN-529 but lacks actual DI integration.Fix required:
- Change signature to
def __init__(self, container: ModelONEXContainer)- Register
RuntimeHostProcessin the container (if not already done)- Resolve
runtimefrom the container inside__init__- Remove explicit
runtimeparameter passing in kernel.py and pass only the containerThis aligns with coding guidelines requiring all services to be container-aware and eliminates the current workaround pattern of passing both dependencies explicitly.
🧹 Nitpick comments (5)
tests/unit/runtime/test_kernel.py (1)
296-296: Consider adding tests for container parameter.While the patch targets are correct, the existing tests don't verify that the
containerparameter is correctly passed to ServiceHealth or that it's used appropriately. Consider adding test cases that verify:
- Container is passed to ServiceHealth during bootstrap
- ServiceHealth uses the container for dependency resolution (if applicable)
- Backwards compatibility when container is not provided (if that's supported)
Also applies to: 738-738
src/omnibase_infra/runtime/__init__.py (1)
38-45: Clarify and manage the breaking change for ServiceHealth and default host/port exportsThe runtime package no longer re‑exports
ServiceHealth,DEFAULT_HTTP_HOST, andDEFAULT_HTTP_PORT, and the comments correctly point consumers toomnibase_infra.services.service_health. This is a public API break for any external code importing these fromomnibase_infra.runtime.Consider either:
- Adding a short deprecation period with aliases in
runtime.__init__before full removal, or- Clearly documenting this migration in release notes / changelog so downstreams can update imports proactively.
Also applies to: 99-101, 168-190
src/omnibase_infra/services/service_health.py (2)
3-30: Fix example import path in ServiceHealth module docstringThe example still shows:
from omnibase_infra.runtime.service_health import ServiceHealthbut the class now lives in
omnibase_infra.services.service_health. Updating this keeps the documentation in sync with the refactor.
125-157: Align initialization error with Onex error conventions and DI guidelines
ServiceHealth.__init__raises a bareValueErrorwhen bothcontainerandruntimeare omitted. Given the repo’s guidance to raise Onex error types for configuration issues and to useModelONEXContaineras the primary DI mechanism, it would be more consistent to:
- Use a configuration‑specific Onex error (e.g.,
ProtocolConfigurationErroror a small dedicated configuration error) rather thanValueError, and- Optionally nudge callers toward the container‑first path in the error message (e.g., suggesting
ServiceHealth.create_from_container(container)).This keeps error handling and DI patterns uniform across services.
Based on learnings, ...
src/omnibase_infra/runtime/runtime_host_process.py (1)
169-252: Container‑aware handler registry resolution in RuntimeHostProcess looks correct; consider caching singleton fallbackThe new DI flow is well‑structured:
container: ModelONEXContainer | Noneis stored and exposed via acontainerproperty._get_handler_registry()resolves in the intended order:
- Explicit
handler_registrypassed to__init__container.service_registry.resolve_service(ProtocolBindingRegistry)(with caching)- Fallback to
get_handler_registry()singleton_populate_handlers_from_registry()andvalidate_envelope(...)both now await_get_handler_registry(), so container‑based registries are honored consistently, and the caching avoids repeated container resolutions.One minor refinement: when falling back to
get_handler_registry(), you might also assign that result toself._handler_registryso subsequent calls don’t repeatedly invoke the singleton accessor and so the behavior is fully symmetric with the container path. This is small, but tightens performance and observability around which registry instance is actually in use.Based on learnings, ...
Also applies to: 400-410, 413-421, 765-799, 874-915, 998-1005
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Lite
⛔ Files ignored due to path filters (1)
poetry.lockis excluded by!**/*.lock
📒 Files selected for processing (10)
pyproject.tomlsrc/omnibase_infra/runtime/__init__.pysrc/omnibase_infra/runtime/kernel.pysrc/omnibase_infra/runtime/runtime_host_process.pysrc/omnibase_infra/services/__init__.pysrc/omnibase_infra/services/service_health.pytests/integration/runtime/test_shutdown_health_integration.pytests/unit/runtime/test_kernel.pytests/unit/runtime/test_runtime_host_process.pytests/unit/runtime/test_service_health.py
🧰 Additional context used
📓 Path-based instructions (2)
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.py: NEVER use Any type - use object for generic payloads instead
All data structures MUST be proper Pydantic models - use Model* naming convention
Use PEP 604 union syntax X | None instead of Optional[X] for nullable types
EnumMessageCategory is used for message routing with values EVENT, COMMAND, INTENT
EnumNodeOutputType is used for node validation with values EVENT, COMMAND, INTENT, PROJECTION - where PROJECTION is only valid for REDUCER nodes
Result models may override bool to enable idiomatic conditional checks - always include a Warning section in the bool docstring explaining non-standard behavior
Use ModelEventEnvelope[object] for generic dispatchers when envelope typing is needed
Use underscore-prefixed unions for Pydantic validation (e.g., _IntentUnion = ModelCommandIntent | ModelEventIntent) and protocols for type hints in function signatures
All services MUST use ModelONEXContainer for dependency injection - receive container in init method with signature def init(self, container: ModelONEXContainer)
Raise OnexError (or subclasses) only - never raise other exception types directly
For config validation errors use ProtocolConfigurationError, for connection failures use InfraConnectionError, for timeouts use InfraTimeoutError, for auth failures use InfraAuthenticationError, for unavailable services use InfraUnavailableError
Always include transport_type, operation, and correlation_id in ModelInfraErrorContext when raising infrastructure errors
Always propagate correlation ID from incoming requests, auto-generate with uuid4() if missing, and include in all error context
Use MixinAsyncCircuitBreaker for external service integrations with threshold, reset_timeout, service_name, and transport_type configuration in _init_circuit_breaker()
Node introspection using MixinNodeIntrospection exposes public method names, signatures, protocol implementations, and FSM state but not private methods, source code, configuration values, or secrets - p...
Files:
tests/integration/runtime/test_shutdown_health_integration.pysrc/omnibase_infra/services/__init__.pytests/unit/runtime/test_runtime_host_process.pytests/unit/runtime/test_kernel.pysrc/omnibase_infra/services/service_health.pysrc/omnibase_infra/runtime/runtime_host_process.pysrc/omnibase_infra/runtime/kernel.pytests/unit/runtime/test_service_health.pysrc/omnibase_infra/runtime/__init__.py
**/service_*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Service files must follow the pattern service_.py with class name Service
Files:
src/omnibase_infra/services/service_health.py
🧠 Learnings (11)
📓 Common learnings
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T21:06:11.137Z
Learning: Applies to **/*.py : All services MUST use ModelONEXContainer for dependency injection - receive container in __init__ method with signature def __init__(self, container: ModelONEXContainer)
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T16:32:55.606Z
Learning: Node services must implement dependency injection using `ModelONEXContainer` from `omnibase_core.models.container.model_onex_container`
📚 Learning: 2025-12-29T21:06:11.137Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T21:06:11.137Z
Learning: Applies to **/*.py : All services MUST use ModelONEXContainer for dependency injection - receive container in __init__ method with signature def __init__(self, container: ModelONEXContainer)
Applied to files:
tests/unit/runtime/test_runtime_host_process.pysrc/omnibase_infra/services/service_health.pysrc/omnibase_infra/runtime/runtime_host_process.pytests/unit/runtime/test_service_health.py
📚 Learning: 2025-11-29T22:07:25.230Z
Learnt from: CR
Repo: OmniNode-ai/omniintelligence PR: 0
File: migration_sources/omniarchon/CLAUDE.md:0-0
Timestamp: 2025-11-29T22:07:25.230Z
Learning: Applies to migration_sources/omniarchon/**/tests/**/*.py : All integration tests must verify correct Kafka port usage for context (9092 for Docker, 29092 for host). Test both local (qdrant, memgraph) and remote (PostgreSQL, Redpanda) database connectivity. Never assume test environment configuration.
Applied to files:
tests/unit/runtime/test_kernel.py
📚 Learning: 2025-12-29T21:06:11.137Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-29T21:06:11.137Z
Learning: Applies to **/*.py : NEVER hardcode service configurations - use contract-driven configuration and ModelONEXContainer for dependency resolution
Applied to files:
src/omnibase_infra/services/service_health.pysrc/omnibase_infra/runtime/runtime_host_process.pytests/unit/runtime/test_service_health.py
📚 Learning: 2025-11-24T16:32:55.606Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T16:32:55.606Z
Learning: Node services must implement dependency injection using `ModelONEXContainer` from `omnibase_core.models.container.model_onex_container`
Applied to files:
src/omnibase_infra/runtime/runtime_host_process.pytests/unit/runtime/test_service_health.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 **/testing/testing_scenario_harness.py : When registry resolver fails, fall back to creating registry with canonical tools (tool_collection=None) rather than setting registry to None
Applied to files:
src/omnibase_infra/runtime/runtime_host_process.py
📚 Learning: 2025-10-14T12:06:38.965Z
Learnt from: jonahgabriel
Repo: OmniNode-ai/omninode_bridge PR: 0
File: :0-0
Timestamp: 2025-10-14T12:06:38.965Z
Learning: In pyproject.toml for OmniNode Bridge: Core dependencies are pydantic ^2.11.7, fastapi ^0.115.0, uvicorn ^0.32.0, asyncpg ^0.29.0, and redis ^6.0.0 (for Redis/Valkey compatibility).
Applied to files:
pyproject.toml
📚 Learning: 2025-10-14T12:06:38.965Z
Learnt from: jonahgabriel
Repo: OmniNode-ai/omninode_bridge PR: 0
File: :0-0
Timestamp: 2025-10-14T12:06:38.965Z
Learning: In pyproject.toml for OmniNode Bridge: Dev dependencies are pytest ^8.4.0, pytest-asyncio ^0.25.0, mypy ^1.13.0, black ^24.10.0, and ruff ^0.8.0, all compatible with Python 3.12.
Applied to files:
pyproject.toml
📚 Learning: 2026-01-05T14:26:26.146Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-05T14:26:26.146Z
Learning: Applies to **/*.py : Use centralized exception constants from omnibase_core.errors.exception_groups instead of manually listing exceptions (e.g., PYDANTIC_MODEL_ERRORS, VALIDATION_ERRORS)
Applied to files:
pyproject.toml
📚 Learning: 2025-12-06T22:21:32.649Z
Learnt from: CR
Repo: OmniNode-ai/omniagent PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T22:21:32.649Z
Learning: Applies to nodes/**/*.py : Use `omnibase_infra` handlers for OmniIntelligence queries via HttpRestAdapter envelope pattern
Applied to files:
src/omnibase_infra/runtime/kernel.py
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: All ONEX nodes must conform to the canonical structure, code generation, and interface patterns established in the `node_cli` node, using it as the primary source of truth for directory structure, contract schema patterns, linked document architecture, base state patterns, shared schema references, extensibility patterns, CLI interface declarations, code generation, dependency injection, error handling, testing, and documentation
Applied to files:
src/omnibase_infra/runtime/__init__.py
🧬 Code graph analysis (2)
src/omnibase_infra/services/service_health.py (3)
src/omnibase_infra/runtime/models/model_health_check_response.py (1)
ModelHealthCheckResponse(41-164)src/omnibase_infra/utils/correlation.py (1)
generate_correlation_id(40-57)src/omnibase_infra/runtime/runtime_host_process.py (3)
container(414-420)RuntimeHostProcess(121-1720)health_check(1214-1345)
tests/unit/runtime/test_service_health.py (1)
src/omnibase_infra/services/service_health.py (7)
container(198-204)ServiceHealth(94-681)runtime(207-222)port(189-195)create_from_container(225-261)is_running(180-186)_handle_health(497-681)
🔇 Additional comments (9)
src/omnibase_infra/runtime/kernel.py (2)
390-394: LGTM - Lazy import correctly avoids circular dependency.The lazy import pattern properly avoids the circular import issue between
kernel.pyandservice_health.py. Importing at function scope rather than module scope ensures the import happens after both modules are initialized.
701-701: The container parameter is properly used for handler resolution in RuntimeHostProcess. The implementation follows a three-tier fallback pattern: first checking for pre-resolved handler registry, then attempting resolution via the container's service registry, and finally falling back to a singleton. The resolved registry is cached for subsequent calls, confirming that dependency injection is correctly implemented.tests/unit/runtime/test_kernel.py (2)
284-302: LGTM - Mock fixture correctly updated for ServiceHealth.The fixture docstring and patch target have been correctly updated to reflect the ServiceHealth rename and new module path.
668-670: Test updates correctly reflect ServiceHealth rename and relocation.All test references, patch targets, import paths, and comments have been consistently updated to reflect:
- Class rename: HealthServer → ServiceHealth
- Module relocation: runtime.health_server → services.service_health
- Import path updates for DEFAULT_HTTP_PORT
The changes are mechanical and correct.
Also applies to: 759-759, 793-793, 873-873, 907-907, 932-932, 987-987
tests/integration/runtime/test_shutdown_health_integration.py (1)
125-125: ServiceHealth correctly supports both DI patterns per OMN-529.The test instantiation follows the documented "Direct runtime injection" pattern explicitly supported by ServiceHealth. The class accepts an optional
containerparameter while maintaining backwards compatibility with directruntimeinjection, as documented in the class docstring:
- Direct runtime injection (original pattern):
server = ServiceHealth(runtime=runtime, port=8085)
- Container-based injection (ONEX-compliant):
server = ServiceHealth(container=container, runtime=runtime)
The
__init__signature validates that at least one dependency source is provided (ValueErrorif both are None), ensuring the service follows the ONEX DI contract while supporting legacy code.Likely an incorrect or invalid review comment.
src/omnibase_infra/services/__init__.py (1)
16-18: Remove the misleading circular import note - no circular dependency exists.The claim about circular imports is incorrect. ServiceHealth imports RuntimeHostProcess (verified at lines 41, 49, 252 in service_health.py), but RuntimeHostProcess does not import from services. This is a one-directional dependency, not circular. The exclusion of ServiceHealth from the package exports is not justified by a circular import concern. If discoverability is the only remaining reason to exclude it, consider exporting it instead and documenting the import location in the docstring if needed.
Likely an incorrect or invalid review comment.
pyproject.toml (1)
31-31: Remove local path dependency or provision the dependency directory—builds will fail as written.The local path
../omnibase_coredoes not exist in the repository, so the build will fail immediately when Poetry tries to resolve this dependency. This also contradicts the README, which documentsomnibase-core ^0.3.5 (PyPI)as a requirement.Either:
- Revert to the version-based dependency:
omnibase-core = "^0.6.2"(matching the inline comment)- If intentional for local monorepo development, ensure the sibling directory exists and document this requirement in README.md with setup instructions for contributors
Docker Compose files exist in the project, but they cannot account for this broken path reference.
⛔ Skipped due to learnings
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 src/omnibase/nodes/*/ : Node directory structure must follow canonical pattern: place README.md and ARCHITECTURE_DECISIONS.md at node root, organize versioned code in v1_0_0/ subdirectoryLearnt 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 src/omnibase/nodes/*/README.md : Follow canonical node directory structure with README.md, ARCHITECTURE_DECISIONS.md, protocols/, and versioned implementation directories (v1_0_0/)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 models from shared core paths using `omnibase.model.core.model_*` patternLearnt 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: Organize models under `src/omnibase_core/models/` by domain including: base, cli, common, config, core, contracts, discovery, health, infrastructure, logging, metadata, nodes, operations, results, security, service, tools, validation, and workflowsLearnt from: CR Repo: OmniNode-ai/omnibase_spi PR: 0 File: CLAUDE.md:0-0 Timestamp: 2026-01-06T17:57:00.677Z Learning: Applies to src/omnibase_spi/**/*.py : SPI MUST NOT import from omnibase_infra (no imports, even transitively)tests/unit/runtime/test_runtime_host_process.py (1)
2529-2769: Container DI tests for RuntimeHostProcess are thorough and aligned with implementationThe new
TestRuntimeHostProcessContainerInjectionsuite exercises all key behaviors:
containerproperty semantics (provided, omitted, explicitNone)- Resolution order and caching in
_get_handler_registry(explicit registry → container.service_registry → singleton fallback)- Error and
Nonecases onservice_registry- Interplay between container and config
This gives good confidence in the new DI path and backward‑compatible behavior.
tests/unit/runtime/test_service_health.py (1)
19-26: Container‑based ServiceHealth tests cover the new DI surface wellThe
TestServiceHealthContainerInjectiontests validate:
containerproperty behavior- Required dependency semantics when neither container nor runtime is supplied
- Instantiation with container only vs container+runtime
create_from_containerfactory resolution and defaults- That
_handle_healthworks when initialized via container + runtimeThis gives solid coverage of the new DI entry points and error paths. The tests look consistent with the ServiceHealth implementation.
Also applies to: 359-505
Resolve conflict in pyproject.toml by keeping published omnibase-core ^0.6.2 with OMN-1257 documentation (ServiceRegistry None handling).
PR Review: ONEX Container Injection & ServiceHealth Refactor✅ Overall AssessmentThis is a well-executed refactor that successfully introduces ONEX-compliant container injection patterns while maintaining backwards compatibility. The code quality is high with comprehensive test coverage and excellent documentation. 🎯 Strengths1. Excellent Container Integration PatternThe implementation follows ONEX container-based DI patterns correctly:
# runtime_host_process.py:876-916
async def _get_handler_registry(self) -> ProtocolBindingRegistry:
# Resolution order: pre-resolved → container → singleton
if self._handler_registry is not None:
return self._handler_registry
if self._container is not None and self._container.service_registry is not None:
try:
resolved_registry = await self._container.service_registry.resolve_service(...)
self._handler_registry = resolved_registry # Caching ✅
return resolved_registry
except Exception as e:
# Graceful fallback ✅
logger.debug("Container resolution failed, falling back to singleton", ...)
return get_handler_registry()2. Strong Test CoverageThe test suite is comprehensive (243 new lines for RuntimeHostProcess alone):
3. Proper Error Handling
4. Documentation Excellence
🔍 Code Quality Issues1.
|
| Category | Status |
|---|---|
| Code Quality | ⭐⭐⭐⭐☆ (4/5) |
| Test Coverage | ⭐⭐⭐⭐⭐ (5/5) |
| ONEX Compliance | ⭐⭐⭐⭐☆ (4/5) |
| Documentation | ⭐⭐⭐⭐⭐ (5/5) |
| Security | ⭐⭐⭐⭐⭐ (5/5) |
Overall: ⭐⭐⭐⭐☆ (4.4/5)
Recommendation: ✅ Approve with minor changes
The core implementation is solid and follows ONEX patterns well. The identified issues are straightforward to fix and don't block the overall architectural direction. Excellent work on test coverage and documentation!
Reviewed by: Claude Sonnet 4.5 (Automated ONEX Code Review)
Review Date: 2026-01-06
ONEX Compliance: v0.6.2
… [OMN-529] - Add deprecation aliases for ServiceHealth, DEFAULT_HTTP_HOST, DEFAULT_HTTP_PORT in runtime/__init__.py with __getattr__ pattern and DeprecationWarning - Fix example import path in service_health.py module docstring - Replace ValueError with ProtocolConfigurationError in ServiceHealth.__init__ - Replace RuntimeError with ProtocolConfigurationError in ServiceHealth.runtime property - Cache singleton fallback in RuntimeHostProcess._get_handler_registry for consistency - Add 3 tests verifying container parameter is passed to ServiceHealth in kernel
PR Review: Container Injection for RuntimeHostProcess & ServiceHealth [OMN-529]SummaryThis PR successfully implements ONEX-compliant container-based dependency injection for
✅ Code Quality & Best PracticesExcellent Work
CRITICAL POLICY VIOLATION
|
Address all review issues including critical, major, minor, and nitpicks: CRITICAL: - Enhanced breaking change documentation with BREAKING CHANGE section - Added clear migration examples (before/after) for deprecated imports - Improved deprecation warnings with removal timeline (v0.5.0) MAJOR: - Fixed test to expect ProtocolConfigurationError instead of ValueError - Added ModelInfraErrorContext to ServiceHealth.__init__ and runtime property - Verified broad exception handling in _handle_health is appropriate MINOR: - Enhanced ServiceHealth documentation with 3 initialization modes - Added Note/Warning sections for constructor behavior - Fixed example import paths in module docstrings - Added ServiceHealth Import Guide to services/__init__.py NITPICK: - Added 5 deprecation tests for runtime module re-exports - Added 4 container injection tests for ServiceHealth - Added 3 caching behavior tests for RuntimeHostProcess - Enhanced _get_handler_registry() docstring with caching behavior Test results: 1341 passed, 38 skipped (expected)
Pull Request Review: Container Injection & ServiceHealth Refactor (OMN-529)OverviewThis PR successfully implements ONEX-compliant container-based dependency injection for ✅ Strengths1. Excellent Container Injection ArchitectureThe container injection pattern for
# src/omnibase_infra/runtime/runtime_host_process.py:876-927
async def _get_handler_registry(self) -> ProtocolBindingRegistry:
if self._handler_registry is not None:
return self._handler_registry # Pre-resolved
if self._container is not None and self._container.service_registry is not None:
try:
resolved_registry = await self._container.service_registry.resolve_service(
ProtocolBindingRegistry
)
self._handler_registry = resolved_registry # Cache\!
return resolved_registry
except Exception:
# Fall through to singleton
singleton_registry = get_handler_registry()
self._handler_registry = singleton_registry
return singleton_registryWhy this is excellent:
2. ServiceHealth Factory PatternThe # Properly handles async service resolution in factory, not __init__
@classmethod
async def create_from_container(
cls,
container: ModelONEXContainer,
port: int | None = None,
host: str = DEFAULT_HTTP_HOST,
version: str = "unknown",
) -> ServiceHealth:
runtime = await container.service_registry.resolve_service(RuntimeHostProcess)
return cls(container=container, runtime=runtime, port=port, host=host, version=version)Why this works:
3. Deprecation Strategy is Production-GradeThe backward compatibility handling via # src/omnibase_infra/runtime/__init__.py:209-257
def __getattr__(name: str) -> object:
if name in _DEPRECATED_SYMBOLS:
warnings.warn(
f"'{name}' is deprecated in omnibase_infra.runtime and will be removed "
f"in v0.5.0. Import from '{new_module}' instead.",
DeprecationWarning,
stacklevel=2,
)
# ... lazy import and returnWhy this is production-grade:
4. Test Coverage is Outstanding
Key test scenarios covered:
🔍 Areas for Consideration1. CRITICAL POLICY VIOLATION: No Backwards Compatibility### No Backwards Compatibility
**ALL changes are breaking changes. NO backwards compatibility is maintained.**
- Breaking changes are **always** acceptable and encouraged
- Remove old patterns **immediately** - do not leave deprecated code
- **NO** backwards compatibility documentation required
- **NO** deprecation periods - old APIs are simply removedCurrent state:
Question for discussion: If policy stands (no deprecation):
If policy is evolving (allow deprecation):
2. Minor: ServiceHealth Constructor ValidationThe constructor validates # Current (line 276-280)
raise ProtocolConfigurationError(
"ServiceHealth requires either 'container' or 'runtime' to be provided. "
"Use ServiceHealth(runtime=runtime) or ServiceHealth(container=container).",
context=context,
)Suggestion: raise ProtocolConfigurationError(
"ServiceHealth requires either 'container' or 'runtime' to be provided. "
"Use ServiceHealth(runtime=runtime) for direct injection, or "
"await ServiceHealth.create_from_container(container) for ONEX-compliant initialization.",
context=context,
)This guides users toward the preferred async factory pattern. 3. Documentation Clarity: Runtime Property BehaviorThe # Add to docstring example (line 324-338)
# Example of INCORRECT usage that will raise:
server = ServiceHealth(container=container) # Only container, no runtime
server.runtime # ProtocolConfigurationError\! Runtime not resolved
# CORRECT usage:
server = await ServiceHealth.create_from_container(container)
server.runtime # Works\! Runtime resolved by factory🎯 Security & PerformanceSecurity✅ No security concerns identified
Performance✅ Excellent performance characteristics
📊 Contract CompliancePer ONEX
🚀 RecommendationStatus: APPROVE with clarification needed on backwards compatibility policy This is high-quality work that demonstrates deep understanding of ONEX patterns. The only blocker is the backwards compatibility vs. CLAUDE.md policy conflict. Action items before merge:
📝 SummaryWhat this PR does exceptionally well:
Key decision needed:
Files reviewed:
Reviewed with ONEX CLAUDE.md compliance guidelines |
…x docs PR Review Fixes: - Narrow exception handling in _get_handler_registry() from generic Exception to (RuntimeError, ValueError, KeyError, AttributeError, LookupError) to avoid masking critical errors like MemoryError - Update ServiceHealth module docstring migration examples to document both deprecated import paths (via __init__ and direct file import) - Fix test exception types to use RuntimeError instead of generic Exception to match the narrowed handler All 1298 runtime unit tests pass. [OMN-529]
PR Review: Container Injection for RuntimeHostProcess and ServiceHealth (OMN-529)SummaryThis PR successfully implements ONEX-compliant container-based dependency injection for RuntimeHostProcess and ServiceHealth, while maintaining backwards compatibility through a well-designed deprecation path. ✅ Strengths1. Excellent ONEX Compliance
2. Strong Backwards Compatibility
3. Robust Error Handling
4. Excellent Test Coverage
5. Clean Refactoring
Minor ObservationsCaching Behavior (runtime_host_process.py:876-935)
Exception Handling (runtime_host_process.py:902-907)
ONEX Compliance ChecklistPer CLAUDE.md requirements:
Final AssessmentCode Quality: 5/5 - Clean, well-structured, ONEX-compliant Approval StatusAPPROVED - This PR successfully implements ONEX-compliant container injection while maintaining backwards compatibility. The code quality is excellent, test coverage is comprehensive, and documentation is thorough. Strengths:
Minor Notes:
Great work on this refactoring! This sets a solid foundation for ONEX-compliant infrastructure services. |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (5)
src/omnibase_infra/runtime/__init__.py (1)
237-253: Inefficient lazy-loading: imports all symbols for each lookup.The
__getattr__function imports all three symbols (ServiceHealth,DEFAULT_HTTP_HOST,DEFAULT_HTTP_PORT) every time any one deprecated symbol is accessed. This is wasteful and can be simplified.♻️ Suggested optimization using importlib
def __getattr__(name: str) -> object: ... if name in _DEPRECATED_SYMBOLS: new_module = _DEPRECATED_SYMBOLS[name] warnings.warn( f"'{name}' is deprecated in omnibase_infra.runtime and will be removed " f"in v0.5.0. Import from '{new_module}' instead.", DeprecationWarning, stacklevel=2, ) - # Import from the new location - from omnibase_infra.services.service_health import ( - DEFAULT_HTTP_HOST as _DEFAULT_HTTP_HOST, - ) - from omnibase_infra.services.service_health import ( - DEFAULT_HTTP_PORT as _DEFAULT_HTTP_PORT, - ) - from omnibase_infra.services.service_health import ( - ServiceHealth as _ServiceHealth, - ) - - _symbol_map: dict[str, object] = { - "ServiceHealth": _ServiceHealth, - "DEFAULT_HTTP_HOST": _DEFAULT_HTTP_HOST, - "DEFAULT_HTTP_PORT": _DEFAULT_HTTP_PORT, - } - return _symbol_map[name] + # Import only the requested symbol from the new location + import importlib + module = importlib.import_module(new_module) + return getattr(module, name) raise AttributeError(f"module {__name__!r} has no attribute {name!r}")src/omnibase_infra/services/service_health.py (1)
387-424: Consider adding error handling for container resolution failure.The
create_from_containerfactory callscontainer.service_registry.resolve_service(RuntimeHostProcess)without explicit error handling. IfRuntimeHostProcessis not registered in the container, the raw exception from the service registry will propagate.For consistency with other container resolution patterns in this codebase (e.g.,
RuntimeHostProcess._get_handler_registry), consider wrapping this in error handling that provides context about the ServiceHealth initialization failure.♻️ Suggested error handling
@classmethod async def create_from_container( cls, container: ModelONEXContainer, port: int | None = None, host: str = DEFAULT_HTTP_HOST, version: str = "unknown", ) -> ServiceHealth: ... from omnibase_infra.runtime.runtime_host_process import RuntimeHostProcess - runtime = await container.service_registry.resolve_service(RuntimeHostProcess) + try: + runtime = await container.service_registry.resolve_service(RuntimeHostProcess) + except (RuntimeError, ValueError, KeyError, LookupError) as e: + context = ModelInfraErrorContext( + transport_type=EnumInfraTransportType.HTTP, + operation="resolve_runtime_from_container", + target_name="ServiceHealth.create_from_container", + ) + raise ProtocolConfigurationError( + f"Failed to resolve RuntimeHostProcess from container: {e}", + context=context, + ) from e return cls( container=container, runtime=runtime, port=port, host=host, version=version, )tests/unit/runtime/test_kernel.py (1)
283-303: Bootstrap ServiceHealth wiring and container injection tests look solid (with one minor brittleness)
- Updating
mock_health_serverto patchomnibase_infra.services.service_health.ServiceHealthmatches the new lazy import inkernel.bootstrapand keeps fixtures aligned with the production wiring.test_bootstrap_passes_container_to_service_healthandtest_bootstrap_passes_all_required_args_to_service_healthnicely verify that aModelONEXContainerinstance is created and forwarded, and thatruntime,port, andversionare propagated as expected frombootstrap.One small robustness concern: in
test_bootstrap_passes_all_required_args_to_service_healthyou assert that the set of kwargs passed toServiceHealthis exactly{"container", "runtime", "port", "version"}. This will break ifbootstrapever adds an optional parameter (e.g.,host) even if behavior remains correct.You could assert that the required keys are a subset instead:
Suggested tweak to reduce test brittleness
- expected_params = {"container", "runtime", "port", "version"} - actual_params = set(call_kwargs.keys()) - assert expected_params == actual_params, ( - f"Expected ServiceHealth params {expected_params}, got {actual_params}" - ) + expected_params = {"container", "runtime", "port", "version"} + actual_params = set(call_kwargs.keys()) + assert expected_params.issubset(actual_params), ( + f"Expected ServiceHealth to receive at least params {expected_params}, " + f"got {actual_params}" + )Also applies to: 587-655
tests/unit/runtime/test_service_health.py (1)
286-344: Real HTTP integration test is valuable; consider note about private attribute usage
test_real_health_endpointprovides a genuine end-to-end check of/healthand/readyusing a realServiceHealthinstance andaiohttp.ClientSession, which is great for catching regressions in routing and serialization.The only minor concern is reliance on private attributes (
server._site._server.sockets) to discover the bound port. That’s acceptable in tests but may be brittle against internal aiohttp changes. If it ever causes issues, you could instead:
- Expose the bound port via a small helper/property on
ServiceHealth, or- Derive it from
server.portwhen not using port 0.For now this is fine as a pragmatic compromise.
src/omnibase_infra/runtime/runtime_host_process.py (1)
765-873: Async handler registry resolution with container + singleton fallback is well designed (minor docstring nit)
_populate_handlers_from_registrynow awaits_get_handler_registry(), which lets you resolveProtocolBindingRegistryfrom:
- An explicit
handler_registrypassed to__init__- The container’s
service_registry.resolve_service(ProtocolBindingRegistry)- The singleton
get_handler_registry()fallback
_get_handler_registry:
- Correctly prioritizes the explicit registry, then container, then singleton.
- Caches whichever registry it resolves first, so subsequent calls are cheap and consistent.
- Narrows the caught exception types for the container resolution path (RuntimeError/ValueError/KeyError/AttributeError/LookupError), which matches the tests and avoids masking unexpected failures.
Two small polish points:
The docstring for
_populate_handlers_from_registrystill says:Registry Resolution:
- If handler_registry provided: Uses pre-resolved registry
- If no handler_registry: Falls back to singleton ...
but the implementation now also supports the container resolution path. Consider updating that block for clarity.
In the error path inside
_populate_handlers_from_registry, you construct aRuntimeHostError(infra_error) but never use it (you log onlystr(e)). Either loginfra_erroror drop the unused variable to avoid confusion.Minimal docstring touch-up (optional)
- Registry Resolution: - - If handler_registry provided: Uses pre-resolved registry - - If no handler_registry: Falls back to singleton get_handler_registry() + Registry Resolution: + - If handler_registry provided: Uses pre-resolved registry + - Else if container is provided: Resolves ProtocolBindingRegistry via + container.service_registry + - Else: Falls back to singleton get_handler_registry()Also applies to: 874-935
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Lite
📒 Files selected for processing (8)
src/omnibase_infra/runtime/__init__.pysrc/omnibase_infra/runtime/kernel.pysrc/omnibase_infra/runtime/runtime_host_process.pysrc/omnibase_infra/services/__init__.pysrc/omnibase_infra/services/service_health.pytests/unit/runtime/test_kernel.pytests/unit/runtime/test_runtime_host_process.pytests/unit/runtime/test_service_health.py
🚧 Files skipped from review as they are similar to previous changes (1)
- src/omnibase_infra/services/init.py
🧰 Additional context used
📓 Path-based instructions (2)
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.py: Use container: ModelONEXContainer for dependency injection in all services and nodes
NEVER useAnytype - useobjectfor generic payloads instead
Use PEP 604 unions: X | None instead of Optional[X] for nullable types
Enum EnumMessageCategory (EVENT, COMMAND, INTENT) is for message routing; EnumNodeOutputType (EVENT, COMMAND, INTENT, PROJECTION) is for node validation - PROJECTION only valid for REDUCER nodes
Raise OnexError(...) from e for all exception handling - NEVER raise other exception types
Error context MUST include transport_type (DATABASE, KAFKA, HTTP, CONSUL, VAULT, VALKEY), operation, and correlation_id; NEVER include passwords, API keys, PII, or connection strings
Prefix internal or sensitive methods with underscore (_) to exclude from node introspection exposure
Always propagate correlation_id from incoming requests or auto-generate with uuid4() if missing; include in all error context
Use ProtocolConfigurationError for invalid config, InfraConnectionError for connection failures, InfraTimeoutError for timeouts, InfraAuthenticationError for auth failures, InfraUnavailableError for unavailable services
Files:
src/omnibase_infra/runtime/__init__.pytests/unit/runtime/test_runtime_host_process.pysrc/omnibase_infra/runtime/runtime_host_process.pytests/unit/runtime/test_kernel.pysrc/omnibase_infra/services/service_health.pysrc/omnibase_infra/runtime/kernel.pytests/unit/runtime/test_service_health.py
**/{model,enum,protocol,service,util}_*.py
📄 CodeRabbit inference engine (CLAUDE.md)
File naming pattern: model_.py for Model, enum_.py for Enum, protocol_.py for Protocol, service_.py for Service, util_.py for utility functions
Files:
src/omnibase_infra/services/service_health.py
🧠 Learnings (9)
📓 Common learnings
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-06T21:03:04.032Z
Learning: Applies to **/*.py : Use container: ModelONEXContainer for dependency injection in all services and nodes
📚 Learning: 2025-12-06T22:21:32.649Z
Learnt from: CR
Repo: OmniNode-ai/omniagent PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T22:21:32.649Z
Learning: Applies to nodes/effect/**/*.py : Use handler envelopes from `omnibase_infra` for all I/O operations (HTTP, database, Kafka) instead of custom clients
Applied to files:
src/omnibase_infra/runtime/__init__.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: Organize models under `src/omnibase_core/models/` by domain including: base, cli, common, config, core, contracts, discovery, health, infrastructure, logging, metadata, nodes, operations, results, security, service, tools, validation, and workflows
Applied to files:
src/omnibase_infra/runtime/__init__.py
📚 Learning: 2026-01-06T21:03:04.032Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-06T21:03:04.032Z
Learning: Applies to **/*.py : Use container: ModelONEXContainer for dependency injection in all services and nodes
Applied to files:
tests/unit/runtime/test_runtime_host_process.pysrc/omnibase_infra/runtime/runtime_host_process.pysrc/omnibase_infra/services/service_health.py
📚 Learning: 2025-11-24T16:32:55.606Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T16:32:55.606Z
Learning: Node services must implement dependency injection using `ModelONEXContainer` from `omnibase_core.models.container.model_onex_container`
Applied to files:
src/omnibase_infra/runtime/runtime_host_process.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 **/testing/testing_scenario_harness.py : When registry resolver fails, fall back to creating registry with canonical tools (tool_collection=None) rather than setting registry to None
Applied to files:
src/omnibase_infra/runtime/runtime_host_process.py
📚 Learning: 2025-11-29T22:07:25.230Z
Learnt from: CR
Repo: OmniNode-ai/omniintelligence PR: 0
File: migration_sources/omniarchon/CLAUDE.md:0-0
Timestamp: 2025-11-29T22:07:25.230Z
Learning: Applies to migration_sources/omniarchon/**/tests/**/*.py : All integration tests must verify correct Kafka port usage for context (9092 for Docker, 29092 for host). Test both local (qdrant, memgraph) and remote (PostgreSQL, Redpanda) database connectivity. Never assume test environment configuration.
Applied to files:
tests/unit/runtime/test_kernel.py
📚 Learning: 2025-12-06T22:21:32.649Z
Learnt from: CR
Repo: OmniNode-ai/omniagent PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T22:21:32.649Z
Learning: Applies to nodes/**/*.py : Use `omnibase_infra` handlers for OmniIntelligence queries via HttpRestAdapter envelope pattern
Applied to files:
src/omnibase_infra/runtime/kernel.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/nodes/**/*.py : Import mixins from omnibase_core.mixins.* and use Mixin* naming pattern (e.g., MixinHealthCheck, MixinMetrics, MixinEventBus) - never use local custom mixins unless experimental and documented
Applied to files:
src/omnibase_infra/runtime/kernel.py
🧬 Code graph analysis (5)
src/omnibase_infra/runtime/__init__.py (1)
src/omnibase_infra/services/service_health.py (1)
ServiceHealth(140-844)
src/omnibase_infra/runtime/runtime_host_process.py (2)
src/omnibase_infra/runtime/handler_registry.py (3)
list_protocols(277-291)ProtocolBindingRegistry(179-389)get_handler_registry(530-552)src/omnibase_infra/runtime/envelope_validator.py (1)
validate_envelope(98-174)
tests/unit/runtime/test_kernel.py (2)
src/omnibase_infra/runtime/kernel.py (1)
bootstrap(309-1084)src/omnibase_infra/services/service_health.py (2)
runtime(336-385)start(426-563)
src/omnibase_infra/services/service_health.py (7)
src/omnibase_infra/models/errors/model_infra_error_context.py (1)
ModelInfraErrorContext(17-96)src/omnibase_infra/errors/error_infra.py (2)
ProtocolConfigurationError(154-189)RuntimeHostError(82-151)src/omnibase_infra/runtime/models/model_health_check_response.py (1)
ModelHealthCheckResponse(41-164)src/omnibase_infra/utils/correlation.py (1)
generate_correlation_id(40-57)src/omnibase_infra/runtime/runtime_host_process.py (3)
container(414-420)RuntimeHostProcess(121-1740)health_check(1234-1365)src/omnibase_infra/handlers/handler_http.py (1)
transport_type(176-198)src/omnibase_infra/enums/enum_infra_transport_type.py (1)
EnumInfraTransportType(28-52)
src/omnibase_infra/runtime/kernel.py (2)
src/omnibase_infra/services/service_health.py (3)
ServiceHealth(140-844)runtime(336-385)container(327-333)src/omnibase_infra/runtime/runtime_host_process.py (2)
RuntimeHostProcess(121-1740)container(414-420)
🔇 Additional comments (16)
src/omnibase_infra/runtime/__init__.py (1)
35-54: Well-documented deprecation with clear migration path.The module docstring and inline comments provide excellent documentation for the breaking change, including:
- Clear removal timeline (v0.5.0)
- Before/after code examples
- Explicit action required for consumers
This follows best practices for deprecation communication.
Also applies to: 178-206
src/omnibase_infra/services/service_health.py (3)
203-306: LGTM: Container injection with proper validation.The
__init__correctly implements:
- Optional container parameter following ONEX DI pattern
- Validation requiring at least one of
containerorruntime- Proper
ProtocolConfigurationErrorwithModelInfraErrorContextincludingtransport_typeandoperation- Clear documentation of the three initialization modes
Based on learnings, this follows the pattern "Use container: ModelONEXContainer for dependency injection in all services and nodes".
335-385: Defensive property with clear error context.The
runtimeproperty correctly:
- Raises
ProtocolConfigurationErrorwhen runtime is not available (not a generic exception)- Includes
ModelInfraErrorContextwithtransport_type,operation, andtarget_name- Provides actionable error message guiding users to the factory method
760-762: Implicit dependency on resolved runtime in health handler.Line 762 accesses
self.runtimewhich will raiseProtocolConfigurationErrorif the runtime was never resolved (container-only init without factory). This exception is caught by the generic handler at lines 821-844 and returns HTTP 503 with error details.This behavior is acceptable for health checks - if the service is misconfigured, it should report unhealthy. The error response includes
correlation_idfor debugging.src/omnibase_infra/runtime/kernel.py (3)
373-377: Lazy import correctly avoids circular dependency.The lazy import of
ServiceHealthandDEFAULT_HTTP_PORTinsidebootstrap()is the correct pattern to avoid circular imports. The comment at lines 95-98 accurately explains the rationale.
683-690: LGTM: Container injection follows ONEX DI pattern.The kernel correctly:
- Passes
container=containertoRuntimeHostProcess(Line 684)- Passes both
container=containerandruntime=runtimetoServiceHealth(Lines 788-790)This uses the "hybrid" initialization mode (Mode 3 from ServiceHealth docs), which is appropriate here since the kernel creates the runtime explicitly with specific configuration, then passes both to ServiceHealth for ONEX compliance.
Based on learnings: "Use container: ModelONEXContainer for dependency injection in all services and nodes".
Also applies to: 788-793
379-381: Type annotation follows PEP 604 convention.Using
ServiceHealth | Noneinstead ofOptional[ServiceHealth]as per coding guidelines.tests/unit/runtime/test_runtime_host_process.py (2)
2529-2877: Thorough coverage of container-based registry resolution and cachingThe new
TestRuntimeHostProcessContainerInjectionsuite cleanly exercises all important paths: container vs explicit registry precedence, resolution failure fallback,service_registry is Nonebehavior, and caching (both container and singleton). UsingAsyncMockto simulateresolve_serviceand the explicit notes about which exception types are caught in_get_handler_registrykeep these tests aligned with the runtime behavior and ONEX container DI expectations.
Based on learnings, this accurately validates theModelONEXContainer-driven injection contract.
2883-2905: Exporting the new test class via__all__is consistentAdding
"TestRuntimeHostProcessContainerInjection"to__all__matches the existing pattern for making test classes importable and discoverable. No issues here.tests/unit/runtime/test_kernel.py (2)
738-795: Integration-level container injection verification is appropriate
test_bootstrap_passes_container_to_service_health_integrationreuses real components (InMemoryEventBus + RuntimeHostProcess) while only mockingServiceHealthand the shutdownasyncio.Event. This is a good balance between realism and isolation and gives end-to-end assurance that the sameModelONEXContainerinstance created inbootstrapis passed through in non-mocked flows as well.
Based on learnings, this confirms container propagation through the ONEX bootstrap path.
835-1125: HTTP port validation tests correctly follow the new ServiceHealth module locationThe
TestHttpPortValidationupdates keep all port behavior assertions intact while:
- Patching
ServiceHealthfromomnibase_infra.services.service_health, matching the new canonical location.- Importing
DEFAULT_HTTP_PORTfrom the same module in the “fallback to default” scenarios, ensuring tests stay tied to the source of truth used inbootstrap.The matrix of cases (0, negative, >MAX, very large, non-numeric and edge non-numeric strings) continues to give strong coverage of the
ONEX_HTTP_PORThandling. Assertions thatServiceHealthis called with the expectedportvalue after each scenario are clear and accurate.tests/unit/runtime/test_service_health.py (3)
29-187: Initialization and lifecycle tests for ServiceHealth are well structuredThe
TestServiceHealthInitandTestServiceHealthLifecycleclasses give good coverage of:
- Default vs custom ctor arguments (port, host, version).
portproperty behavior.start()creatingApplication,AppRunner, andTCPSitewith proper mocking and verifying idempotence.stop()idempotence and port-binding failure raisingRuntimeHostError.Using
AsyncMockforsetup,start, and cleanup ensures no real network IO, and the tests align with the documentedstartbehavior inservices.service_health.
359-625: Container-based initialization and factory tests closely follow the ONEX DI patternThe
TestServiceHealthContainerInjectionblock exercises:
- All combinations of
container/runtimepresence, including the “neither provided” configuration error.- The
runtimeproperty’sProtocolConfigurationErrorbehavior when only a container is supplied (matching theruntime()docstring inservice_health.py).- The async
create_from_containerfactory, both with explicit overrides and defaults, including the failure path whereresolve_serviceraises.These tests line up well with the expected
ModelONEXContainersemantics and make the dependency graph explicit.
Based on learnings, this is a good validation of the container-first initialization contract.
627-751: Deprecation behavior tests accurately capture the migration contract
TestServiceHealthDeprecationcorrectly asserts that:
- Accessing
ServiceHealth,DEFAULT_HTTP_PORT, andDEFAULT_HTTP_HOSTviaomnibase_infra.runtimeemits a singleDeprecationWarningwith the right message and v0.5.0 removal timeline, while still returning the canonical objects/values.- Direct imports from
omnibase_infra.services.service_healthproduce no warnings.- Accessing a non-existent attribute on
omnibase_infra.runtimeraises a clearAttributeError.This gives strong guardrails around the migration from the old runtime-level exports to the new services module.
src/omnibase_infra/runtime/runtime_host_process.py (2)
169-421: Container injection into RuntimeHostProcess is clean and backwards compatible
- Adding
container: ModelONEXContainer | None = Noneand storing it asself._container(plus thecontainerproperty) cleanly introduces DI without affecting existing call sites.- The constructor docstring and debug log now surface
has_container/has_handler_registry, which will be useful for observability.- Because
from __future__ import annotationsis enabled, usingModelONEXContaineronly underTYPE_CHECKINGavoids runtime import-time coupling while keeping type hints accurate.This aligns well with the ONEX-wide guidance to use
ModelONEXContainerfor service/node dependency injection while preserving the legacy “no container” path.
Based on learnings, this is the expected DI shape.
993-1051: Envelope validation now correctly uses the async, container-aware registrySwitching
validate_envelopeto useawait self._get_handler_registry()ensures:
- Envelopes are validated against the same
ProtocolBindingRegistryinstance used to populate handlers, whether it came from DI (ModelONEXContainer) or the singleton.- Container resolution + caching semantics are reused consistently between startup and per-envelope validation.
Given the caching in
_get_handler_registry, the per-envelope overhead stays minimal. The existing error handling forEnvelopeValidationErrorandUnknownHandlerTypeErrorremains unchanged.
The lock file had omnibase-core configured with a local directory source (../omnibase_core) from development, causing CI to fail since that path doesn't exist in the CI environment. Changes: - Remove directory source reference for omnibase-core - Add proper PyPI file hashes for omnibase-core 0.6.2 - Update content hash This fixes the "Dependency install failed" errors in PR #117 CI.
Code Review - PR #117: Container Injection & ServiceHealth RefactorOverall AssessmentStatus: This PR implements container-based dependency injection for 🚨 CRITICAL ISSUE: Policy ViolationBackwards Compatibility Breaks ONEX PolicyCLAUDE.md Lines 33-43 explicitly state:
Violations Found:
Required Fix: Since ✅ Just move it. Update imports in the codebase and remove the old file entirely. Per CLAUDE.md: Downstream consumers are expected to update immediately. Version bumps may contain any breaking change without warning. Code Quality Issues1. Exception Handling Too BroadFile: except (
RuntimeError,
ValueError,
KeyError,
AttributeError,
LookupError,
) as e:Issue: Catches 5 different exception types. This is overly broad and could mask unexpected errors. Recommendation: Only catch the specific exceptions that 2. Method Changed from Sync to Async Without Clear JustificationFile: Change: # Before
def _get_handler_registry(self) -> ProtocolBindingRegistry:
# After
async def _get_handler_registry(self) -> ProtocolBindingRegistry:Issue: The method became async to support container resolution, but:
Questions:
Recommendation: Document why async is necessary, or consider restructuring to keep sync access when registry is pre-resolved. 3. Inconsistent Validation PatternFile: if container is None and runtime is None:
# Raises ProtocolConfigurationErrorIssue: The validation allows Recommendation: Either:
The current hybrid approach creates confusion and deferred errors. Positive Aspects✅ Container Integration: Proper ONEX container-based DI pattern Security Considerations✅ No security concerns identified Performance Considerations
Test Coverage Assessment✅ Excellent coverage:
Action ItemsMUST FIX (Blocking):
SHOULD FIX (High Priority):
NICE TO HAVE:
RecommendationREQUEST CHANGES - The backwards compatibility machinery violates ONEX policy and must be removed before merge. Once that's addressed and the exception handling is tightened, this will be a solid implementation of container-based DI. References:
|
…529] Fix two CI failures in PR #117: 1. ONEX Validators - ServiceHealth violations: - Add exemptions for 'Service' anti-pattern in class name - Add exemption for 6-parameter __init__ (supports dual DI modes) 2. Docker Integration Tests - service_registry is None: - Add guard checks in kernel.py before wire_infrastructure_services() - Add guard before resolve_service(ProtocolBindingRegistry) - Graceful degradation when omnibase_core 0.6.2 circular import bug causes service_registry to be None - Follows existing pattern from PostgreSQL pool creation Both fixes follow established patterns in the codebase.
Pull Request Review: Container Injection for Runtime Components [OMN-529]SummaryThis PR successfully implements ONEX-compliant container-based dependency injection for ✅ Strengths1. Excellent ONEX Compliance
2. Graceful Migration Strategy
3. Container Resolution Logic# RuntimeHostProcess._get_handler_registry() (lines 874-933)
# Excellent 3-tier resolution with caching:
1. Pre-resolved registry (constructor injection)
2. Container resolution (async, cached after first call)
3. Singleton fallback (backward compatibility)
4. Documentation Quality
5. Test Coverage
|
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In @src/omnibase_infra/runtime/kernel.py:
- Around line 488-498: The current guard that logs a warning and returns an
empty wire_summary when container.service_registry is None silently degrades DI;
replace that degraded-path with a fail-fast raise of ProtocolConfigurationError
(include correlation_id and a clear message about the missing service_registry /
circular import) instead of creating an empty wire_summary, remove the
empty-summary branch and ensure ProtocolConfigurationError is imported and
raised in the same place where the code currently checks
container.service_registry before calling wire_infrastructure_services.
- Around line 684-689: The container-based handler registry resolution currently
lacks error handling and a warning when container.service_registry is None; wrap
the await container.service_registry.resolve_service(ProtocolBindingRegistry)
call in a try/except, set handler_registry to None on failure, and use
processLogger (or the module logger) to emit a warning that the container
resolution degraded to the singleton fallback (matching the pattern used around
event bus and PG pool initialization); keep
RuntimeHostProcess._get_handler_registry() as the final fallback.
🧹 Nitpick comments (2)
src/omnibase_infra/validation/validation_exemptions.yaml (1)
498-520: Consider adding parameter count specifics and migration timeline.The ServiceHealth exemptions follow the established pattern for Service* classes, which is good. However, the init parameter exemption could be improved:
Vague parameter count: The reason states "multiple optional parameters" but doesn't specify the actual count vs. the threshold (5 parameters). Other exemptions like KafkaEventBus (line 111) explicitly state: "Threshold: 5 params, KafkaEventBus has 10+". This helps track when refactoring becomes necessary.
Migration pattern without timeline: The reasoning mentions "support migration from legacy patterns to ONEX-compliant container injection," which implies this is a temporary backwards-compatibility measure. Consider documenting:
- A follow-up ticket for deprecating the legacy initialization mode
- Expected timeline for removing the dual-mode support
- Migration guidance reference (e.g.,
docs/migrations/SERVICE_HEALTH_CONTAINER_MIGRATION.md)Based on learnings, container-based DI is the standard, so having a clear path to remove legacy patterns would align with architectural goals.
✨ Suggested enhancement
- file_pattern: 'service_health\.py' method_pattern: "Function '__init__'" violation_pattern: 'has \d+ parameters' reason: > - ServiceHealth supports dual initialization modes (direct runtime injection and container-based DI) requiring multiple optional parameters. This is intentional to support migration from legacy patterns to ONEX-compliant container injection. + ServiceHealth supports dual initialization modes (direct runtime injection and container-based DI) requiring multiple optional parameters. Threshold: 5 params, ServiceHealth has 6+. This is intentional to support migration from legacy patterns to ONEX-compliant container injection. Legacy direct injection mode is deprecated and will be removed in OMN-932. documentation: - CLAUDE.md (Container-Based Dependency Injection) + - docs/migrations/SERVICE_HEALTH_CONTAINER_MIGRATION.md (if exists) ticket: OMN-529src/omnibase_infra/runtime/kernel.py (1)
95-97: Consider resolving the circular import architecturally.The lazy import pattern works around a circular dependency between
kernel.pyandservices.service_health.py, but this indicates an architectural issue. Lazy imports make module dependencies implicit and harder to trace.Consider refactoring the module structure to eliminate the circular dependency, such as:
- Extract shared types/interfaces to a separate module
- Use protocol/interface abstractions to break the cycle
- Reorganize the dependency graph so ServiceHealth doesn't depend on kernel internals
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Lite
📒 Files selected for processing (2)
src/omnibase_infra/runtime/kernel.pysrc/omnibase_infra/validation/validation_exemptions.yaml
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.py: Use container: ModelONEXContainer for dependency injection in all services and nodes
NEVER useAnytype - useobjectfor generic payloads instead
Use PEP 604 unions: X | None instead of Optional[X] for nullable types
Enum EnumMessageCategory (EVENT, COMMAND, INTENT) is for message routing; EnumNodeOutputType (EVENT, COMMAND, INTENT, PROJECTION) is for node validation - PROJECTION only valid for REDUCER nodes
Raise OnexError(...) from e for all exception handling - NEVER raise other exception types
Error context MUST include transport_type (DATABASE, KAFKA, HTTP, CONSUL, VAULT, VALKEY), operation, and correlation_id; NEVER include passwords, API keys, PII, or connection strings
Prefix internal or sensitive methods with underscore (_) to exclude from node introspection exposure
Always propagate correlation_id from incoming requests or auto-generate with uuid4() if missing; include in all error context
Use ProtocolConfigurationError for invalid config, InfraConnectionError for connection failures, InfraTimeoutError for timeouts, InfraAuthenticationError for auth failures, InfraUnavailableError for unavailable services
Files:
src/omnibase_infra/runtime/kernel.py
🧠 Learnings (5)
📓 Common learnings
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-06T21:03:04.032Z
Learning: Applies to **/*.py : Use container: ModelONEXContainer for dependency injection in all services and nodes
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T16:32:55.606Z
Learning: Node services must implement dependency injection using `ModelONEXContainer` from `omnibase_core.models.container.model_onex_container`
📚 Learning: 2025-12-06T22:21:32.649Z
Learnt from: CR
Repo: OmniNode-ai/omniagent PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T22:21:32.649Z
Learning: Applies to nodes/**/*.py : Use `omnibase_infra` handlers for OmniIntelligence queries via HttpRestAdapter envelope pattern
Applied to files:
src/omnibase_infra/runtime/kernel.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/nodes/**/*.py : Import mixins from omnibase_core.mixins.* and use Mixin* naming pattern (e.g., MixinHealthCheck, MixinMetrics, MixinEventBus) - never use local custom mixins unless experimental and documented
Applied to files:
src/omnibase_infra/runtime/kernel.py
📚 Learning: 2026-01-06T21:03:04.032Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-06T21:03:04.032Z
Learning: Applies to **/*.py : Use container: ModelONEXContainer for dependency injection in all services and nodes
Applied to files:
src/omnibase_infra/runtime/kernel.py
📚 Learning: 2025-11-24T16:32:55.606Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T16:32:55.606Z
Learning: Node services must implement dependency injection using `ModelONEXContainer` from `omnibase_core.models.container.model_onex_container`
Applied to files:
src/omnibase_infra/runtime/kernel.py
🔇 Additional comments (3)
src/omnibase_infra/runtime/kernel.py (3)
373-377: Lazy import implementation matches the pattern described above.This lazy import successfully avoids the circular dependency at module load time. However, this is the implementation of the architectural concern already flagged in the comment at lines 95-97.
381-381: LGTM - Type annotation correctly updated.The type annotation correctly reflects the ServiceHealth class rename and uses PEP 604 union syntax (
ServiceHealth | None) as per coding guidelines.
697-697: LGTM - Container DI correctly implemented.The addition of
container=containerparameters to both RuntimeHostProcess and ServiceHealth constructors correctly implements the dependency injection pattern specified in coding guidelines and retrieved learnings.This makes dependencies explicit and enables proper container-based resolution of services and handlers throughout the runtime.
Based on coding guidelines: "Use container: ModelONEXContainer for dependency injection in all services and nodes"
Also applies to: 801-806
| if container.service_registry is None: | ||
| logger.warning( | ||
| "service_registry is None (omnibase_core circular import bug?), " | ||
| "skipping container wiring (correlation_id=%s)", | ||
| correlation_id, | ||
| ) | ||
| wire_summary: dict[str, list[str]] = { | ||
| "services": [] | ||
| } # Empty summary for degraded mode | ||
| else: | ||
| wire_summary = await wire_infrastructure_services(container) |
There was a problem hiding this comment.
Degraded mode guard masks critical DI failure.
The guard allows the system to continue with empty service wiring when container.service_registry is None, logging only a warning. This silent degradation violates the coding guideline to "Raise OnexError(...) from e for all exception handling" and creates several risks:
- Silent failure: Services expecting container-wired dependencies will fail downstream with confusing errors
- Production masking: Critical DI configuration issues are hidden behind a warning
- Inconsistent behavior: System behaves differently depending on whether the circular import bug occurs
The comment explicitly acknowledges this as working around an "omnibase_core circular import bug" rather than proper error handling.
Recommendation: Raise ProtocolConfigurationError when service_registry is None to fail fast with clear context, rather than allowing degraded operation.
🔧 Proposed fix to fail fast instead of degrading silently
- if container.service_registry is None:
- logger.warning(
- "service_registry is None (omnibase_core circular import bug?), "
- "skipping container wiring (correlation_id=%s)",
- correlation_id,
- )
- wire_summary: dict[str, list[str]] = {
- "services": []
- } # Empty summary for degraded mode
- else:
- wire_summary = await wire_infrastructure_services(container)
+ if container.service_registry is None:
+ context = ModelInfraErrorContext(
+ transport_type=EnumInfraTransportType.RUNTIME,
+ operation="wire_container",
+ correlation_id=correlation_id,
+ target_name="container.service_registry",
+ )
+ raise ProtocolConfigurationError(
+ "Container service_registry is None - dependency injection cannot proceed. "
+ "This may indicate a circular import issue in omnibase_core.",
+ context=context,
+ )
+ wire_summary = await wire_infrastructure_services(container)Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In @src/omnibase_infra/runtime/kernel.py around lines 488 - 498, The current
guard that logs a warning and returns an empty wire_summary when
container.service_registry is None silently degrades DI; replace that
degraded-path with a fail-fast raise of ProtocolConfigurationError (include
correlation_id and a clear message about the missing service_registry / circular
import) instead of creating an empty wire_summary, remove the empty-summary
branch and ensure ProtocolConfigurationError is imported and raised in the same
place where the code currently checks container.service_registry before calling
wire_infrastructure_services.
Remove backwards compatibility shims per CLAUDE.md "No BC" policy: - Remove deprecated ServiceHealth re-exports from runtime/__init__.py - Remove __getattr__ lazy deprecation mechanism - Remove migration documentation from service_health.py and services/__init__.py - Remove TestServiceHealthDeprecation test class (validated deprecated behavior) Improve error handling in kernel.py: - Add try/except around wire_infrastructure_services() with correlation_id logging - Add try/except around handler registry resolution with fallback to singleton - Move ProtocolBindingRegistry import to module level (was unnecessary lazy import) Fix documentation: - Simplify RuntimeHostProcess import path in ServiceHealth docstring example All 5143 tests pass.
PR Review: Container Injection & ServiceHealth Refactoring [OMN-529]✅ Strengths1. Excellent ONEX Compliance
2. Well-Designed Container Integration
3. Excellent Documentation
4. Robust Error Handling
5. Strong Test Coverage
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In @tests/unit/runtime/test_service_health.py:
- Around line 455-479: Add the pytest.mark.unit marker to every test function in
this file (including async tests) so they are categorized as unit tests;
specifically decorate test_create_from_container_factory (and all other test_*
functions in tests/unit/runtime/test_service_health.py) with @pytest.mark.unit
(in addition to any existing @pytest.mark.asyncio where present) to satisfy the
project requirement that all tests under tests/unit/ carry the unit marker.
🧹 Nitpick comments (2)
tests/unit/runtime/test_service_health.py (1)
314-320: Accessing internal server attributes for port discovery.The access to
server._site._server.socketsis reaching into aiohttp internals, which could break if aiohttp changes its implementation. This is acceptable for integration testing with port 0 (auto-assign), but consider adding a comment noting this is fragile.📝 Suggested comment addition
# Get actual port after binding - use type assertions for mypy + # NOTE: Accessing aiohttp internals; may need adjustment if aiohttp changes site = server._site assert site is not Nonesrc/omnibase_infra/services/service_health.py (1)
368-405: Consider adding error handling tocreate_from_container.The factory method directly calls
container.service_registry.resolve_service(RuntimeHostProcess)without wrapping exceptions. While the test verifies that exceptions propagate (which is acceptable), consider wrapping in a try/except to provide more contextual errors for debugging.📝 Optional: Wrap with contextual error
@classmethod async def create_from_container( cls, container: ModelONEXContainer, port: int | None = None, host: str = DEFAULT_HTTP_HOST, version: str = "unknown", ) -> ServiceHealth: ... from omnibase_infra.runtime.runtime_host_process import RuntimeHostProcess - runtime = await container.service_registry.resolve_service(RuntimeHostProcess) + try: + runtime = await container.service_registry.resolve_service(RuntimeHostProcess) + except Exception as e: + context = ModelInfraErrorContext( + transport_type=EnumInfraTransportType.HTTP, + operation="resolve_runtime_from_container", + target_name="RuntimeHostProcess", + ) + raise ProtocolConfigurationError( + f"Failed to resolve RuntimeHostProcess from container: {e}", + context=context, + ) from e return cls( container=container, runtime=runtime,This would provide consistent error types and context for container resolution failures, following the coding guideline to "Raise OnexError(...) from e for all exception handling."
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Lite
📒 Files selected for processing (5)
src/omnibase_infra/runtime/__init__.pysrc/omnibase_infra/runtime/kernel.pysrc/omnibase_infra/services/__init__.pysrc/omnibase_infra/services/service_health.pytests/unit/runtime/test_service_health.py
🚧 Files skipped from review as they are similar to previous changes (1)
- src/omnibase_infra/services/init.py
🧰 Additional context used
📓 Path-based instructions (2)
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.py: Use container: ModelONEXContainer for dependency injection in all services and nodes
NEVER useAnytype - useobjectfor generic payloads instead
Use PEP 604 unions: X | None instead of Optional[X] for nullable types
Enum EnumMessageCategory (EVENT, COMMAND, INTENT) is for message routing; EnumNodeOutputType (EVENT, COMMAND, INTENT, PROJECTION) is for node validation - PROJECTION only valid for REDUCER nodes
Raise OnexError(...) from e for all exception handling - NEVER raise other exception types
Error context MUST include transport_type (DATABASE, KAFKA, HTTP, CONSUL, VAULT, VALKEY), operation, and correlation_id; NEVER include passwords, API keys, PII, or connection strings
Prefix internal or sensitive methods with underscore (_) to exclude from node introspection exposure
Always propagate correlation_id from incoming requests or auto-generate with uuid4() if missing; include in all error context
Use ProtocolConfigurationError for invalid config, InfraConnectionError for connection failures, InfraTimeoutError for timeouts, InfraAuthenticationError for auth failures, InfraUnavailableError for unavailable services
Files:
src/omnibase_infra/runtime/__init__.pytests/unit/runtime/test_service_health.pysrc/omnibase_infra/services/service_health.pysrc/omnibase_infra/runtime/kernel.py
**/{model,enum,protocol,service,util}_*.py
📄 CodeRabbit inference engine (CLAUDE.md)
File naming pattern: model_.py for Model, enum_.py for Enum, protocol_.py for Protocol, service_.py for Service, util_.py for utility functions
Files:
src/omnibase_infra/services/service_health.py
🧠 Learnings (9)
📓 Common learnings
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-06T21:03:04.032Z
Learning: Applies to **/*.py : Use container: ModelONEXContainer for dependency injection in all services and nodes
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T16:32:55.606Z
Learning: Node services must implement dependency injection using `ModelONEXContainer` from `omnibase_core.models.container.model_onex_container`
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/*.py : All ONEX node implementations must follow dependency injection and protocol-first design patterns as established in the node_cli canonical reference
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: All ONEX nodes must conform to the canonical structure, code generation, and interface patterns established in the `node_cli` node, using it as the primary source of truth for directory structure, contract schema patterns, linked document architecture, base state patterns, shared schema references, extensibility patterns, CLI interface declarations, code generation, dependency injection, error handling, testing, and documentation
Applied to files:
src/omnibase_infra/runtime/__init__.py
📚 Learning: 2025-11-24T16:32:55.606Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T16:32:55.606Z
Learning: All ONEX nodes must conform to the 4-Node Architecture pattern with clear separation of concerns and unidirectional data flow (EFFECT → COMPUTE → REDUCER → ORCHESTRATOR)
Applied to files:
src/omnibase_infra/runtime/__init__.py
📚 Learning: 2026-01-06T21:03:04.032Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-06T21:03:04.032Z
Learning: Applies to **/*.py : Use container: ModelONEXContainer for dependency injection in all services and nodes
Applied to files:
src/omnibase_infra/services/service_health.pysrc/omnibase_infra/runtime/kernel.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 **/v[0-9]_[0-9]_[0-9]/{tools,registry}/**.py : Constructor-based dependency injection must be used for all tool and node classes; validate that required dependencies are not None, raising OnexError with specific error code if missing
Applied to files:
src/omnibase_infra/runtime/kernel.py
📚 Learning: 2026-01-05T14:26:26.146Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-05T14:26:26.146Z
Learning: Applies to **/*.py : Document catch-all and broad exception handlers with standardized comment markers (fallback-ok:, catch-all-ok:, cleanup-resilience-ok:, boundary-ok:, init-errors-ok:, tool-resilience-ok:)
Applied to files:
src/omnibase_infra/runtime/kernel.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 **/testing/testing_scenario_harness.py : When registry resolver fails, fall back to creating registry with canonical tools (tool_collection=None) rather than setting registry to None
Applied to files:
src/omnibase_infra/runtime/kernel.py
📚 Learning: 2025-12-06T22:21:32.649Z
Learnt from: CR
Repo: OmniNode-ai/omniagent PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T22:21:32.649Z
Learning: Applies to nodes/**/*.py : Use `omnibase_infra` handlers for OmniIntelligence queries via HttpRestAdapter envelope pattern
Applied to files:
src/omnibase_infra/runtime/kernel.py
📚 Learning: 2025-11-24T16:32:55.606Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T16:32:55.606Z
Learning: Node services must implement dependency injection using `ModelONEXContainer` from `omnibase_core.models.container.model_onex_container`
Applied to files:
src/omnibase_infra/runtime/kernel.py
🧬 Code graph analysis (3)
tests/unit/runtime/test_service_health.py (3)
src/omnibase_infra/services/service_health.py (7)
container(308-314)ServiceHealth(121-825)runtime(317-366)is_running(290-296)port(299-305)start(407-544)create_from_container(369-405)src/omnibase_infra/runtime/runtime_host_process.py (3)
container(414-420)is_running(432-438)start(550-610)src/omnibase_infra/errors/error_infra.py (2)
ProtocolConfigurationError(154-189)RuntimeHostError(82-151)
src/omnibase_infra/services/service_health.py (6)
src/omnibase_infra/models/errors/model_infra_error_context.py (1)
ModelInfraErrorContext(17-96)src/omnibase_infra/errors/error_infra.py (2)
ProtocolConfigurationError(154-189)RuntimeHostError(82-151)src/omnibase_infra/runtime/models/model_health_check_response.py (1)
ModelHealthCheckResponse(41-164)src/omnibase_infra/utils/correlation.py (1)
generate_correlation_id(40-57)src/omnibase_infra/runtime/runtime_host_process.py (2)
container(414-420)health_check(1234-1365)src/omnibase_infra/enums/enum_infra_transport_type.py (1)
EnumInfraTransportType(28-52)
src/omnibase_infra/runtime/kernel.py (3)
src/omnibase_infra/services/service_health.py (3)
runtime(317-366)ServiceHealth(121-825)container(308-314)src/omnibase_infra/runtime/handler_registry.py (1)
ProtocolBindingRegistry(179-389)src/omnibase_infra/runtime/container_wiring.py (1)
wire_infrastructure_services(196-348)
🔇 Additional comments (11)
src/omnibase_infra/runtime/__init__.py (1)
87-89: LGTM! Clean API surface update with migration guidance.The comment clearly directs users to the new import path for
ServiceHealth. This aligns with the PR's "No BC" policy for removing deprecated re-exports.tests/unit/runtime/test_service_health.py (1)
1-27: LGTM! Well-structured test file with comprehensive coverage.The imports and test organization follow best practices. The test file covers:
- Initialization scenarios (defaults, custom values, container-only, runtime-only, hybrid)
- Lifecycle management (start/stop idempotency, error handling)
- Health endpoint responses for all states
- Container-based DI factory method
- Error propagation from container resolution
src/omnibase_infra/runtime/kernel.py (3)
374-378: LGTM! Lazy import to avoid circular dependency.The lazy import of
ServiceHealthandDEFAULT_HTTP_PORTinsidebootstrap()is the correct pattern to avoid circular imports, as noted in the comment at lines 96-98.
721-728: LGTM! Container-aware RuntimeHostProcess construction.The RuntimeHostProcess now receives
container=containerandhandler_registry=handler_registry(which may be None), following the container-based DI pattern per coding guidelines.
826-831: LGTM! ServiceHealth instantiated with both container and runtime.This uses the "hybrid mode" (Mode 3) documented in ServiceHealth, providing both the container for ONEX compliance and the explicit runtime for health checks.
src/omnibase_infra/services/service_health.py (6)
3-53: LGTM! Comprehensive module docstring with clear examples.The docstring clearly documents both initialization modes (direct runtime and container-based) with executable examples. The
See Alsosection properly references the class and factory method.
121-182: LGTM! Well-documented class with three initialization modes.The class docstring thoroughly explains:
- Mode 1: Direct Runtime Injection (legacy/simple)
- Mode 2: Container-Based Injection (ONEX-compliant)
- Mode 3: Hybrid (container + explicit runtime)
The validation requirement (at least one of container or runtime) is clearly stated. Based on learnings, this follows the ONEX container injection pattern.
250-266: LGTM! Proper validation with ProtocolConfigurationError.The constructor correctly validates that at least one dependency source is provided and raises
ProtocolConfigurationErrorwith properModelInfraErrorContextincluding transport_type and operation. This follows the coding guidelines for error handling.
316-366: LGTM! Runtime property with clear error when unavailable.The property raises
ProtocolConfigurationErrorwith detailed context when runtime is None, providing clear guidance to usecreate_from_container(). The docstring thoroughly documents the failure scenarios.
741-743: LGTM! Usesself.runtimeproperty for fail-fast behavior.Using
self.runtimeinstead ofself._runtimeensures that if runtime is None, aProtocolConfigurationErroris raised with proper context rather than causing a confusingAttributeErrorlater.
828-828: LGTM! Clean public API export.The
__all__export list properly includes the renamedServiceHealthclass and the default constants.
…ding nitpicks [OMN-529] 🔴 CRITICAL: - Add @pytest.mark.unit to all 6 test classes in test_service_health.py - Remove backwards compatibility shims (DeprecationWarning) from policy_registry.py 🟠 MAJOR: - Improve kernel.py error handling with specific exception types - Add ServiceResolutionError handling separate from unexpected errors - Add error handling to ServiceHealth.create_from_container() with correlation_id - Document circular import resolution in kernel.py 🟡 MINOR: - Fix import path in ServiceHealth module docstring example - Enhance runtime property and factory method documentation - Add parameter count specifics to factory method docstring ⚪ NITPICK: - Add 10 new tests for container parameter handling - Add TestServiceHealthPrivateAttributeDocumentation class - Document private attribute access patterns in tests - Verify lazy imports are acceptable (not in hot paths) - Update comments from "backwards compat" to "graceful degradation"
…ts [OMN-529] Merged origin/main into feature branch, resolving conflict in kernel.py: - Combined robust error handling (ServiceResolutionError, RuntimeError/AttributeError) from feature branch with degraded mode fallback from main - On resolution failures, now creates new ProtocolBindingRegistry() instead of None - Maintains DEGRADED_MODE logging pattern from main branch - Preserves ProtocolConfigurationError propagation for invalid configurations
…-529] Address all remaining PR #117 review issues: CRITICAL: - Add @pytest.mark.asyncio to 9 async test methods in test_service_health.py - Remove backwards compatibility code per CLAUDE.md policy: - Delete docs/migrations/ directory (migration guides) - Remove JsonValue alias from models/types/__init__.py - Remove migration notes from docstrings - Remove validation exemptions for deprecated code MAJOR: - Improve kernel.py error handling with specific exception types - Add consistent DEGRADED_MODE logging pattern with correlation_id - Catch ServiceResolutionError, RuntimeError, AttributeError separately NITPICK: - Fix docstring import path in service_health.py - Add 5 new container parameter edge case tests All 81 tests pass (42 ServiceHealth + 39 kernel).
PR Review: Container Injection and ServiceHealth Refactor [OMN-529]SummaryThis PR adds ModelONEXContainer dependency injection support to RuntimeHostProcess and ServiceHealth, following ONEX compliance patterns. The refactor includes renaming HealthServer → ServiceHealth per naming conventions and relocating it from runtime/ to services/. Overall implementation quality is very strong with excellent test coverage and proper adherence to the "No Backwards Compatibility" policy. ✅ Strengths1. Excellent Container Integration Pattern
2. Strong Error Handling
3. Comprehensive Testing
4. Clean Breaking Change Execution
5. Documentation Quality
🟡 Minor Issues1. Private Attribute Access in Tests (Minor - Acceptable)Tests access private attributes ( # tests/unit/runtime/test_service_health.py:38
assert server._runtime is mock_runtime
assert server._port == DEFAULT_HTTP_PORTImpact: Low - this is standard practice for unit tests 2. Lazy Import in kernel.py (Minor - Already Documented)ServiceHealth import is lazy to avoid circular dependency: # src/omnibase_infra/runtime/kernel.py:392-398
def bootstrap() -> int:
from omnibase_infra.services.service_health import (
DEFAULT_HTTP_PORT,
ServiceHealth,
)Impact: None - properly documented with detailed comment explaining the circular import chain 3. Validation Exemption Specificity (Nitpick)Validation exemption for ServiceHealth uses broad parameter count pattern: # src/omnibase_infra/validation/validation_exemptions.yaml:503-505
violation_pattern: 'has \d+ parameters'
reason: >
ServiceHealth supports dual initialization modes requiring multiple optional parameters.Impact: Very low - exemption is well-documented with clear rationale 📊 Code Quality Metrics
🔒 Security Review✅ No security concerns identified
🚀 Performance Considerations✅ No performance regressions expected
📝 ONEX Compliance Checklist
✅ RecommendationAPPROVE - This PR is ready to merge. The implementation demonstrates excellent adherence to ONEX principles with strong test coverage, proper error handling, and clean execution of breaking changes. The minor issues noted are all acceptable patterns for infrastructure code. Key Achievements:
Great work maintaining code quality while executing a significant refactor! 🎉 Reviewed by: Claude Sonnet 4.5 |
Summary
container: ModelONEXContainerparameter with async handler registry resolution from containerHealthServer): Renamed and relocated fromruntime/health_server.pytoservices/service_health.pyper ONEX naming conventions; added optionalcontainerparameter andcreate_from_container()async factory methodTest plan
RuntimeHostProcesscontainer injection scenariosServiceHealth.create_from_container()factory methodServiceHealthclasspytest tests/unit/runtime/ -vto verify runtime component testspytest tests/integration/runtime/ -vto verify integration testsmypy src/omnibase_infra/runtime/ src/omnibase_infra/services/for type checkingSummary by CodeRabbit
New Features
Refactor
Documentation
Tests
✏️ Tip: You can customize this high-level summary in your review settings.