omnibase_infra 0.2.1__py3-none-any.whl → 0.2.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- omnibase_infra/__init__.py +1 -1
- omnibase_infra/adapters/adapter_onex_tool_execution.py +446 -0
- omnibase_infra/cli/commands.py +1 -1
- omnibase_infra/configs/widget_mapping.yaml +176 -0
- omnibase_infra/contracts/handlers/filesystem/handler_contract.yaml +4 -1
- omnibase_infra/contracts/handlers/mcp/handler_contract.yaml +4 -1
- omnibase_infra/errors/error_compute_registry.py +4 -1
- omnibase_infra/errors/error_event_bus_registry.py +4 -1
- omnibase_infra/errors/error_infra.py +3 -1
- omnibase_infra/errors/error_policy_registry.py +4 -1
- omnibase_infra/handlers/handler_db.py +2 -1
- omnibase_infra/handlers/handler_graph.py +10 -5
- omnibase_infra/handlers/handler_mcp.py +736 -63
- omnibase_infra/handlers/mixins/mixin_consul_kv.py +4 -3
- omnibase_infra/handlers/mixins/mixin_consul_service.py +2 -1
- omnibase_infra/handlers/service_discovery/handler_service_discovery_consul.py +301 -4
- omnibase_infra/handlers/service_discovery/models/model_service_info.py +10 -0
- omnibase_infra/mixins/mixin_async_circuit_breaker.py +3 -2
- omnibase_infra/mixins/mixin_node_introspection.py +24 -7
- omnibase_infra/mixins/mixin_retry_execution.py +1 -1
- omnibase_infra/models/handlers/__init__.py +10 -0
- omnibase_infra/models/handlers/model_bootstrap_handler_descriptor.py +162 -0
- omnibase_infra/models/handlers/model_handler_descriptor.py +15 -0
- omnibase_infra/models/mcp/__init__.py +15 -0
- omnibase_infra/models/mcp/model_mcp_contract_config.py +80 -0
- omnibase_infra/models/mcp/model_mcp_server_config.py +67 -0
- omnibase_infra/models/mcp/model_mcp_tool_definition.py +73 -0
- omnibase_infra/models/mcp/model_mcp_tool_parameter.py +35 -0
- omnibase_infra/models/registration/model_node_capabilities.py +11 -0
- omnibase_infra/nodes/architecture_validator/contract_architecture_validator.yaml +0 -5
- omnibase_infra/nodes/architecture_validator/registry/registry_infra_architecture_validator.py +17 -10
- omnibase_infra/nodes/effects/contract.yaml +0 -5
- omnibase_infra/nodes/node_registration_orchestrator/contract.yaml +7 -0
- omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_introspected.py +86 -1
- omnibase_infra/nodes/node_registration_orchestrator/introspection_event_router.py +3 -3
- omnibase_infra/nodes/node_registration_orchestrator/registry/registry_infra_node_registration_orchestrator.py +9 -8
- omnibase_infra/nodes/node_registration_orchestrator/wiring.py +14 -13
- omnibase_infra/nodes/node_registration_storage_effect/contract.yaml +0 -5
- omnibase_infra/nodes/node_registration_storage_effect/registry/registry_infra_registration_storage.py +46 -25
- omnibase_infra/nodes/node_registry_effect/contract.yaml +0 -5
- omnibase_infra/nodes/node_registry_effect/handlers/handler_partial_retry.py +2 -1
- omnibase_infra/nodes/node_service_discovery_effect/registry/registry_infra_service_discovery.py +24 -19
- omnibase_infra/plugins/examples/plugin_json_normalizer.py +2 -2
- omnibase_infra/plugins/examples/plugin_json_normalizer_error_handling.py +2 -2
- omnibase_infra/plugins/plugin_compute_base.py +16 -2
- omnibase_infra/protocols/protocol_event_projector.py +1 -1
- omnibase_infra/runtime/__init__.py +51 -1
- omnibase_infra/runtime/binding_config_resolver.py +102 -37
- omnibase_infra/runtime/constants_notification.py +75 -0
- omnibase_infra/runtime/contract_handler_discovery.py +6 -1
- omnibase_infra/runtime/handler_bootstrap_source.py +514 -0
- omnibase_infra/runtime/handler_contract_config_loader.py +603 -0
- omnibase_infra/runtime/handler_contract_source.py +289 -167
- omnibase_infra/runtime/handler_plugin_loader.py +4 -2
- omnibase_infra/runtime/mixin_semver_cache.py +25 -1
- omnibase_infra/runtime/mixins/__init__.py +7 -0
- omnibase_infra/runtime/mixins/mixin_projector_notification_publishing.py +566 -0
- omnibase_infra/runtime/mixins/mixin_projector_sql_operations.py +31 -10
- omnibase_infra/runtime/models/__init__.py +24 -0
- omnibase_infra/runtime/models/model_health_check_result.py +2 -1
- omnibase_infra/runtime/models/model_projector_notification_config.py +171 -0
- omnibase_infra/runtime/models/model_transition_notification_outbox_config.py +112 -0
- omnibase_infra/runtime/models/model_transition_notification_outbox_metrics.py +140 -0
- omnibase_infra/runtime/models/model_transition_notification_publisher_metrics.py +357 -0
- omnibase_infra/runtime/projector_plugin_loader.py +1 -1
- omnibase_infra/runtime/projector_shell.py +229 -1
- omnibase_infra/runtime/protocols/__init__.py +10 -0
- omnibase_infra/runtime/registry/registry_protocol_binding.py +3 -2
- omnibase_infra/runtime/registry_policy.py +9 -326
- omnibase_infra/runtime/secret_resolver.py +4 -2
- omnibase_infra/runtime/service_kernel.py +10 -2
- omnibase_infra/runtime/service_message_dispatch_engine.py +4 -2
- omnibase_infra/runtime/service_runtime_host_process.py +225 -15
- omnibase_infra/runtime/transition_notification_outbox.py +1190 -0
- omnibase_infra/runtime/transition_notification_publisher.py +764 -0
- omnibase_infra/runtime/util_container_wiring.py +6 -5
- omnibase_infra/runtime/util_wiring.py +5 -1
- omnibase_infra/schemas/schema_transition_notification_outbox.sql +245 -0
- omnibase_infra/services/mcp/__init__.py +31 -0
- omnibase_infra/services/mcp/mcp_server_lifecycle.py +443 -0
- omnibase_infra/services/mcp/service_mcp_tool_discovery.py +411 -0
- omnibase_infra/services/mcp/service_mcp_tool_registry.py +329 -0
- omnibase_infra/services/mcp/service_mcp_tool_sync.py +547 -0
- omnibase_infra/services/registry_api/__init__.py +40 -0
- omnibase_infra/services/registry_api/main.py +243 -0
- omnibase_infra/services/registry_api/models/__init__.py +66 -0
- omnibase_infra/services/registry_api/models/model_capability_widget_mapping.py +38 -0
- omnibase_infra/services/registry_api/models/model_pagination_info.py +48 -0
- omnibase_infra/services/registry_api/models/model_registry_discovery_response.py +73 -0
- omnibase_infra/services/registry_api/models/model_registry_health_response.py +49 -0
- omnibase_infra/services/registry_api/models/model_registry_instance_view.py +88 -0
- omnibase_infra/services/registry_api/models/model_registry_node_view.py +88 -0
- omnibase_infra/services/registry_api/models/model_registry_summary.py +60 -0
- omnibase_infra/services/registry_api/models/model_response_list_instances.py +43 -0
- omnibase_infra/services/registry_api/models/model_response_list_nodes.py +51 -0
- omnibase_infra/services/registry_api/models/model_warning.py +49 -0
- omnibase_infra/services/registry_api/models/model_widget_defaults.py +28 -0
- omnibase_infra/services/registry_api/models/model_widget_mapping.py +51 -0
- omnibase_infra/services/registry_api/routes.py +371 -0
- omnibase_infra/services/registry_api/service.py +846 -0
- omnibase_infra/services/service_capability_query.py +4 -4
- omnibase_infra/services/service_health.py +3 -2
- omnibase_infra/services/service_timeout_emitter.py +13 -2
- omnibase_infra/utils/util_dsn_validation.py +1 -1
- omnibase_infra/validation/__init__.py +3 -19
- omnibase_infra/validation/contracts/security.validation.yaml +114 -0
- omnibase_infra/validation/infra_validators.py +35 -24
- omnibase_infra/validation/validation_exemptions.yaml +113 -9
- omnibase_infra/validation/validator_chain_propagation.py +2 -2
- omnibase_infra/validation/validator_runtime_shape.py +1 -1
- omnibase_infra/validation/validator_security.py +473 -370
- {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.2.dist-info}/METADATA +2 -2
- {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.2.dist-info}/RECORD +116 -74
- {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.2.dist-info}/WHEEL +0 -0
- {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.2.dist-info}/entry_points.txt +0 -0
- {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -43,6 +43,7 @@ Integration with Handlers:
|
|
|
43
43
|
from __future__ import annotations
|
|
44
44
|
|
|
45
45
|
import asyncio
|
|
46
|
+
import importlib
|
|
46
47
|
import json
|
|
47
48
|
import logging
|
|
48
49
|
from collections.abc import Awaitable, Callable
|
|
@@ -79,6 +80,7 @@ if TYPE_CHECKING:
|
|
|
79
80
|
from omnibase_infra.idempotency.protocol_idempotency_store import (
|
|
80
81
|
ProtocolIdempotencyStore,
|
|
81
82
|
)
|
|
83
|
+
from omnibase_infra.models.handlers import ModelHandlerDescriptor
|
|
82
84
|
from omnibase_infra.nodes.architecture_validator import ProtocolArchitectureRule
|
|
83
85
|
from omnibase_infra.runtime.contract_handler_discovery import (
|
|
84
86
|
ContractHandlerDiscovery,
|
|
@@ -244,10 +246,13 @@ class RuntimeHostProcess:
|
|
|
244
246
|
the container and pass it to RuntimeHostProcess:
|
|
245
247
|
|
|
246
248
|
```python
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
249
|
+
async def create_runtime() -> RuntimeHostProcess:
|
|
250
|
+
container = ModelONEXContainer()
|
|
251
|
+
await wire_infrastructure_services(container)
|
|
252
|
+
registry = await container.service_registry.resolve_service(
|
|
253
|
+
RegistryProtocolBinding
|
|
254
|
+
)
|
|
255
|
+
return RuntimeHostProcess(handler_registry=registry)
|
|
251
256
|
```
|
|
252
257
|
|
|
253
258
|
This follows ONEX container-based DI patterns for better testability
|
|
@@ -475,6 +480,11 @@ class RuntimeHostProcess:
|
|
|
475
480
|
# Used by health_check() to report degraded state
|
|
476
481
|
self._failed_handlers: dict[str, str] = {}
|
|
477
482
|
|
|
483
|
+
# Handler descriptors (handler_type -> descriptor with contract_config)
|
|
484
|
+
# Stored during registration for use during handler initialization
|
|
485
|
+
# Enables contract config to be passed to handlers via initialize()
|
|
486
|
+
self._handler_descriptors: dict[str, ModelHandlerDescriptor] = {}
|
|
487
|
+
|
|
478
488
|
# Pending message tracking for graceful shutdown (OMN-756)
|
|
479
489
|
# Tracks count of in-flight messages currently being processed
|
|
480
490
|
self._pending_message_count: int = 0
|
|
@@ -967,33 +977,37 @@ class RuntimeHostProcess:
|
|
|
967
977
|
logger.info("RuntimeHostProcess stopped successfully")
|
|
968
978
|
|
|
969
979
|
async def _discover_or_wire_handlers(self) -> None:
|
|
970
|
-
"""Discover
|
|
980
|
+
"""Discover and register handlers for the runtime.
|
|
971
981
|
|
|
972
982
|
This method implements the handler discovery/wiring step (Step 3) of the
|
|
973
|
-
start() sequence.
|
|
983
|
+
start() sequence.
|
|
984
|
+
|
|
985
|
+
Bootstrap Handlers (OMN-1087):
|
|
986
|
+
Bootstrap handlers (Consul, DB, HTTP, Vault) are ALWAYS registered first
|
|
987
|
+
via HandlerBootstrapSource. These core infrastructure handlers are
|
|
988
|
+
essential for the ONEX runtime and are loaded from descriptor-based
|
|
989
|
+
definitions rather than filesystem contracts.
|
|
974
990
|
|
|
975
991
|
Contract-Based Discovery (OMN-1133):
|
|
976
992
|
If contract_paths were provided at init, uses ContractHandlerDiscovery
|
|
977
|
-
to auto-discover and register handlers from the specified paths.
|
|
993
|
+
to auto-discover and register additional handlers from the specified paths.
|
|
978
994
|
|
|
979
995
|
Discovery errors are logged but do not block startup, enabling
|
|
980
996
|
graceful degradation where some handlers can be registered even
|
|
981
997
|
if others fail to load.
|
|
982
998
|
|
|
983
|
-
Default Handler Wiring (Fallback):
|
|
984
|
-
If no contract_paths were provided, falls back to wire_default_handlers()
|
|
985
|
-
which registers the standard set of handlers (HTTP, DB, Consul, Vault).
|
|
986
|
-
|
|
987
999
|
The discovery/wiring step registers handler CLASSES with the handler registry.
|
|
988
1000
|
The subsequent _populate_handlers_from_registry() step instantiates and
|
|
989
1001
|
initializes these handler classes.
|
|
990
1002
|
"""
|
|
1003
|
+
# Register bootstrap handlers FIRST (OMN-1087)
|
|
1004
|
+
# Bootstrap handlers are core infrastructure handlers that are always
|
|
1005
|
+
# available, loaded from HandlerBootstrapSource descriptors.
|
|
1006
|
+
await self._register_bootstrap_handlers()
|
|
1007
|
+
|
|
991
1008
|
if self._contract_paths:
|
|
992
1009
|
# Contract-based handler discovery (OMN-1133)
|
|
993
1010
|
await self._discover_handlers_from_contracts()
|
|
994
|
-
else:
|
|
995
|
-
# Fallback to default handler wiring (existing behavior)
|
|
996
|
-
wire_handlers()
|
|
997
1011
|
|
|
998
1012
|
async def _discover_handlers_from_contracts(self) -> None:
|
|
999
1013
|
"""Discover and register handlers from contract files.
|
|
@@ -1076,6 +1090,168 @@ class RuntimeHostProcess:
|
|
|
1076
1090
|
},
|
|
1077
1091
|
)
|
|
1078
1092
|
|
|
1093
|
+
async def _register_bootstrap_handlers(self) -> None:
|
|
1094
|
+
"""Register core infrastructure handlers from HandlerBootstrapSource.
|
|
1095
|
+
|
|
1096
|
+
This method implements descriptor-based handler registration as part of
|
|
1097
|
+
OMN-1087. It uses HandlerBootstrapSource to discover and register the
|
|
1098
|
+
core infrastructure handlers (Consul, DB, HTTP, Vault) without requiring
|
|
1099
|
+
contract.yaml files on the filesystem.
|
|
1100
|
+
|
|
1101
|
+
Bootstrap handlers are registered FIRST, before any contract-based or
|
|
1102
|
+
default handler wiring. This ensures core infrastructure handlers are
|
|
1103
|
+
always available regardless of how other handlers are discovered.
|
|
1104
|
+
|
|
1105
|
+
Handler Registration Process:
|
|
1106
|
+
1. Create HandlerBootstrapSource instance
|
|
1107
|
+
2. Call discover_handlers() to get handler descriptors
|
|
1108
|
+
3. For each descriptor:
|
|
1109
|
+
a. Extract protocol type from handler_id (e.g., "bootstrap.consul" -> "consul")
|
|
1110
|
+
b. Import handler class from fully qualified class path
|
|
1111
|
+
c. Register class with handler registry
|
|
1112
|
+
|
|
1113
|
+
Error Handling:
|
|
1114
|
+
Individual handler failures are logged but do not block registration
|
|
1115
|
+
of other handlers. This enables graceful degradation where some
|
|
1116
|
+
bootstrap handlers can be registered even if others fail to import.
|
|
1117
|
+
|
|
1118
|
+
Related:
|
|
1119
|
+
- HandlerBootstrapSource: Source that provides handler descriptors
|
|
1120
|
+
- ModelHandlerDescriptor: Descriptor model with handler metadata
|
|
1121
|
+
- _discover_or_wire_handlers: Caller that orchestrates all handler loading
|
|
1122
|
+
"""
|
|
1123
|
+
from omnibase_infra.runtime.handler_bootstrap_source import (
|
|
1124
|
+
SOURCE_TYPE_BOOTSTRAP,
|
|
1125
|
+
HandlerBootstrapSource,
|
|
1126
|
+
)
|
|
1127
|
+
|
|
1128
|
+
logger.info(
|
|
1129
|
+
"Starting bootstrap handler registration",
|
|
1130
|
+
extra={"source_type": SOURCE_TYPE_BOOTSTRAP},
|
|
1131
|
+
)
|
|
1132
|
+
|
|
1133
|
+
# Get handler registry for registration
|
|
1134
|
+
handler_registry = await self._get_handler_registry()
|
|
1135
|
+
|
|
1136
|
+
# Create bootstrap source and discover handlers
|
|
1137
|
+
bootstrap_source = HandlerBootstrapSource()
|
|
1138
|
+
discovery_result = await bootstrap_source.discover_handlers()
|
|
1139
|
+
|
|
1140
|
+
registered_count = 0
|
|
1141
|
+
error_count = 0
|
|
1142
|
+
|
|
1143
|
+
for descriptor in discovery_result.descriptors:
|
|
1144
|
+
try:
|
|
1145
|
+
# Extract protocol type from handler_id
|
|
1146
|
+
# Handler IDs are formatted as "bootstrap.{protocol_type}"
|
|
1147
|
+
# e.g., "bootstrap.consul" -> "consul"
|
|
1148
|
+
# removeprefix returns original string if prefix not found
|
|
1149
|
+
protocol_type = descriptor.handler_id.removeprefix("bootstrap.")
|
|
1150
|
+
|
|
1151
|
+
# Import the handler class from fully qualified path
|
|
1152
|
+
handler_class_path = descriptor.handler_class
|
|
1153
|
+
if handler_class_path is None:
|
|
1154
|
+
logger.warning(
|
|
1155
|
+
"Bootstrap handler missing handler_class, skipping",
|
|
1156
|
+
extra={
|
|
1157
|
+
"handler_id": descriptor.handler_id,
|
|
1158
|
+
"handler_name": descriptor.name,
|
|
1159
|
+
},
|
|
1160
|
+
)
|
|
1161
|
+
error_count += 1
|
|
1162
|
+
continue
|
|
1163
|
+
|
|
1164
|
+
# Import class using rsplit pattern (same as ContractHandlerDiscovery)
|
|
1165
|
+
if "." not in handler_class_path:
|
|
1166
|
+
logger.error(
|
|
1167
|
+
"Invalid handler class path (must be fully qualified): %s",
|
|
1168
|
+
handler_class_path,
|
|
1169
|
+
extra={"handler_id": descriptor.handler_id},
|
|
1170
|
+
)
|
|
1171
|
+
error_count += 1
|
|
1172
|
+
continue
|
|
1173
|
+
|
|
1174
|
+
module_path, class_name = handler_class_path.rsplit(".", 1)
|
|
1175
|
+
module = importlib.import_module(module_path)
|
|
1176
|
+
handler_cls = getattr(module, class_name)
|
|
1177
|
+
|
|
1178
|
+
# Verify it's actually a class
|
|
1179
|
+
if not isinstance(handler_cls, type):
|
|
1180
|
+
logger.error(
|
|
1181
|
+
"Handler path does not resolve to a class: %s",
|
|
1182
|
+
handler_class_path,
|
|
1183
|
+
extra={
|
|
1184
|
+
"handler_id": descriptor.handler_id,
|
|
1185
|
+
"resolved_type": type(handler_cls).__name__,
|
|
1186
|
+
},
|
|
1187
|
+
)
|
|
1188
|
+
error_count += 1
|
|
1189
|
+
continue
|
|
1190
|
+
|
|
1191
|
+
# Register with handler registry
|
|
1192
|
+
handler_registry.register(protocol_type, handler_cls)
|
|
1193
|
+
registered_count += 1
|
|
1194
|
+
|
|
1195
|
+
# Store descriptor for later use during handler initialization
|
|
1196
|
+
# This enables passing contract_config to handler.initialize()
|
|
1197
|
+
self._handler_descriptors[protocol_type] = descriptor
|
|
1198
|
+
|
|
1199
|
+
logger.debug(
|
|
1200
|
+
"Registered bootstrap handler: %s -> %s",
|
|
1201
|
+
protocol_type,
|
|
1202
|
+
handler_class_path,
|
|
1203
|
+
extra={
|
|
1204
|
+
"handler_id": descriptor.handler_id,
|
|
1205
|
+
"protocol_type": protocol_type,
|
|
1206
|
+
"handler_class": handler_class_path,
|
|
1207
|
+
"has_contract_config": descriptor.contract_config is not None,
|
|
1208
|
+
"source_type": SOURCE_TYPE_BOOTSTRAP,
|
|
1209
|
+
},
|
|
1210
|
+
)
|
|
1211
|
+
|
|
1212
|
+
except (ImportError, AttributeError):
|
|
1213
|
+
# Module or class import failed
|
|
1214
|
+
error_count += 1
|
|
1215
|
+
logger.exception(
|
|
1216
|
+
"Failed to import bootstrap handler",
|
|
1217
|
+
extra={
|
|
1218
|
+
"handler_id": descriptor.handler_id,
|
|
1219
|
+
"handler_class": descriptor.handler_class,
|
|
1220
|
+
},
|
|
1221
|
+
)
|
|
1222
|
+
|
|
1223
|
+
except Exception:
|
|
1224
|
+
# Unexpected error - log but continue with other handlers
|
|
1225
|
+
error_count += 1
|
|
1226
|
+
logger.exception(
|
|
1227
|
+
"Unexpected error registering bootstrap handler",
|
|
1228
|
+
extra={
|
|
1229
|
+
"handler_id": descriptor.handler_id,
|
|
1230
|
+
"handler_class": descriptor.handler_class,
|
|
1231
|
+
},
|
|
1232
|
+
)
|
|
1233
|
+
|
|
1234
|
+
# Log summary
|
|
1235
|
+
if error_count > 0:
|
|
1236
|
+
logger.warning(
|
|
1237
|
+
"Bootstrap handler registration completed with errors",
|
|
1238
|
+
extra={
|
|
1239
|
+
"registered_count": registered_count,
|
|
1240
|
+
"error_count": error_count,
|
|
1241
|
+
"total_descriptors": len(discovery_result.descriptors),
|
|
1242
|
+
"source_type": SOURCE_TYPE_BOOTSTRAP,
|
|
1243
|
+
},
|
|
1244
|
+
)
|
|
1245
|
+
else:
|
|
1246
|
+
logger.info(
|
|
1247
|
+
"Bootstrap handler registration completed successfully",
|
|
1248
|
+
extra={
|
|
1249
|
+
"registered_count": registered_count,
|
|
1250
|
+
"total_descriptors": len(discovery_result.descriptors),
|
|
1251
|
+
"source_type": SOURCE_TYPE_BOOTSTRAP,
|
|
1252
|
+
},
|
|
1253
|
+
)
|
|
1254
|
+
|
|
1079
1255
|
async def _populate_handlers_from_registry(self) -> None:
|
|
1080
1256
|
"""Populate self._handlers from handler registry (container or singleton).
|
|
1081
1257
|
|
|
@@ -1136,7 +1312,41 @@ class RuntimeHostProcess:
|
|
|
1136
1312
|
# Call initialize() if the handler has this method
|
|
1137
1313
|
# Handlers may require async initialization with config
|
|
1138
1314
|
if hasattr(handler_instance, "initialize"):
|
|
1139
|
-
|
|
1315
|
+
# Build effective config: contract config as base, runtime overrides on top
|
|
1316
|
+
# This enables contracts to provide handler-specific defaults while
|
|
1317
|
+
# allowing runtime/deploy-time customization without touching contracts
|
|
1318
|
+
effective_config: dict[str, object] = {}
|
|
1319
|
+
config_source = "runtime_only"
|
|
1320
|
+
|
|
1321
|
+
# Layer 1: Contract config as baseline (if descriptor exists with config)
|
|
1322
|
+
descriptor = self._handler_descriptors.get(handler_type)
|
|
1323
|
+
if descriptor and descriptor.contract_config:
|
|
1324
|
+
effective_config.update(descriptor.contract_config)
|
|
1325
|
+
config_source = "contract_only"
|
|
1326
|
+
|
|
1327
|
+
# Layer 2: Runtime config overrides
|
|
1328
|
+
# Runtime config takes precedence, enabling deploy-time customization
|
|
1329
|
+
if self._config:
|
|
1330
|
+
effective_config.update(self._config)
|
|
1331
|
+
if descriptor and descriptor.contract_config:
|
|
1332
|
+
config_source = "contract+runtime_override"
|
|
1333
|
+
|
|
1334
|
+
# Pass empty dict if no config, not None
|
|
1335
|
+
# Handlers expect dict interface (e.g., config.get("key"))
|
|
1336
|
+
await handler_instance.initialize(effective_config)
|
|
1337
|
+
|
|
1338
|
+
logger.debug(
|
|
1339
|
+
"Handler initialized with effective config",
|
|
1340
|
+
extra={
|
|
1341
|
+
"handler_type": handler_type,
|
|
1342
|
+
"config_source": config_source,
|
|
1343
|
+
"effective_config_keys": list(effective_config.keys()),
|
|
1344
|
+
"has_contract_config": bool(
|
|
1345
|
+
descriptor and descriptor.contract_config
|
|
1346
|
+
),
|
|
1347
|
+
"has_runtime_config": bool(self._config),
|
|
1348
|
+
},
|
|
1349
|
+
)
|
|
1140
1350
|
|
|
1141
1351
|
# Store the handler instance for routing
|
|
1142
1352
|
self._handlers[handler_type] = handler_instance
|