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.
Files changed (116) hide show
  1. omnibase_infra/__init__.py +1 -1
  2. omnibase_infra/adapters/adapter_onex_tool_execution.py +446 -0
  3. omnibase_infra/cli/commands.py +1 -1
  4. omnibase_infra/configs/widget_mapping.yaml +176 -0
  5. omnibase_infra/contracts/handlers/filesystem/handler_contract.yaml +4 -1
  6. omnibase_infra/contracts/handlers/mcp/handler_contract.yaml +4 -1
  7. omnibase_infra/errors/error_compute_registry.py +4 -1
  8. omnibase_infra/errors/error_event_bus_registry.py +4 -1
  9. omnibase_infra/errors/error_infra.py +3 -1
  10. omnibase_infra/errors/error_policy_registry.py +4 -1
  11. omnibase_infra/handlers/handler_db.py +2 -1
  12. omnibase_infra/handlers/handler_graph.py +10 -5
  13. omnibase_infra/handlers/handler_mcp.py +736 -63
  14. omnibase_infra/handlers/mixins/mixin_consul_kv.py +4 -3
  15. omnibase_infra/handlers/mixins/mixin_consul_service.py +2 -1
  16. omnibase_infra/handlers/service_discovery/handler_service_discovery_consul.py +301 -4
  17. omnibase_infra/handlers/service_discovery/models/model_service_info.py +10 -0
  18. omnibase_infra/mixins/mixin_async_circuit_breaker.py +3 -2
  19. omnibase_infra/mixins/mixin_node_introspection.py +24 -7
  20. omnibase_infra/mixins/mixin_retry_execution.py +1 -1
  21. omnibase_infra/models/handlers/__init__.py +10 -0
  22. omnibase_infra/models/handlers/model_bootstrap_handler_descriptor.py +162 -0
  23. omnibase_infra/models/handlers/model_handler_descriptor.py +15 -0
  24. omnibase_infra/models/mcp/__init__.py +15 -0
  25. omnibase_infra/models/mcp/model_mcp_contract_config.py +80 -0
  26. omnibase_infra/models/mcp/model_mcp_server_config.py +67 -0
  27. omnibase_infra/models/mcp/model_mcp_tool_definition.py +73 -0
  28. omnibase_infra/models/mcp/model_mcp_tool_parameter.py +35 -0
  29. omnibase_infra/models/registration/model_node_capabilities.py +11 -0
  30. omnibase_infra/nodes/architecture_validator/contract_architecture_validator.yaml +0 -5
  31. omnibase_infra/nodes/architecture_validator/registry/registry_infra_architecture_validator.py +17 -10
  32. omnibase_infra/nodes/effects/contract.yaml +0 -5
  33. omnibase_infra/nodes/node_registration_orchestrator/contract.yaml +7 -0
  34. omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_introspected.py +86 -1
  35. omnibase_infra/nodes/node_registration_orchestrator/introspection_event_router.py +3 -3
  36. omnibase_infra/nodes/node_registration_orchestrator/registry/registry_infra_node_registration_orchestrator.py +9 -8
  37. omnibase_infra/nodes/node_registration_orchestrator/wiring.py +14 -13
  38. omnibase_infra/nodes/node_registration_storage_effect/contract.yaml +0 -5
  39. omnibase_infra/nodes/node_registration_storage_effect/registry/registry_infra_registration_storage.py +46 -25
  40. omnibase_infra/nodes/node_registry_effect/contract.yaml +0 -5
  41. omnibase_infra/nodes/node_registry_effect/handlers/handler_partial_retry.py +2 -1
  42. omnibase_infra/nodes/node_service_discovery_effect/registry/registry_infra_service_discovery.py +24 -19
  43. omnibase_infra/plugins/examples/plugin_json_normalizer.py +2 -2
  44. omnibase_infra/plugins/examples/plugin_json_normalizer_error_handling.py +2 -2
  45. omnibase_infra/plugins/plugin_compute_base.py +16 -2
  46. omnibase_infra/protocols/protocol_event_projector.py +1 -1
  47. omnibase_infra/runtime/__init__.py +51 -1
  48. omnibase_infra/runtime/binding_config_resolver.py +102 -37
  49. omnibase_infra/runtime/constants_notification.py +75 -0
  50. omnibase_infra/runtime/contract_handler_discovery.py +6 -1
  51. omnibase_infra/runtime/handler_bootstrap_source.py +514 -0
  52. omnibase_infra/runtime/handler_contract_config_loader.py +603 -0
  53. omnibase_infra/runtime/handler_contract_source.py +289 -167
  54. omnibase_infra/runtime/handler_plugin_loader.py +4 -2
  55. omnibase_infra/runtime/mixin_semver_cache.py +25 -1
  56. omnibase_infra/runtime/mixins/__init__.py +7 -0
  57. omnibase_infra/runtime/mixins/mixin_projector_notification_publishing.py +566 -0
  58. omnibase_infra/runtime/mixins/mixin_projector_sql_operations.py +31 -10
  59. omnibase_infra/runtime/models/__init__.py +24 -0
  60. omnibase_infra/runtime/models/model_health_check_result.py +2 -1
  61. omnibase_infra/runtime/models/model_projector_notification_config.py +171 -0
  62. omnibase_infra/runtime/models/model_transition_notification_outbox_config.py +112 -0
  63. omnibase_infra/runtime/models/model_transition_notification_outbox_metrics.py +140 -0
  64. omnibase_infra/runtime/models/model_transition_notification_publisher_metrics.py +357 -0
  65. omnibase_infra/runtime/projector_plugin_loader.py +1 -1
  66. omnibase_infra/runtime/projector_shell.py +229 -1
  67. omnibase_infra/runtime/protocols/__init__.py +10 -0
  68. omnibase_infra/runtime/registry/registry_protocol_binding.py +3 -2
  69. omnibase_infra/runtime/registry_policy.py +9 -326
  70. omnibase_infra/runtime/secret_resolver.py +4 -2
  71. omnibase_infra/runtime/service_kernel.py +10 -2
  72. omnibase_infra/runtime/service_message_dispatch_engine.py +4 -2
  73. omnibase_infra/runtime/service_runtime_host_process.py +225 -15
  74. omnibase_infra/runtime/transition_notification_outbox.py +1190 -0
  75. omnibase_infra/runtime/transition_notification_publisher.py +764 -0
  76. omnibase_infra/runtime/util_container_wiring.py +6 -5
  77. omnibase_infra/runtime/util_wiring.py +5 -1
  78. omnibase_infra/schemas/schema_transition_notification_outbox.sql +245 -0
  79. omnibase_infra/services/mcp/__init__.py +31 -0
  80. omnibase_infra/services/mcp/mcp_server_lifecycle.py +443 -0
  81. omnibase_infra/services/mcp/service_mcp_tool_discovery.py +411 -0
  82. omnibase_infra/services/mcp/service_mcp_tool_registry.py +329 -0
  83. omnibase_infra/services/mcp/service_mcp_tool_sync.py +547 -0
  84. omnibase_infra/services/registry_api/__init__.py +40 -0
  85. omnibase_infra/services/registry_api/main.py +243 -0
  86. omnibase_infra/services/registry_api/models/__init__.py +66 -0
  87. omnibase_infra/services/registry_api/models/model_capability_widget_mapping.py +38 -0
  88. omnibase_infra/services/registry_api/models/model_pagination_info.py +48 -0
  89. omnibase_infra/services/registry_api/models/model_registry_discovery_response.py +73 -0
  90. omnibase_infra/services/registry_api/models/model_registry_health_response.py +49 -0
  91. omnibase_infra/services/registry_api/models/model_registry_instance_view.py +88 -0
  92. omnibase_infra/services/registry_api/models/model_registry_node_view.py +88 -0
  93. omnibase_infra/services/registry_api/models/model_registry_summary.py +60 -0
  94. omnibase_infra/services/registry_api/models/model_response_list_instances.py +43 -0
  95. omnibase_infra/services/registry_api/models/model_response_list_nodes.py +51 -0
  96. omnibase_infra/services/registry_api/models/model_warning.py +49 -0
  97. omnibase_infra/services/registry_api/models/model_widget_defaults.py +28 -0
  98. omnibase_infra/services/registry_api/models/model_widget_mapping.py +51 -0
  99. omnibase_infra/services/registry_api/routes.py +371 -0
  100. omnibase_infra/services/registry_api/service.py +846 -0
  101. omnibase_infra/services/service_capability_query.py +4 -4
  102. omnibase_infra/services/service_health.py +3 -2
  103. omnibase_infra/services/service_timeout_emitter.py +13 -2
  104. omnibase_infra/utils/util_dsn_validation.py +1 -1
  105. omnibase_infra/validation/__init__.py +3 -19
  106. omnibase_infra/validation/contracts/security.validation.yaml +114 -0
  107. omnibase_infra/validation/infra_validators.py +35 -24
  108. omnibase_infra/validation/validation_exemptions.yaml +113 -9
  109. omnibase_infra/validation/validator_chain_propagation.py +2 -2
  110. omnibase_infra/validation/validator_runtime_shape.py +1 -1
  111. omnibase_infra/validation/validator_security.py +473 -370
  112. {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.2.dist-info}/METADATA +2 -2
  113. {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.2.dist-info}/RECORD +116 -74
  114. {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.2.dist-info}/WHEEL +0 -0
  115. {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.2.dist-info}/entry_points.txt +0 -0
  116. {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
- container = ModelONEXContainer()
248
- wire_infrastructure_services(container)
249
- registry = container.service_registry.resolve_service(RegistryProtocolBinding)
250
- process = RuntimeHostProcess(handler_registry=registry)
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 handlers from contracts or wire default handlers.
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. It supports two modes:
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
- await handler_instance.initialize(self._config)
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