Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
79f2b8e
Revert "Revert "feat(OMN-1095): Add handler source mode feature flag …
jonahgabriel Jan 22, 2026
1206787
feat(OMN-1095): Integrate HandlerSourceResolver into RuntimeHostProcess
jonahgabriel Jan 23, 2026
380ac3f
fix(OMN-1095): Address PR review issues and CI test failures
jonahgabriel Jan 23, 2026
276adb4
refactor(OMN-1095): Address PR review feedback for handler source mode
jonahgabriel Jan 23, 2026
24f1e23
fix(OMN-1095): Enforce strict CONTRACT mode - require contract_paths
jonahgabriel Jan 23, 2026
f71e7e3
fix(OMN-1095): Address PR review feedback - improve handler source re…
jonahgabriel Jan 23, 2026
c69df64
fix(OMN-1095): Address PR review feedback - improve handler source re…
jonahgabriel Jan 23, 2026
f4dbab7
Merge remote-tracking branch 'origin/main' into jonah/omn-1095-handle…
jonahgabriel Jan 24, 2026
04a45be
fix(OMN-1095): Wire allow_bootstrap_override through config to resolver
jonahgabriel Jan 24, 2026
9c54c31
fix(OMN-1095): Address code review feedback - improve logging and docs
jonahgabriel Jan 24, 2026
e708e79
fix(OMN-1095): Address code review issues - handler ID, version, name…
jonahgabriel Jan 24, 2026
700b8a0
fix(OMN-1095): Replace assert with explicit error handling, improve docs
jonahgabriel Jan 24, 2026
350eb19
fix(OMN-1095): Neutral handler ID prefix, security tests, HYBRID docs
jonahgabriel Jan 24, 2026
0d00bfe
fix(OMN-1095): Add bool coercion validator and validation_error_count…
jonahgabriel Jan 24, 2026
0bbac14
fix(OMN-1095): Remove duplicate bool coercion in _load_handler_source…
jonahgabriel Jan 24, 2026
e397a5f
fix(OMN-1095): Improve bool coercion, document model_rebuild() pattern
jonahgabriel Jan 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/omnibase_infra/enums/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
EnumHandlerErrorType: Handler error types for validation and lifecycle
EnumHandlerLoaderError: Handler loader error codes for plugin loading
EnumResponseStatus: Handler response status (SUCCESS, ERROR)
EnumHandlerSourceMode: Handler source modes for loading strategy (BOOTSTRAP, CONTRACT, HYBRID)
EnumHandlerSourceType: Handler validation error source types
EnumHandlerType: Handler architectural roles (INFRA_HANDLER, NODE_HANDLER)
EnumHandlerTypeCategory: Behavioral classification (COMPUTE, EFFECT)
Expand Down Expand Up @@ -62,6 +63,7 @@
)
from omnibase_infra.enums.enum_handler_error_type import EnumHandlerErrorType
from omnibase_infra.enums.enum_handler_loader_error import EnumHandlerLoaderError
from omnibase_infra.enums.enum_handler_source_mode import EnumHandlerSourceMode
from omnibase_infra.enums.enum_handler_source_type import EnumHandlerSourceType
from omnibase_infra.enums.enum_handler_type import EnumHandlerType
from omnibase_infra.enums.enum_handler_type_category import EnumHandlerTypeCategory
Expand Down Expand Up @@ -102,6 +104,7 @@
"EnumExecutionShapeViolation",
"EnumHandlerErrorType",
"EnumHandlerLoaderError",
"EnumHandlerSourceMode",
"EnumHandlerSourceType",
"EnumHandlerType",
"EnumHandlerTypeCategory",
Expand Down
72 changes: 72 additions & 0 deletions src/omnibase_infra/enums/enum_handler_source_mode.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2025 OmniNode Team
"""Handler Source Mode Enumeration for Handler Loading Strategy.

Defines the canonical source modes for handler loading in the ONEX runtime.
Each mode determines where handlers are discovered and loaded from, enabling
flexible deployment configurations and migration strategies.

Handler loading can operate in three modes:
- BOOTSTRAP: Only use hardcoded bootstrap handlers.
Uses the legacy hardcoded handler registry. No YAML contract
discovery. Useful for minimal deployments or testing.
- CONTRACT: Only use YAML contract-discovered handlers.
All handlers must be defined in contract.yaml files. No
hardcoded handlers are loaded. Enables fully declarative
handler configuration.
- HYBRID: Per-handler resolution with contract precedence.
When a handler identity matches both bootstrap and contract,
the contract-defined handler wins. Bootstrap handlers serve
as fallback for handlers not defined in contracts.

The HYBRID mode supports gradual migration from hardcoded to contract-based
handlers by allowing both sources to coexist with deterministic resolution.

See Also:
- EnumHandlerSourceType: Defines validation error source types (different purpose)
- HandlerPluginLoader: Uses this enum to determine loading strategy
- ModelRuntimeConfig: Configuration model that holds the source mode setting
"""

from enum import Enum


class EnumHandlerSourceMode(str, Enum):
"""Handler source modes for handler loading strategy selection.

These represent the different strategies for discovering and loading
handlers at runtime. The mode determines whether handlers come from
hardcoded registries, YAML contracts, or a combination of both.

Attributes:
BOOTSTRAP: Only use hardcoded bootstrap handlers.
The runtime loads handlers from the legacy hardcoded registry only.
No YAML contract discovery is performed. Use cases:
- Minimal deployments without contract infrastructure
- Testing with known handler set
- Backwards compatibility during migration
- Environments where contract files are not available
CONTRACT: Only use YAML contract-discovered handlers.
All handlers must be defined in contract.yaml files. The hardcoded
bootstrap registry is ignored. Use cases:
- Fully declarative handler configuration
- Dynamic handler deployment via contracts
- Environments requiring audit trail of handler changes
- Production deployments with contract validation
HYBRID: Per-handler resolution with contract precedence.
Both bootstrap and contract sources are used. When a handler
identity (module + class) matches in both sources, the contract-
defined handler takes precedence. Bootstrap handlers serve as
fallback for handlers not defined in contracts. Use cases:
- Gradual migration from bootstrap to contract
- Core handlers in bootstrap, extensions in contracts
- Development environments with mixed configurations
- A/B testing of handler implementations
"""

BOOTSTRAP = "bootstrap"
CONTRACT = "contract"
HYBRID = "hybrid"


__all__ = ["EnumHandlerSourceMode"]
43 changes: 38 additions & 5 deletions src/omnibase_infra/models/handlers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,21 @@
Added ModelBootstrapHandlerDescriptor for OMN-1087 bootstrap handler
validation with required handler_class field.

.. versionchanged:: 0.7.0
Added ModelHandlerSourceConfig for OMN-1095 handler source mode
configuration with production hardening features.

Note:
ModelContractDiscoveryResult uses a forward reference to
ModelHandlerValidationError to avoid circular imports. The forward
reference is resolved via model_rebuild() in handler_contract_source.py
after both classes are defined. This pattern is tested in
tests/unit/runtime/test_handler_contract_source.py.
ModelContractDiscoveryResult uses a forward reference to ModelHandlerValidationError
to avoid circular imports between models.handlers and models.errors packages.
The forward reference is resolved via model_rebuild() calls in runtime modules
that import ModelHandlerValidationError (e.g., handler_contract_source.py,
handler_bootstrap_source.py, registry_contract_source.py). Each module calls
model_rebuild() after importing both the model and the forward-referenced type.
This pattern is required because:
1. models.errors imports ModelHandlerIdentifier from models.handlers
2. models.handlers cannot import from models.errors at module level (circular)
3. model_rebuild() is idempotent, so multiple calls are harmless
"""

from omnibase_infra.models.handlers.model_bootstrap_handler_descriptor import (
Expand All @@ -37,11 +46,35 @@
from omnibase_infra.models.handlers.model_handler_identifier import (
ModelHandlerIdentifier,
)
from omnibase_infra.models.handlers.model_handler_source_config import (
ModelHandlerSourceConfig,
)

__all__ = [
"LiteralHandlerKind",
"ModelBootstrapHandlerDescriptor",
"ModelContractDiscoveryResult",
"ModelHandlerDescriptor",
"ModelHandlerIdentifier",
"ModelHandlerSourceConfig",
]

# =============================================================================
# Forward Reference Resolution
# =============================================================================
# ModelContractDiscoveryResult uses TYPE_CHECKING to defer import of
# ModelHandlerValidationError to avoid circular imports:
# - models.errors imports ModelHandlerIdentifier from models.handlers
# - models.handlers cannot import ModelHandlerValidationError at module level
#
# The forward reference is resolved via model_rebuild() in runtime modules that
# import ModelHandlerValidationError (e.g., handler_contract_source.py,
# handler_bootstrap_source.py, registry_contract_source.py, handler_source_resolver.py).
# Each module calls model_rebuild() at module level after importing both the model
# and the forward-referenced type. This is safe because model_rebuild() is idempotent.
#
# Why NOT here at module level:
# - Circular import: models.handlers.__init__ -> models.errors.__init__
# -> model_handler_validation_error.py -> models.handlers (for identifier)
# - Runtime modules load after model packages, avoiding this cycle
# =============================================================================
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class ModelBootstrapHandlerDescriptor(ModelHandlerDescriptor):
All other fields maintain the same constraints as the parent class.

Attributes:
handler_id: Unique identifier for the handler (e.g., "bootstrap.consul").
handler_id: Unique identifier for the handler (e.g., "proto.consul").
name: Human-readable name for the handler.
version: Semantic version (ModelSemVer). Accepts string, dict, or ModelSemVer.
handler_kind: Handler kind (compute, effect, reducer, orchestrator).
Expand All @@ -58,7 +58,7 @@ class ModelBootstrapHandlerDescriptor(ModelHandlerDescriptor):
Create a bootstrap handler descriptor:

>>> descriptor = ModelBootstrapHandlerDescriptor(
... handler_id="bootstrap.consul",
... handler_id="proto.consul",
... name="Consul Handler",
... version="1.0.0",
... handler_kind="effect",
Expand All @@ -74,7 +74,7 @@ class ModelBootstrapHandlerDescriptor(ModelHandlerDescriptor):
>>> from pydantic import ValidationError
>>> try:
... ModelBootstrapHandlerDescriptor(
... handler_id="bootstrap.consul",
... handler_id="proto.consul",
... name="Consul Handler",
... version="1.0.0",
... handler_kind="effect",
Expand Down Expand Up @@ -144,7 +144,7 @@ def to_base_descriptor(self) -> ModelHandlerDescriptor:

Example:
>>> bootstrap_desc = ModelBootstrapHandlerDescriptor(
... handler_id="bootstrap.consul",
... handler_id="proto.consul",
... name="Consul Handler",
... version="1.0.0",
... handler_kind="effect",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,11 @@ class ModelContractDiscoveryResult(BaseModel):
)


# Rebuild model to resolve forward reference after all imports are available.
# model_rebuild() is called in omnibase_infra.runtime.handler_contract_source
# after ModelHandlerValidationError is imported. See the comment block preceding
# model_rebuild() in handler_contract_source.py (lines 52-71) for detailed explanation.
# Forward Reference Resolution:
# This model uses TYPE_CHECKING to defer import of ModelHandlerValidationError.
# model_rebuild() is called in runtime modules that import ModelHandlerValidationError
# (e.g., handler_contract_source.py, handler_bootstrap_source.py, registry_contract_source.py).
# Each module calls model_rebuild() at module level after importing both the model
# and the forward-referenced type. This is safe because model_rebuild() is idempotent.

__all__ = ["ModelContractDiscoveryResult"]
Loading