omnibase_infra 0.2.1__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 (675) hide show
  1. omnibase_infra/__init__.py +101 -0
  2. omnibase_infra/cli/__init__.py +1 -0
  3. omnibase_infra/cli/commands.py +216 -0
  4. omnibase_infra/clients/__init__.py +0 -0
  5. omnibase_infra/contracts/handlers/filesystem/handler_contract.yaml +261 -0
  6. omnibase_infra/contracts/handlers/mcp/handler_contract.yaml +138 -0
  7. omnibase_infra/decorators/__init__.py +29 -0
  8. omnibase_infra/decorators/allow_any.py +109 -0
  9. omnibase_infra/dlq/__init__.py +90 -0
  10. omnibase_infra/dlq/constants_dlq.py +57 -0
  11. omnibase_infra/dlq/models/__init__.py +26 -0
  12. omnibase_infra/dlq/models/enum_replay_status.py +37 -0
  13. omnibase_infra/dlq/models/model_dlq_replay_record.py +135 -0
  14. omnibase_infra/dlq/models/model_dlq_tracking_config.py +184 -0
  15. omnibase_infra/dlq/service_dlq_tracking.py +611 -0
  16. omnibase_infra/enums/__init__.py +123 -0
  17. omnibase_infra/enums/enum_any_type_violation.py +104 -0
  18. omnibase_infra/enums/enum_backend_type.py +27 -0
  19. omnibase_infra/enums/enum_capture_outcome.py +42 -0
  20. omnibase_infra/enums/enum_capture_state.py +88 -0
  21. omnibase_infra/enums/enum_chain_violation_type.py +119 -0
  22. omnibase_infra/enums/enum_circuit_state.py +51 -0
  23. omnibase_infra/enums/enum_confirmation_event_type.py +27 -0
  24. omnibase_infra/enums/enum_contract_type.py +84 -0
  25. omnibase_infra/enums/enum_dedupe_strategy.py +46 -0
  26. omnibase_infra/enums/enum_dispatch_status.py +191 -0
  27. omnibase_infra/enums/enum_environment.py +46 -0
  28. omnibase_infra/enums/enum_execution_shape_violation.py +103 -0
  29. omnibase_infra/enums/enum_handler_error_type.py +101 -0
  30. omnibase_infra/enums/enum_handler_loader_error.py +178 -0
  31. omnibase_infra/enums/enum_handler_source_type.py +87 -0
  32. omnibase_infra/enums/enum_handler_type.py +77 -0
  33. omnibase_infra/enums/enum_handler_type_category.py +61 -0
  34. omnibase_infra/enums/enum_infra_transport_type.py +73 -0
  35. omnibase_infra/enums/enum_introspection_reason.py +154 -0
  36. omnibase_infra/enums/enum_message_category.py +213 -0
  37. omnibase_infra/enums/enum_node_archetype.py +74 -0
  38. omnibase_infra/enums/enum_node_output_type.py +185 -0
  39. omnibase_infra/enums/enum_non_retryable_error_category.py +224 -0
  40. omnibase_infra/enums/enum_policy_type.py +32 -0
  41. omnibase_infra/enums/enum_registration_state.py +261 -0
  42. omnibase_infra/enums/enum_registration_status.py +33 -0
  43. omnibase_infra/enums/enum_registry_response_status.py +28 -0
  44. omnibase_infra/enums/enum_response_status.py +26 -0
  45. omnibase_infra/enums/enum_retry_error_category.py +98 -0
  46. omnibase_infra/enums/enum_security_rule_id.py +103 -0
  47. omnibase_infra/enums/enum_selection_strategy.py +91 -0
  48. omnibase_infra/enums/enum_topic_standard.py +42 -0
  49. omnibase_infra/enums/enum_validation_severity.py +78 -0
  50. omnibase_infra/errors/__init__.py +156 -0
  51. omnibase_infra/errors/error_architecture_violation.py +152 -0
  52. omnibase_infra/errors/error_chain_propagation.py +188 -0
  53. omnibase_infra/errors/error_compute_registry.py +92 -0
  54. omnibase_infra/errors/error_consul.py +132 -0
  55. omnibase_infra/errors/error_container_wiring.py +243 -0
  56. omnibase_infra/errors/error_event_bus_registry.py +102 -0
  57. omnibase_infra/errors/error_infra.py +608 -0
  58. omnibase_infra/errors/error_message_type_registry.py +101 -0
  59. omnibase_infra/errors/error_policy_registry.py +112 -0
  60. omnibase_infra/errors/error_vault.py +123 -0
  61. omnibase_infra/event_bus/__init__.py +72 -0
  62. omnibase_infra/event_bus/configs/kafka_event_bus_config.yaml +86 -0
  63. omnibase_infra/event_bus/event_bus_inmemory.py +743 -0
  64. omnibase_infra/event_bus/event_bus_kafka.py +1658 -0
  65. omnibase_infra/event_bus/mixin_kafka_broadcast.py +184 -0
  66. omnibase_infra/event_bus/mixin_kafka_dlq.py +765 -0
  67. omnibase_infra/event_bus/models/__init__.py +29 -0
  68. omnibase_infra/event_bus/models/config/__init__.py +20 -0
  69. omnibase_infra/event_bus/models/config/model_kafka_event_bus_config.py +725 -0
  70. omnibase_infra/event_bus/models/model_dlq_event.py +206 -0
  71. omnibase_infra/event_bus/models/model_dlq_metrics.py +304 -0
  72. omnibase_infra/event_bus/models/model_event_headers.py +115 -0
  73. omnibase_infra/event_bus/models/model_event_message.py +60 -0
  74. omnibase_infra/event_bus/topic_constants.py +376 -0
  75. omnibase_infra/handlers/__init__.py +75 -0
  76. omnibase_infra/handlers/filesystem/__init__.py +48 -0
  77. omnibase_infra/handlers/filesystem/enum_file_system_operation.py +35 -0
  78. omnibase_infra/handlers/filesystem/model_file_system_request.py +298 -0
  79. omnibase_infra/handlers/filesystem/model_file_system_result.py +166 -0
  80. omnibase_infra/handlers/handler_consul.py +787 -0
  81. omnibase_infra/handlers/handler_db.py +1039 -0
  82. omnibase_infra/handlers/handler_filesystem.py +1478 -0
  83. omnibase_infra/handlers/handler_graph.py +1154 -0
  84. omnibase_infra/handlers/handler_http.py +920 -0
  85. omnibase_infra/handlers/handler_manifest_persistence.contract.yaml +184 -0
  86. omnibase_infra/handlers/handler_manifest_persistence.py +1539 -0
  87. omnibase_infra/handlers/handler_mcp.py +748 -0
  88. omnibase_infra/handlers/handler_qdrant.py +1076 -0
  89. omnibase_infra/handlers/handler_vault.py +422 -0
  90. omnibase_infra/handlers/mcp/__init__.py +19 -0
  91. omnibase_infra/handlers/mcp/adapter_onex_to_mcp.py +446 -0
  92. omnibase_infra/handlers/mcp/protocols.py +178 -0
  93. omnibase_infra/handlers/mcp/transport_streamable_http.py +352 -0
  94. omnibase_infra/handlers/mixins/__init__.py +42 -0
  95. omnibase_infra/handlers/mixins/mixin_consul_initialization.py +349 -0
  96. omnibase_infra/handlers/mixins/mixin_consul_kv.py +337 -0
  97. omnibase_infra/handlers/mixins/mixin_consul_service.py +277 -0
  98. omnibase_infra/handlers/mixins/mixin_vault_initialization.py +338 -0
  99. omnibase_infra/handlers/mixins/mixin_vault_retry.py +412 -0
  100. omnibase_infra/handlers/mixins/mixin_vault_secrets.py +450 -0
  101. omnibase_infra/handlers/mixins/mixin_vault_token.py +365 -0
  102. omnibase_infra/handlers/models/__init__.py +286 -0
  103. omnibase_infra/handlers/models/consul/__init__.py +81 -0
  104. omnibase_infra/handlers/models/consul/enum_consul_operation_type.py +57 -0
  105. omnibase_infra/handlers/models/consul/model_consul_deregister_payload.py +51 -0
  106. omnibase_infra/handlers/models/consul/model_consul_handler_config.py +153 -0
  107. omnibase_infra/handlers/models/consul/model_consul_handler_payload.py +89 -0
  108. omnibase_infra/handlers/models/consul/model_consul_kv_get_found_payload.py +55 -0
  109. omnibase_infra/handlers/models/consul/model_consul_kv_get_not_found_payload.py +49 -0
  110. omnibase_infra/handlers/models/consul/model_consul_kv_get_recurse_payload.py +50 -0
  111. omnibase_infra/handlers/models/consul/model_consul_kv_item.py +33 -0
  112. omnibase_infra/handlers/models/consul/model_consul_kv_put_payload.py +41 -0
  113. omnibase_infra/handlers/models/consul/model_consul_register_payload.py +53 -0
  114. omnibase_infra/handlers/models/consul/model_consul_retry_config.py +66 -0
  115. omnibase_infra/handlers/models/consul/model_payload_consul.py +66 -0
  116. omnibase_infra/handlers/models/consul/registry_payload_consul.py +214 -0
  117. omnibase_infra/handlers/models/graph/__init__.py +35 -0
  118. omnibase_infra/handlers/models/graph/enum_graph_operation_type.py +20 -0
  119. omnibase_infra/handlers/models/graph/model_graph_execute_payload.py +38 -0
  120. omnibase_infra/handlers/models/graph/model_graph_handler_config.py +54 -0
  121. omnibase_infra/handlers/models/graph/model_graph_handler_payload.py +44 -0
  122. omnibase_infra/handlers/models/graph/model_graph_query_payload.py +40 -0
  123. omnibase_infra/handlers/models/graph/model_graph_record.py +22 -0
  124. omnibase_infra/handlers/models/http/__init__.py +50 -0
  125. omnibase_infra/handlers/models/http/enum_http_operation_type.py +29 -0
  126. omnibase_infra/handlers/models/http/model_http_body_content.py +45 -0
  127. omnibase_infra/handlers/models/http/model_http_get_payload.py +88 -0
  128. omnibase_infra/handlers/models/http/model_http_handler_payload.py +90 -0
  129. omnibase_infra/handlers/models/http/model_http_post_payload.py +88 -0
  130. omnibase_infra/handlers/models/http/model_payload_http.py +66 -0
  131. omnibase_infra/handlers/models/http/registry_payload_http.py +212 -0
  132. omnibase_infra/handlers/models/mcp/__init__.py +23 -0
  133. omnibase_infra/handlers/models/mcp/enum_mcp_operation_type.py +24 -0
  134. omnibase_infra/handlers/models/mcp/model_mcp_handler_config.py +40 -0
  135. omnibase_infra/handlers/models/mcp/model_mcp_tool_call.py +32 -0
  136. omnibase_infra/handlers/models/mcp/model_mcp_tool_result.py +45 -0
  137. omnibase_infra/handlers/models/model_consul_handler_response.py +96 -0
  138. omnibase_infra/handlers/models/model_db_describe_response.py +83 -0
  139. omnibase_infra/handlers/models/model_db_query_payload.py +95 -0
  140. omnibase_infra/handlers/models/model_db_query_response.py +60 -0
  141. omnibase_infra/handlers/models/model_filesystem_config.py +98 -0
  142. omnibase_infra/handlers/models/model_filesystem_delete_payload.py +54 -0
  143. omnibase_infra/handlers/models/model_filesystem_delete_result.py +77 -0
  144. omnibase_infra/handlers/models/model_filesystem_directory_entry.py +75 -0
  145. omnibase_infra/handlers/models/model_filesystem_ensure_directory_payload.py +54 -0
  146. omnibase_infra/handlers/models/model_filesystem_ensure_directory_result.py +60 -0
  147. omnibase_infra/handlers/models/model_filesystem_list_directory_payload.py +60 -0
  148. omnibase_infra/handlers/models/model_filesystem_list_directory_result.py +68 -0
  149. omnibase_infra/handlers/models/model_filesystem_read_payload.py +62 -0
  150. omnibase_infra/handlers/models/model_filesystem_read_result.py +61 -0
  151. omnibase_infra/handlers/models/model_filesystem_write_payload.py +70 -0
  152. omnibase_infra/handlers/models/model_filesystem_write_result.py +55 -0
  153. omnibase_infra/handlers/models/model_graph_handler_response.py +98 -0
  154. omnibase_infra/handlers/models/model_handler_response.py +103 -0
  155. omnibase_infra/handlers/models/model_http_handler_response.py +101 -0
  156. omnibase_infra/handlers/models/model_manifest_metadata.py +75 -0
  157. omnibase_infra/handlers/models/model_manifest_persistence_config.py +62 -0
  158. omnibase_infra/handlers/models/model_manifest_query_payload.py +90 -0
  159. omnibase_infra/handlers/models/model_manifest_query_result.py +97 -0
  160. omnibase_infra/handlers/models/model_manifest_retrieve_payload.py +44 -0
  161. omnibase_infra/handlers/models/model_manifest_retrieve_result.py +98 -0
  162. omnibase_infra/handlers/models/model_manifest_store_payload.py +47 -0
  163. omnibase_infra/handlers/models/model_manifest_store_result.py +67 -0
  164. omnibase_infra/handlers/models/model_operation_context.py +187 -0
  165. omnibase_infra/handlers/models/model_qdrant_handler_response.py +98 -0
  166. omnibase_infra/handlers/models/model_retry_state.py +162 -0
  167. omnibase_infra/handlers/models/model_vault_handler_response.py +98 -0
  168. omnibase_infra/handlers/models/qdrant/__init__.py +44 -0
  169. omnibase_infra/handlers/models/qdrant/enum_qdrant_operation_type.py +26 -0
  170. omnibase_infra/handlers/models/qdrant/model_qdrant_collection_payload.py +42 -0
  171. omnibase_infra/handlers/models/qdrant/model_qdrant_delete_payload.py +36 -0
  172. omnibase_infra/handlers/models/qdrant/model_qdrant_handler_config.py +42 -0
  173. omnibase_infra/handlers/models/qdrant/model_qdrant_handler_payload.py +54 -0
  174. omnibase_infra/handlers/models/qdrant/model_qdrant_search_payload.py +42 -0
  175. omnibase_infra/handlers/models/qdrant/model_qdrant_search_result.py +30 -0
  176. omnibase_infra/handlers/models/qdrant/model_qdrant_upsert_payload.py +36 -0
  177. omnibase_infra/handlers/models/vault/__init__.py +69 -0
  178. omnibase_infra/handlers/models/vault/enum_vault_operation_type.py +35 -0
  179. omnibase_infra/handlers/models/vault/model_payload_vault.py +66 -0
  180. omnibase_infra/handlers/models/vault/model_vault_delete_payload.py +57 -0
  181. omnibase_infra/handlers/models/vault/model_vault_handler_config.py +148 -0
  182. omnibase_infra/handlers/models/vault/model_vault_handler_payload.py +101 -0
  183. omnibase_infra/handlers/models/vault/model_vault_list_payload.py +58 -0
  184. omnibase_infra/handlers/models/vault/model_vault_renew_token_payload.py +67 -0
  185. omnibase_infra/handlers/models/vault/model_vault_retry_config.py +66 -0
  186. omnibase_infra/handlers/models/vault/model_vault_secret_payload.py +106 -0
  187. omnibase_infra/handlers/models/vault/model_vault_write_payload.py +66 -0
  188. omnibase_infra/handlers/models/vault/registry_payload_vault.py +213 -0
  189. omnibase_infra/handlers/registration_storage/__init__.py +43 -0
  190. omnibase_infra/handlers/registration_storage/handler_registration_storage_mock.py +392 -0
  191. omnibase_infra/handlers/registration_storage/handler_registration_storage_postgres.py +915 -0
  192. omnibase_infra/handlers/registration_storage/models/__init__.py +23 -0
  193. omnibase_infra/handlers/registration_storage/models/model_delete_registration_request.py +58 -0
  194. omnibase_infra/handlers/registration_storage/models/model_update_registration_request.py +73 -0
  195. omnibase_infra/handlers/registration_storage/protocol_registration_persistence.py +191 -0
  196. omnibase_infra/handlers/service_discovery/__init__.py +43 -0
  197. omnibase_infra/handlers/service_discovery/handler_service_discovery_consul.py +747 -0
  198. omnibase_infra/handlers/service_discovery/handler_service_discovery_mock.py +258 -0
  199. omnibase_infra/handlers/service_discovery/models/__init__.py +22 -0
  200. omnibase_infra/handlers/service_discovery/models/model_discovery_result.py +64 -0
  201. omnibase_infra/handlers/service_discovery/models/model_registration_result.py +138 -0
  202. omnibase_infra/handlers/service_discovery/models/model_service_info.py +99 -0
  203. omnibase_infra/handlers/service_discovery/protocol_discovery_operations.py +170 -0
  204. omnibase_infra/idempotency/__init__.py +94 -0
  205. omnibase_infra/idempotency/models/__init__.py +43 -0
  206. omnibase_infra/idempotency/models/model_idempotency_check_result.py +85 -0
  207. omnibase_infra/idempotency/models/model_idempotency_guard_config.py +130 -0
  208. omnibase_infra/idempotency/models/model_idempotency_record.py +86 -0
  209. omnibase_infra/idempotency/models/model_idempotency_store_health_check_result.py +81 -0
  210. omnibase_infra/idempotency/models/model_idempotency_store_metrics.py +140 -0
  211. omnibase_infra/idempotency/models/model_postgres_idempotency_store_config.py +299 -0
  212. omnibase_infra/idempotency/protocol_idempotency_store.py +184 -0
  213. omnibase_infra/idempotency/store_inmemory.py +265 -0
  214. omnibase_infra/idempotency/store_postgres.py +923 -0
  215. omnibase_infra/infrastructure/__init__.py +0 -0
  216. omnibase_infra/mixins/__init__.py +71 -0
  217. omnibase_infra/mixins/mixin_async_circuit_breaker.py +655 -0
  218. omnibase_infra/mixins/mixin_dict_like_accessors.py +146 -0
  219. omnibase_infra/mixins/mixin_envelope_extraction.py +119 -0
  220. omnibase_infra/mixins/mixin_node_introspection.py +2465 -0
  221. omnibase_infra/mixins/mixin_retry_execution.py +386 -0
  222. omnibase_infra/mixins/protocol_circuit_breaker_aware.py +133 -0
  223. omnibase_infra/models/__init__.py +136 -0
  224. omnibase_infra/models/corpus/__init__.py +17 -0
  225. omnibase_infra/models/corpus/model_capture_config.py +133 -0
  226. omnibase_infra/models/corpus/model_capture_result.py +86 -0
  227. omnibase_infra/models/discovery/__init__.py +42 -0
  228. omnibase_infra/models/discovery/model_dependency_spec.py +319 -0
  229. omnibase_infra/models/discovery/model_discovered_capabilities.py +50 -0
  230. omnibase_infra/models/discovery/model_introspection_config.py +311 -0
  231. omnibase_infra/models/discovery/model_introspection_performance_metrics.py +169 -0
  232. omnibase_infra/models/discovery/model_introspection_task_config.py +116 -0
  233. omnibase_infra/models/dispatch/__init__.py +147 -0
  234. omnibase_infra/models/dispatch/model_dispatch_context.py +439 -0
  235. omnibase_infra/models/dispatch/model_dispatch_error.py +336 -0
  236. omnibase_infra/models/dispatch/model_dispatch_log_context.py +400 -0
  237. omnibase_infra/models/dispatch/model_dispatch_metadata.py +228 -0
  238. omnibase_infra/models/dispatch/model_dispatch_metrics.py +496 -0
  239. omnibase_infra/models/dispatch/model_dispatch_outcome.py +317 -0
  240. omnibase_infra/models/dispatch/model_dispatch_outputs.py +231 -0
  241. omnibase_infra/models/dispatch/model_dispatch_result.py +436 -0
  242. omnibase_infra/models/dispatch/model_dispatch_route.py +279 -0
  243. omnibase_infra/models/dispatch/model_dispatcher_metrics.py +275 -0
  244. omnibase_infra/models/dispatch/model_dispatcher_registration.py +352 -0
  245. omnibase_infra/models/dispatch/model_parsed_topic.py +135 -0
  246. omnibase_infra/models/dispatch/model_topic_parser.py +725 -0
  247. omnibase_infra/models/dispatch/model_tracing_context.py +285 -0
  248. omnibase_infra/models/errors/__init__.py +45 -0
  249. omnibase_infra/models/errors/model_handler_validation_error.py +594 -0
  250. omnibase_infra/models/errors/model_infra_error_context.py +99 -0
  251. omnibase_infra/models/errors/model_message_type_registry_error_context.py +71 -0
  252. omnibase_infra/models/errors/model_timeout_error_context.py +110 -0
  253. omnibase_infra/models/handlers/__init__.py +37 -0
  254. omnibase_infra/models/handlers/model_contract_discovery_result.py +80 -0
  255. omnibase_infra/models/handlers/model_handler_descriptor.py +185 -0
  256. omnibase_infra/models/handlers/model_handler_identifier.py +215 -0
  257. omnibase_infra/models/health/__init__.py +9 -0
  258. omnibase_infra/models/health/model_health_check_result.py +40 -0
  259. omnibase_infra/models/lifecycle/__init__.py +39 -0
  260. omnibase_infra/models/logging/__init__.py +51 -0
  261. omnibase_infra/models/logging/model_log_context.py +756 -0
  262. omnibase_infra/models/model_retry_error_classification.py +78 -0
  263. omnibase_infra/models/projection/__init__.py +43 -0
  264. omnibase_infra/models/projection/model_capability_fields.py +112 -0
  265. omnibase_infra/models/projection/model_registration_projection.py +434 -0
  266. omnibase_infra/models/projection/model_registration_snapshot.py +322 -0
  267. omnibase_infra/models/projection/model_sequence_info.py +182 -0
  268. omnibase_infra/models/projection/model_snapshot_topic_config.py +590 -0
  269. omnibase_infra/models/projectors/__init__.py +41 -0
  270. omnibase_infra/models/projectors/model_projector_column.py +289 -0
  271. omnibase_infra/models/projectors/model_projector_discovery_result.py +65 -0
  272. omnibase_infra/models/projectors/model_projector_index.py +270 -0
  273. omnibase_infra/models/projectors/model_projector_schema.py +415 -0
  274. omnibase_infra/models/projectors/model_projector_validation_error.py +63 -0
  275. omnibase_infra/models/projectors/util_sql_identifiers.py +115 -0
  276. omnibase_infra/models/registration/__init__.py +59 -0
  277. omnibase_infra/models/registration/commands/__init__.py +15 -0
  278. omnibase_infra/models/registration/commands/model_node_registration_acked.py +108 -0
  279. omnibase_infra/models/registration/events/__init__.py +56 -0
  280. omnibase_infra/models/registration/events/model_node_became_active.py +103 -0
  281. omnibase_infra/models/registration/events/model_node_liveness_expired.py +103 -0
  282. omnibase_infra/models/registration/events/model_node_registration_accepted.py +98 -0
  283. omnibase_infra/models/registration/events/model_node_registration_ack_received.py +98 -0
  284. omnibase_infra/models/registration/events/model_node_registration_ack_timed_out.py +112 -0
  285. omnibase_infra/models/registration/events/model_node_registration_initiated.py +107 -0
  286. omnibase_infra/models/registration/events/model_node_registration_rejected.py +104 -0
  287. omnibase_infra/models/registration/model_introspection_metrics.py +253 -0
  288. omnibase_infra/models/registration/model_node_capabilities.py +179 -0
  289. omnibase_infra/models/registration/model_node_heartbeat_event.py +126 -0
  290. omnibase_infra/models/registration/model_node_introspection_event.py +175 -0
  291. omnibase_infra/models/registration/model_node_metadata.py +79 -0
  292. omnibase_infra/models/registration/model_node_registration.py +162 -0
  293. omnibase_infra/models/registration/model_node_registration_record.py +162 -0
  294. omnibase_infra/models/registry/__init__.py +29 -0
  295. omnibase_infra/models/registry/model_domain_constraint.py +202 -0
  296. omnibase_infra/models/registry/model_message_type_entry.py +271 -0
  297. omnibase_infra/models/resilience/__init__.py +9 -0
  298. omnibase_infra/models/resilience/model_circuit_breaker_config.py +227 -0
  299. omnibase_infra/models/routing/__init__.py +25 -0
  300. omnibase_infra/models/routing/model_routing_entry.py +52 -0
  301. omnibase_infra/models/routing/model_routing_subcontract.py +70 -0
  302. omnibase_infra/models/runtime/__init__.py +40 -0
  303. omnibase_infra/models/runtime/model_contract_security_config.py +41 -0
  304. omnibase_infra/models/runtime/model_discovery_error.py +81 -0
  305. omnibase_infra/models/runtime/model_discovery_result.py +162 -0
  306. omnibase_infra/models/runtime/model_discovery_warning.py +74 -0
  307. omnibase_infra/models/runtime/model_failed_plugin_load.py +63 -0
  308. omnibase_infra/models/runtime/model_handler_contract.py +280 -0
  309. omnibase_infra/models/runtime/model_loaded_handler.py +120 -0
  310. omnibase_infra/models/runtime/model_plugin_load_context.py +93 -0
  311. omnibase_infra/models/runtime/model_plugin_load_summary.py +124 -0
  312. omnibase_infra/models/security/__init__.py +50 -0
  313. omnibase_infra/models/security/classification_levels.py +99 -0
  314. omnibase_infra/models/security/model_environment_policy.py +145 -0
  315. omnibase_infra/models/security/model_handler_security_policy.py +107 -0
  316. omnibase_infra/models/security/model_security_error.py +81 -0
  317. omnibase_infra/models/security/model_security_validation_result.py +328 -0
  318. omnibase_infra/models/security/model_security_warning.py +67 -0
  319. omnibase_infra/models/snapshot/__init__.py +27 -0
  320. omnibase_infra/models/snapshot/model_field_change.py +65 -0
  321. omnibase_infra/models/snapshot/model_snapshot.py +270 -0
  322. omnibase_infra/models/snapshot/model_snapshot_diff.py +203 -0
  323. omnibase_infra/models/snapshot/model_subject_ref.py +81 -0
  324. omnibase_infra/models/types/__init__.py +71 -0
  325. omnibase_infra/models/validation/__init__.py +89 -0
  326. omnibase_infra/models/validation/model_any_type_validation_result.py +118 -0
  327. omnibase_infra/models/validation/model_any_type_violation.py +141 -0
  328. omnibase_infra/models/validation/model_category_match_result.py +345 -0
  329. omnibase_infra/models/validation/model_chain_violation.py +166 -0
  330. omnibase_infra/models/validation/model_coverage_metrics.py +316 -0
  331. omnibase_infra/models/validation/model_execution_shape_rule.py +159 -0
  332. omnibase_infra/models/validation/model_execution_shape_validation.py +208 -0
  333. omnibase_infra/models/validation/model_execution_shape_validation_result.py +294 -0
  334. omnibase_infra/models/validation/model_execution_shape_violation.py +122 -0
  335. omnibase_infra/models/validation/model_localhandler_validation_result.py +139 -0
  336. omnibase_infra/models/validation/model_localhandler_violation.py +100 -0
  337. omnibase_infra/models/validation/model_output_validation_params.py +74 -0
  338. omnibase_infra/models/validation/model_validate_and_raise_params.py +84 -0
  339. omnibase_infra/models/validation/model_validation_error_params.py +84 -0
  340. omnibase_infra/models/validation/model_validation_outcome.py +287 -0
  341. omnibase_infra/nodes/__init__.py +48 -0
  342. omnibase_infra/nodes/architecture_validator/__init__.py +79 -0
  343. omnibase_infra/nodes/architecture_validator/contract.yaml +252 -0
  344. omnibase_infra/nodes/architecture_validator/contract_architecture_validator.yaml +208 -0
  345. omnibase_infra/nodes/architecture_validator/mixins/__init__.py +16 -0
  346. omnibase_infra/nodes/architecture_validator/mixins/mixin_file_path_rule.py +92 -0
  347. omnibase_infra/nodes/architecture_validator/models/__init__.py +36 -0
  348. omnibase_infra/nodes/architecture_validator/models/model_architecture_validation_request.py +56 -0
  349. omnibase_infra/nodes/architecture_validator/models/model_architecture_validation_result.py +311 -0
  350. omnibase_infra/nodes/architecture_validator/models/model_architecture_violation.py +163 -0
  351. omnibase_infra/nodes/architecture_validator/models/model_rule_check_result.py +265 -0
  352. omnibase_infra/nodes/architecture_validator/models/model_validation_request.py +105 -0
  353. omnibase_infra/nodes/architecture_validator/models/model_validation_result.py +314 -0
  354. omnibase_infra/nodes/architecture_validator/node.py +262 -0
  355. omnibase_infra/nodes/architecture_validator/node_architecture_validator.py +383 -0
  356. omnibase_infra/nodes/architecture_validator/protocols/__init__.py +9 -0
  357. omnibase_infra/nodes/architecture_validator/protocols/protocol_architecture_rule.py +225 -0
  358. omnibase_infra/nodes/architecture_validator/registry/__init__.py +28 -0
  359. omnibase_infra/nodes/architecture_validator/registry/registry_infra_architecture_validator.py +99 -0
  360. omnibase_infra/nodes/architecture_validator/validators/__init__.py +104 -0
  361. omnibase_infra/nodes/architecture_validator/validators/validator_no_direct_dispatch.py +422 -0
  362. omnibase_infra/nodes/architecture_validator/validators/validator_no_handler_publishing.py +481 -0
  363. omnibase_infra/nodes/architecture_validator/validators/validator_no_orchestrator_fsm.py +491 -0
  364. omnibase_infra/nodes/effects/README.md +358 -0
  365. omnibase_infra/nodes/effects/__init__.py +26 -0
  366. omnibase_infra/nodes/effects/contract.yaml +172 -0
  367. omnibase_infra/nodes/effects/models/__init__.py +32 -0
  368. omnibase_infra/nodes/effects/models/model_backend_result.py +190 -0
  369. omnibase_infra/nodes/effects/models/model_effect_idempotency_config.py +92 -0
  370. omnibase_infra/nodes/effects/models/model_registry_request.py +132 -0
  371. omnibase_infra/nodes/effects/models/model_registry_response.py +263 -0
  372. omnibase_infra/nodes/effects/protocol_consul_client.py +89 -0
  373. omnibase_infra/nodes/effects/protocol_effect_idempotency_store.py +143 -0
  374. omnibase_infra/nodes/effects/protocol_postgres_adapter.py +96 -0
  375. omnibase_infra/nodes/effects/registry_effect.py +525 -0
  376. omnibase_infra/nodes/effects/store_effect_idempotency_inmemory.py +425 -0
  377. omnibase_infra/nodes/node_registration_orchestrator/README.md +542 -0
  378. omnibase_infra/nodes/node_registration_orchestrator/__init__.py +120 -0
  379. omnibase_infra/nodes/node_registration_orchestrator/contract.yaml +475 -0
  380. omnibase_infra/nodes/node_registration_orchestrator/dispatchers/__init__.py +53 -0
  381. omnibase_infra/nodes/node_registration_orchestrator/dispatchers/dispatcher_node_introspected.py +376 -0
  382. omnibase_infra/nodes/node_registration_orchestrator/dispatchers/dispatcher_node_registration_acked.py +376 -0
  383. omnibase_infra/nodes/node_registration_orchestrator/dispatchers/dispatcher_runtime_tick.py +373 -0
  384. omnibase_infra/nodes/node_registration_orchestrator/handlers/__init__.py +62 -0
  385. omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_heartbeat.py +376 -0
  386. omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_introspected.py +609 -0
  387. omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_registration_acked.py +458 -0
  388. omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_runtime_tick.py +364 -0
  389. omnibase_infra/nodes/node_registration_orchestrator/introspection_event_router.py +544 -0
  390. omnibase_infra/nodes/node_registration_orchestrator/models/__init__.py +75 -0
  391. omnibase_infra/nodes/node_registration_orchestrator/models/model_consul_intent_payload.py +194 -0
  392. omnibase_infra/nodes/node_registration_orchestrator/models/model_consul_registration_intent.py +67 -0
  393. omnibase_infra/nodes/node_registration_orchestrator/models/model_intent_execution_result.py +50 -0
  394. omnibase_infra/nodes/node_registration_orchestrator/models/model_node_liveness_expired.py +107 -0
  395. omnibase_infra/nodes/node_registration_orchestrator/models/model_orchestrator_config.py +67 -0
  396. omnibase_infra/nodes/node_registration_orchestrator/models/model_orchestrator_input.py +41 -0
  397. omnibase_infra/nodes/node_registration_orchestrator/models/model_orchestrator_output.py +166 -0
  398. omnibase_infra/nodes/node_registration_orchestrator/models/model_postgres_intent_payload.py +235 -0
  399. omnibase_infra/nodes/node_registration_orchestrator/models/model_postgres_upsert_intent.py +68 -0
  400. omnibase_infra/nodes/node_registration_orchestrator/models/model_reducer_execution_result.py +384 -0
  401. omnibase_infra/nodes/node_registration_orchestrator/models/model_reducer_state.py +60 -0
  402. omnibase_infra/nodes/node_registration_orchestrator/models/model_registration_intent.py +177 -0
  403. omnibase_infra/nodes/node_registration_orchestrator/models/model_registry_intent.py +247 -0
  404. omnibase_infra/nodes/node_registration_orchestrator/node.py +195 -0
  405. omnibase_infra/nodes/node_registration_orchestrator/plugin.py +909 -0
  406. omnibase_infra/nodes/node_registration_orchestrator/protocols.py +439 -0
  407. omnibase_infra/nodes/node_registration_orchestrator/registry/__init__.py +41 -0
  408. omnibase_infra/nodes/node_registration_orchestrator/registry/registry_infra_node_registration_orchestrator.py +525 -0
  409. omnibase_infra/nodes/node_registration_orchestrator/timeout_coordinator.py +392 -0
  410. omnibase_infra/nodes/node_registration_orchestrator/wiring.py +742 -0
  411. omnibase_infra/nodes/node_registration_reducer/__init__.py +15 -0
  412. omnibase_infra/nodes/node_registration_reducer/contract.yaml +301 -0
  413. omnibase_infra/nodes/node_registration_reducer/models/__init__.py +38 -0
  414. omnibase_infra/nodes/node_registration_reducer/models/model_validation_result.py +113 -0
  415. omnibase_infra/nodes/node_registration_reducer/node.py +139 -0
  416. omnibase_infra/nodes/node_registration_reducer/registry/__init__.py +9 -0
  417. omnibase_infra/nodes/node_registration_reducer/registry/registry_infra_node_registration_reducer.py +79 -0
  418. omnibase_infra/nodes/node_registration_storage_effect/__init__.py +41 -0
  419. omnibase_infra/nodes/node_registration_storage_effect/contract.yaml +225 -0
  420. omnibase_infra/nodes/node_registration_storage_effect/models/__init__.py +44 -0
  421. omnibase_infra/nodes/node_registration_storage_effect/models/model_delete_result.py +132 -0
  422. omnibase_infra/nodes/node_registration_storage_effect/models/model_registration_record.py +199 -0
  423. omnibase_infra/nodes/node_registration_storage_effect/models/model_registration_update.py +155 -0
  424. omnibase_infra/nodes/node_registration_storage_effect/models/model_storage_health_check_details.py +123 -0
  425. omnibase_infra/nodes/node_registration_storage_effect/models/model_storage_health_check_result.py +117 -0
  426. omnibase_infra/nodes/node_registration_storage_effect/models/model_storage_query.py +100 -0
  427. omnibase_infra/nodes/node_registration_storage_effect/models/model_storage_result.py +136 -0
  428. omnibase_infra/nodes/node_registration_storage_effect/models/model_upsert_result.py +127 -0
  429. omnibase_infra/nodes/node_registration_storage_effect/node.py +109 -0
  430. omnibase_infra/nodes/node_registration_storage_effect/protocols/__init__.py +22 -0
  431. omnibase_infra/nodes/node_registration_storage_effect/protocols/protocol_registration_persistence.py +333 -0
  432. omnibase_infra/nodes/node_registration_storage_effect/registry/__init__.py +23 -0
  433. omnibase_infra/nodes/node_registration_storage_effect/registry/registry_infra_registration_storage.py +194 -0
  434. omnibase_infra/nodes/node_registry_effect/__init__.py +85 -0
  435. omnibase_infra/nodes/node_registry_effect/contract.yaml +682 -0
  436. omnibase_infra/nodes/node_registry_effect/handlers/__init__.py +70 -0
  437. omnibase_infra/nodes/node_registry_effect/handlers/handler_consul_deregister.py +211 -0
  438. omnibase_infra/nodes/node_registry_effect/handlers/handler_consul_register.py +212 -0
  439. omnibase_infra/nodes/node_registry_effect/handlers/handler_partial_retry.py +416 -0
  440. omnibase_infra/nodes/node_registry_effect/handlers/handler_postgres_deactivate.py +215 -0
  441. omnibase_infra/nodes/node_registry_effect/handlers/handler_postgres_upsert.py +208 -0
  442. omnibase_infra/nodes/node_registry_effect/models/__init__.py +43 -0
  443. omnibase_infra/nodes/node_registry_effect/models/model_partial_retry_request.py +92 -0
  444. omnibase_infra/nodes/node_registry_effect/node.py +165 -0
  445. omnibase_infra/nodes/node_registry_effect/registry/__init__.py +27 -0
  446. omnibase_infra/nodes/node_registry_effect/registry/registry_infra_registry_effect.py +196 -0
  447. omnibase_infra/nodes/node_service_discovery_effect/__init__.py +111 -0
  448. omnibase_infra/nodes/node_service_discovery_effect/contract.yaml +246 -0
  449. omnibase_infra/nodes/node_service_discovery_effect/models/__init__.py +67 -0
  450. omnibase_infra/nodes/node_service_discovery_effect/models/enum_health_status.py +72 -0
  451. omnibase_infra/nodes/node_service_discovery_effect/models/enum_service_discovery_operation.py +58 -0
  452. omnibase_infra/nodes/node_service_discovery_effect/models/model_discovery_query.py +99 -0
  453. omnibase_infra/nodes/node_service_discovery_effect/models/model_discovery_result.py +98 -0
  454. omnibase_infra/nodes/node_service_discovery_effect/models/model_health_check_config.py +121 -0
  455. omnibase_infra/nodes/node_service_discovery_effect/models/model_query_metadata.py +63 -0
  456. omnibase_infra/nodes/node_service_discovery_effect/models/model_registration_result.py +130 -0
  457. omnibase_infra/nodes/node_service_discovery_effect/models/model_service_discovery_health_check_details.py +111 -0
  458. omnibase_infra/nodes/node_service_discovery_effect/models/model_service_discovery_health_check_result.py +119 -0
  459. omnibase_infra/nodes/node_service_discovery_effect/models/model_service_info.py +106 -0
  460. omnibase_infra/nodes/node_service_discovery_effect/models/model_service_registration.py +121 -0
  461. omnibase_infra/nodes/node_service_discovery_effect/node.py +111 -0
  462. omnibase_infra/nodes/node_service_discovery_effect/protocols/__init__.py +14 -0
  463. omnibase_infra/nodes/node_service_discovery_effect/protocols/protocol_discovery_operations.py +279 -0
  464. omnibase_infra/nodes/node_service_discovery_effect/registry/__init__.py +13 -0
  465. omnibase_infra/nodes/node_service_discovery_effect/registry/registry_infra_service_discovery.py +214 -0
  466. omnibase_infra/nodes/reducers/__init__.py +30 -0
  467. omnibase_infra/nodes/reducers/models/__init__.py +32 -0
  468. omnibase_infra/nodes/reducers/models/model_payload_consul_register.py +76 -0
  469. omnibase_infra/nodes/reducers/models/model_payload_postgres_upsert_registration.py +60 -0
  470. omnibase_infra/nodes/reducers/models/model_registration_confirmation.py +166 -0
  471. omnibase_infra/nodes/reducers/models/model_registration_state.py +433 -0
  472. omnibase_infra/nodes/reducers/registration_reducer.py +1137 -0
  473. omnibase_infra/observability/__init__.py +143 -0
  474. omnibase_infra/observability/constants_metrics.py +91 -0
  475. omnibase_infra/observability/factory_observability_sink.py +525 -0
  476. omnibase_infra/observability/handlers/__init__.py +118 -0
  477. omnibase_infra/observability/handlers/handler_logging_structured.py +967 -0
  478. omnibase_infra/observability/handlers/handler_metrics_prometheus.py +1120 -0
  479. omnibase_infra/observability/handlers/model_logging_handler_config.py +71 -0
  480. omnibase_infra/observability/handlers/model_logging_handler_response.py +77 -0
  481. omnibase_infra/observability/handlers/model_metrics_handler_config.py +172 -0
  482. omnibase_infra/observability/handlers/model_metrics_handler_payload.py +135 -0
  483. omnibase_infra/observability/handlers/model_metrics_handler_response.py +101 -0
  484. omnibase_infra/observability/hooks/__init__.py +74 -0
  485. omnibase_infra/observability/hooks/hook_observability.py +1223 -0
  486. omnibase_infra/observability/models/__init__.py +30 -0
  487. omnibase_infra/observability/models/enum_required_log_context_key.py +77 -0
  488. omnibase_infra/observability/models/model_buffered_log_entry.py +117 -0
  489. omnibase_infra/observability/models/model_logging_sink_config.py +73 -0
  490. omnibase_infra/observability/models/model_metrics_sink_config.py +156 -0
  491. omnibase_infra/observability/sinks/__init__.py +69 -0
  492. omnibase_infra/observability/sinks/sink_logging_structured.py +809 -0
  493. omnibase_infra/observability/sinks/sink_metrics_prometheus.py +710 -0
  494. omnibase_infra/plugins/__init__.py +27 -0
  495. omnibase_infra/plugins/examples/__init__.py +28 -0
  496. omnibase_infra/plugins/examples/plugin_json_normalizer.py +271 -0
  497. omnibase_infra/plugins/examples/plugin_json_normalizer_error_handling.py +210 -0
  498. omnibase_infra/plugins/models/__init__.py +21 -0
  499. omnibase_infra/plugins/models/model_plugin_context.py +76 -0
  500. omnibase_infra/plugins/models/model_plugin_input_data.py +58 -0
  501. omnibase_infra/plugins/models/model_plugin_output_data.py +62 -0
  502. omnibase_infra/plugins/plugin_compute_base.py +435 -0
  503. omnibase_infra/projectors/__init__.py +30 -0
  504. omnibase_infra/projectors/contracts/__init__.py +63 -0
  505. omnibase_infra/projectors/contracts/registration_projector.yaml +370 -0
  506. omnibase_infra/projectors/projection_reader_registration.py +1559 -0
  507. omnibase_infra/projectors/snapshot_publisher_registration.py +1329 -0
  508. omnibase_infra/protocols/__init__.py +99 -0
  509. omnibase_infra/protocols/protocol_capability_projection.py +253 -0
  510. omnibase_infra/protocols/protocol_capability_query.py +251 -0
  511. omnibase_infra/protocols/protocol_event_bus_like.py +127 -0
  512. omnibase_infra/protocols/protocol_event_projector.py +96 -0
  513. omnibase_infra/protocols/protocol_idempotency_store.py +142 -0
  514. omnibase_infra/protocols/protocol_message_dispatcher.py +247 -0
  515. omnibase_infra/protocols/protocol_message_type_registry.py +306 -0
  516. omnibase_infra/protocols/protocol_plugin_compute.py +368 -0
  517. omnibase_infra/protocols/protocol_projector_schema_validator.py +82 -0
  518. omnibase_infra/protocols/protocol_registry_metrics.py +215 -0
  519. omnibase_infra/protocols/protocol_snapshot_publisher.py +396 -0
  520. omnibase_infra/protocols/protocol_snapshot_store.py +567 -0
  521. omnibase_infra/runtime/__init__.py +296 -0
  522. omnibase_infra/runtime/binding_config_resolver.py +2706 -0
  523. omnibase_infra/runtime/chain_aware_dispatch.py +467 -0
  524. omnibase_infra/runtime/contract_handler_discovery.py +582 -0
  525. omnibase_infra/runtime/contract_loaders/__init__.py +42 -0
  526. omnibase_infra/runtime/contract_loaders/handler_routing_loader.py +464 -0
  527. omnibase_infra/runtime/dispatch_context_enforcer.py +427 -0
  528. omnibase_infra/runtime/enums/__init__.py +18 -0
  529. omnibase_infra/runtime/enums/enum_config_ref_scheme.py +33 -0
  530. omnibase_infra/runtime/enums/enum_scheduler_status.py +170 -0
  531. omnibase_infra/runtime/envelope_validator.py +179 -0
  532. omnibase_infra/runtime/handler_contract_source.py +669 -0
  533. omnibase_infra/runtime/handler_plugin_loader.py +2029 -0
  534. omnibase_infra/runtime/handler_registry.py +321 -0
  535. omnibase_infra/runtime/invocation_security_enforcer.py +427 -0
  536. omnibase_infra/runtime/kernel.py +40 -0
  537. omnibase_infra/runtime/mixin_policy_validation.py +522 -0
  538. omnibase_infra/runtime/mixin_semver_cache.py +378 -0
  539. omnibase_infra/runtime/mixins/__init__.py +17 -0
  540. omnibase_infra/runtime/mixins/mixin_projector_sql_operations.py +757 -0
  541. omnibase_infra/runtime/models/__init__.py +192 -0
  542. omnibase_infra/runtime/models/model_batch_lifecycle_result.py +217 -0
  543. omnibase_infra/runtime/models/model_binding_config.py +168 -0
  544. omnibase_infra/runtime/models/model_binding_config_cache_stats.py +135 -0
  545. omnibase_infra/runtime/models/model_binding_config_resolver_config.py +329 -0
  546. omnibase_infra/runtime/models/model_cached_secret.py +138 -0
  547. omnibase_infra/runtime/models/model_compute_key.py +138 -0
  548. omnibase_infra/runtime/models/model_compute_registration.py +97 -0
  549. omnibase_infra/runtime/models/model_config_cache_entry.py +61 -0
  550. omnibase_infra/runtime/models/model_config_ref.py +331 -0
  551. omnibase_infra/runtime/models/model_config_ref_parse_result.py +125 -0
  552. omnibase_infra/runtime/models/model_domain_plugin_config.py +92 -0
  553. omnibase_infra/runtime/models/model_domain_plugin_result.py +270 -0
  554. omnibase_infra/runtime/models/model_duplicate_response.py +54 -0
  555. omnibase_infra/runtime/models/model_enabled_protocols_config.py +61 -0
  556. omnibase_infra/runtime/models/model_event_bus_config.py +54 -0
  557. omnibase_infra/runtime/models/model_failed_component.py +55 -0
  558. omnibase_infra/runtime/models/model_health_check_response.py +168 -0
  559. omnibase_infra/runtime/models/model_health_check_result.py +228 -0
  560. omnibase_infra/runtime/models/model_lifecycle_result.py +245 -0
  561. omnibase_infra/runtime/models/model_logging_config.py +42 -0
  562. omnibase_infra/runtime/models/model_optional_correlation_id.py +167 -0
  563. omnibase_infra/runtime/models/model_optional_string.py +94 -0
  564. omnibase_infra/runtime/models/model_optional_uuid.py +110 -0
  565. omnibase_infra/runtime/models/model_policy_context.py +100 -0
  566. omnibase_infra/runtime/models/model_policy_key.py +138 -0
  567. omnibase_infra/runtime/models/model_policy_registration.py +139 -0
  568. omnibase_infra/runtime/models/model_policy_result.py +103 -0
  569. omnibase_infra/runtime/models/model_policy_type_filter.py +157 -0
  570. omnibase_infra/runtime/models/model_projector_plugin_loader_config.py +47 -0
  571. omnibase_infra/runtime/models/model_protocol_registration_config.py +65 -0
  572. omnibase_infra/runtime/models/model_retry_policy.py +105 -0
  573. omnibase_infra/runtime/models/model_runtime_config.py +150 -0
  574. omnibase_infra/runtime/models/model_runtime_scheduler_config.py +624 -0
  575. omnibase_infra/runtime/models/model_runtime_scheduler_metrics.py +233 -0
  576. omnibase_infra/runtime/models/model_runtime_tick.py +193 -0
  577. omnibase_infra/runtime/models/model_secret_cache_stats.py +82 -0
  578. omnibase_infra/runtime/models/model_secret_mapping.py +63 -0
  579. omnibase_infra/runtime/models/model_secret_resolver_config.py +107 -0
  580. omnibase_infra/runtime/models/model_secret_resolver_metrics.py +111 -0
  581. omnibase_infra/runtime/models/model_secret_source_info.py +72 -0
  582. omnibase_infra/runtime/models/model_secret_source_spec.py +66 -0
  583. omnibase_infra/runtime/models/model_shutdown_batch_result.py +75 -0
  584. omnibase_infra/runtime/models/model_shutdown_config.py +94 -0
  585. omnibase_infra/runtime/projector_plugin_loader.py +1462 -0
  586. omnibase_infra/runtime/projector_schema_manager.py +565 -0
  587. omnibase_infra/runtime/projector_shell.py +1102 -0
  588. omnibase_infra/runtime/protocol_contract_descriptor.py +92 -0
  589. omnibase_infra/runtime/protocol_contract_source.py +92 -0
  590. omnibase_infra/runtime/protocol_domain_plugin.py +474 -0
  591. omnibase_infra/runtime/protocol_handler_discovery.py +221 -0
  592. omnibase_infra/runtime/protocol_handler_plugin_loader.py +327 -0
  593. omnibase_infra/runtime/protocol_lifecycle_executor.py +435 -0
  594. omnibase_infra/runtime/protocol_policy.py +366 -0
  595. omnibase_infra/runtime/protocols/__init__.py +27 -0
  596. omnibase_infra/runtime/protocols/protocol_runtime_scheduler.py +468 -0
  597. omnibase_infra/runtime/registry/__init__.py +93 -0
  598. omnibase_infra/runtime/registry/mixin_message_type_query.py +326 -0
  599. omnibase_infra/runtime/registry/mixin_message_type_registration.py +354 -0
  600. omnibase_infra/runtime/registry/registry_event_bus_binding.py +268 -0
  601. omnibase_infra/runtime/registry/registry_message_type.py +542 -0
  602. omnibase_infra/runtime/registry/registry_protocol_binding.py +444 -0
  603. omnibase_infra/runtime/registry_compute.py +1143 -0
  604. omnibase_infra/runtime/registry_dispatcher.py +678 -0
  605. omnibase_infra/runtime/registry_policy.py +1502 -0
  606. omnibase_infra/runtime/runtime_scheduler.py +1070 -0
  607. omnibase_infra/runtime/secret_resolver.py +2110 -0
  608. omnibase_infra/runtime/security_metadata_validator.py +776 -0
  609. omnibase_infra/runtime/service_kernel.py +1573 -0
  610. omnibase_infra/runtime/service_message_dispatch_engine.py +1805 -0
  611. omnibase_infra/runtime/service_runtime_host_process.py +2260 -0
  612. omnibase_infra/runtime/util_container_wiring.py +1123 -0
  613. omnibase_infra/runtime/util_validation.py +314 -0
  614. omnibase_infra/runtime/util_version.py +98 -0
  615. omnibase_infra/runtime/util_wiring.py +566 -0
  616. omnibase_infra/schemas/schema_registration_projection.sql +320 -0
  617. omnibase_infra/services/__init__.py +68 -0
  618. omnibase_infra/services/corpus_capture.py +678 -0
  619. omnibase_infra/services/service_capability_query.py +945 -0
  620. omnibase_infra/services/service_health.py +897 -0
  621. omnibase_infra/services/service_node_selector.py +530 -0
  622. omnibase_infra/services/service_timeout_emitter.py +682 -0
  623. omnibase_infra/services/service_timeout_scanner.py +390 -0
  624. omnibase_infra/services/snapshot/__init__.py +31 -0
  625. omnibase_infra/services/snapshot/service_snapshot.py +647 -0
  626. omnibase_infra/services/snapshot/store_inmemory.py +637 -0
  627. omnibase_infra/services/snapshot/store_postgres.py +1279 -0
  628. omnibase_infra/shared/__init__.py +8 -0
  629. omnibase_infra/testing/__init__.py +10 -0
  630. omnibase_infra/testing/utils.py +23 -0
  631. omnibase_infra/types/__init__.py +48 -0
  632. omnibase_infra/types/type_cache_info.py +49 -0
  633. omnibase_infra/types/type_dsn.py +173 -0
  634. omnibase_infra/types/type_infra_aliases.py +60 -0
  635. omnibase_infra/types/typed_dict/__init__.py +21 -0
  636. omnibase_infra/types/typed_dict/typed_dict_introspection_cache.py +128 -0
  637. omnibase_infra/types/typed_dict/typed_dict_performance_metrics_cache.py +140 -0
  638. omnibase_infra/types/typed_dict_capabilities.py +64 -0
  639. omnibase_infra/utils/__init__.py +89 -0
  640. omnibase_infra/utils/correlation.py +208 -0
  641. omnibase_infra/utils/util_datetime.py +372 -0
  642. omnibase_infra/utils/util_dsn_validation.py +333 -0
  643. omnibase_infra/utils/util_env_parsing.py +264 -0
  644. omnibase_infra/utils/util_error_sanitization.py +457 -0
  645. omnibase_infra/utils/util_pydantic_validators.py +477 -0
  646. omnibase_infra/utils/util_semver.py +233 -0
  647. omnibase_infra/validation/__init__.py +307 -0
  648. omnibase_infra/validation/enums/__init__.py +11 -0
  649. omnibase_infra/validation/enums/enum_contract_violation_severity.py +13 -0
  650. omnibase_infra/validation/infra_validators.py +1486 -0
  651. omnibase_infra/validation/linter_contract.py +907 -0
  652. omnibase_infra/validation/mixin_any_type_classification.py +120 -0
  653. omnibase_infra/validation/mixin_any_type_exemption.py +580 -0
  654. omnibase_infra/validation/mixin_any_type_reporting.py +106 -0
  655. omnibase_infra/validation/mixin_execution_shape_violation_checks.py +596 -0
  656. omnibase_infra/validation/mixin_node_archetype_detection.py +254 -0
  657. omnibase_infra/validation/models/__init__.py +15 -0
  658. omnibase_infra/validation/models/model_contract_lint_result.py +101 -0
  659. omnibase_infra/validation/models/model_contract_violation.py +41 -0
  660. omnibase_infra/validation/service_validation_aggregator.py +395 -0
  661. omnibase_infra/validation/validation_exemptions.yaml +1710 -0
  662. omnibase_infra/validation/validator_any_type.py +715 -0
  663. omnibase_infra/validation/validator_chain_propagation.py +839 -0
  664. omnibase_infra/validation/validator_execution_shape.py +465 -0
  665. omnibase_infra/validation/validator_localhandler.py +261 -0
  666. omnibase_infra/validation/validator_registration_security.py +410 -0
  667. omnibase_infra/validation/validator_routing_coverage.py +1020 -0
  668. omnibase_infra/validation/validator_runtime_shape.py +915 -0
  669. omnibase_infra/validation/validator_security.py +410 -0
  670. omnibase_infra/validation/validator_topic_category.py +1152 -0
  671. omnibase_infra-0.2.1.dist-info/METADATA +197 -0
  672. omnibase_infra-0.2.1.dist-info/RECORD +675 -0
  673. omnibase_infra-0.2.1.dist-info/WHEEL +4 -0
  674. omnibase_infra-0.2.1.dist-info/entry_points.txt +4 -0
  675. omnibase_infra-0.2.1.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,1573 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2025 OmniNode Team
3
+ """ONEX Kernel - Minimal bootstrap for contract-driven runtime.
4
+
5
+ This is the kernel entrypoint for the ONEX runtime. It provides a contract-driven
6
+ bootstrap that wires configuration into the existing RuntimeHostProcess.
7
+
8
+ The kernel is responsible for:
9
+ 1. Loading runtime configuration from contracts or environment
10
+ 2. Creating and starting the event bus (EventBusInmemory or EventBusKafka)
11
+ 3. Building the dependency container (event_bus, config)
12
+ 4. Instantiating RuntimeHostProcess with contract-driven configuration
13
+ 5. Starting the HTTP health server for Docker/K8s probes
14
+ 6. Setting up graceful shutdown signal handlers
15
+ 7. Running the runtime until shutdown is requested
16
+
17
+ Event Bus Selection:
18
+ The kernel supports two event bus implementations:
19
+ - EventBusInmemory: For local development and testing (default)
20
+ - EventBusKafka: For production use with Kafka/Redpanda
21
+
22
+ Selection is determined by:
23
+ - KAFKA_BOOTSTRAP_SERVERS environment variable (if set, uses Kafka)
24
+ - config.event_bus.type field in runtime_config.yaml
25
+
26
+ Usage:
27
+ # Run with default contracts directory (./contracts)
28
+ python -m omnibase_infra.runtime.service_kernel
29
+
30
+ # Run with custom contracts directory
31
+ ONEX_CONTRACTS_DIR=/path/to/contracts python -m omnibase_infra.runtime.service_kernel
32
+
33
+ # Or via the installed entrypoint
34
+ onex-runtime
35
+
36
+ Environment Variables:
37
+ ONEX_CONTRACTS_DIR: Path to contracts directory (default: ./contracts)
38
+ ONEX_HTTP_PORT: Port for health check HTTP server (default: 8085)
39
+ ONEX_LOG_LEVEL: Logging level (default: INFO)
40
+ ONEX_ENVIRONMENT: Runtime environment name (default: local)
41
+
42
+ Note:
43
+ This kernel uses the existing RuntimeHostProcess as the core runtime engine.
44
+ A future refactor may integrate NodeOrchestrator as the primary execution
45
+ engine, but for MVP this lean kernel provides contract-driven bootstrap
46
+ with minimal risk and maximum reuse of tested code.
47
+ """
48
+
49
+ from __future__ import annotations
50
+
51
+ import asyncio
52
+ import logging
53
+ import os
54
+ import signal
55
+ import sys
56
+ import time
57
+ from collections.abc import Awaitable, Callable
58
+ from importlib.metadata import version as get_package_version
59
+ from pathlib import Path
60
+ from typing import cast
61
+ from uuid import UUID
62
+
63
+ import asyncpg
64
+ import yaml
65
+ from pydantic import ValidationError
66
+
67
+ from omnibase_core.container import ModelONEXContainer
68
+ from omnibase_infra.enums import EnumInfraTransportType
69
+ from omnibase_infra.errors import (
70
+ ModelInfraErrorContext,
71
+ ProtocolConfigurationError,
72
+ RuntimeHostError,
73
+ ServiceResolutionError,
74
+ )
75
+ from omnibase_infra.event_bus.event_bus_inmemory import EventBusInmemory
76
+ from omnibase_infra.event_bus.event_bus_kafka import EventBusKafka
77
+ from omnibase_infra.event_bus.models.config import ModelKafkaEventBusConfig
78
+ from omnibase_infra.nodes.node_registration_orchestrator.dispatchers import (
79
+ DispatcherNodeIntrospected,
80
+ )
81
+ from omnibase_infra.nodes.node_registration_orchestrator.introspection_event_router import (
82
+ IntrospectionEventRouter,
83
+ )
84
+ from omnibase_infra.runtime.handler_registry import RegistryProtocolBinding
85
+ from omnibase_infra.runtime.models import (
86
+ ModelProjectorPluginLoaderConfig,
87
+ ModelRuntimeConfig,
88
+ )
89
+ from omnibase_infra.runtime.projector_plugin_loader import (
90
+ ProjectorPluginLoader,
91
+ ProjectorShell,
92
+ ProtocolEventProjector,
93
+ )
94
+ from omnibase_infra.runtime.service_runtime_host_process import RuntimeHostProcess
95
+ from omnibase_infra.runtime.util_container_wiring import (
96
+ wire_infrastructure_services,
97
+ wire_registration_handlers,
98
+ )
99
+
100
+ # Circular Import Note (OMN-529):
101
+ # ---------------------------------
102
+ # ServiceHealth and DEFAULT_HTTP_PORT are imported inside bootstrap() rather than
103
+ # at module level to avoid a circular import. The import chain is:
104
+ #
105
+ # 1. omnibase_infra/runtime/__init__.py imports kernel_bootstrap from kernel.py
106
+ # 2. If kernel.py imported ServiceHealth at module level, it would load service_health.py
107
+ # 3. service_health.py imports ModelHealthCheckResponse from runtime.models
108
+ # 4. This triggers initialization of omnibase_infra.runtime package (step 1)
109
+ # 5. Runtime package tries to import kernel.py which is still initializing -> circular!
110
+ #
111
+ # The lazy import in bootstrap() is acceptable because:
112
+ # - ServiceHealth is only instantiated at runtime, not at import time
113
+ # - Type checking uses forward references (no import needed)
114
+ # - No import-time side effects are bypassed
115
+ # - The omnibase_infra.services.__init__.py already excludes ServiceHealth exports
116
+ # to prevent accidental circular imports from other modules
117
+ #
118
+ # See also: omnibase_infra/services/__init__.py "ServiceHealth Import Guide" section
119
+ from omnibase_infra.runtime.util_validation import validate_runtime_config
120
+ from omnibase_infra.utils.correlation import generate_correlation_id
121
+ from omnibase_infra.utils.util_error_sanitization import sanitize_error_message
122
+
123
+ logger = logging.getLogger(__name__)
124
+
125
+ # Kernel version - read from installed package metadata to avoid version drift
126
+ # between code and pyproject.toml. Falls back to "unknown" if package is not
127
+ # installed (e.g., during development without editable install).
128
+ try:
129
+ KERNEL_VERSION = get_package_version("omnibase_infra")
130
+ except Exception:
131
+ KERNEL_VERSION = "unknown"
132
+
133
+ # Default configuration
134
+ DEFAULT_CONTRACTS_DIR = "./contracts"
135
+ DEFAULT_RUNTIME_CONFIG = "runtime/runtime_config.yaml"
136
+
137
+ # Environment variable name for contracts directory
138
+ ENV_CONTRACTS_DIR = "ONEX_CONTRACTS_DIR"
139
+ DEFAULT_INPUT_TOPIC = "requests"
140
+ DEFAULT_OUTPUT_TOPIC = "responses"
141
+ DEFAULT_GROUP_ID = "onex-runtime"
142
+
143
+ # Port validation constants
144
+ MIN_PORT = 1
145
+ MAX_PORT = 65535
146
+
147
+
148
+ def _get_contracts_dir() -> Path:
149
+ """Get contracts directory from environment.
150
+
151
+ Reads the ONEX_CONTRACTS_DIR environment variable. If not set,
152
+ returns the default contracts directory.
153
+
154
+ Returns:
155
+ Path to the contracts directory.
156
+ """
157
+ onex_value = os.environ.get(ENV_CONTRACTS_DIR)
158
+ if onex_value:
159
+ return Path(onex_value)
160
+
161
+ return Path(DEFAULT_CONTRACTS_DIR)
162
+
163
+
164
+ def load_runtime_config(
165
+ contracts_dir: Path,
166
+ correlation_id: UUID | None = None,
167
+ ) -> ModelRuntimeConfig:
168
+ """Load runtime configuration from contract file or return defaults.
169
+
170
+ Attempts to load runtime_config.yaml from the contracts directory.
171
+ If the file doesn't exist, returns sensible defaults to allow
172
+ the runtime to start without requiring a config file.
173
+
174
+ Configuration Loading Process:
175
+ 1. Check for runtime_config.yaml in contracts directory
176
+ 2. If found, parse YAML and validate against ModelRuntimeConfig schema
177
+ 3. If not found, construct config from environment variables and defaults
178
+ 4. Return fully validated configuration model
179
+
180
+ Configuration Precedence:
181
+ - File-based config is returned as-is when present (no environment overrides)
182
+ - Environment variables are only used when no config file exists
183
+ - Defaults are used when neither file nor environment variables are set
184
+ - Note: Environment overrides (e.g., ONEX_ENVIRONMENT) are applied by the
185
+ caller (bootstrap), not by this function
186
+
187
+ Args:
188
+ contracts_dir: Path to the contracts directory containing runtime_config.yaml.
189
+ Example: Path("./contracts") or Path("/app/contracts")
190
+ correlation_id: Optional correlation ID for distributed tracing. If not
191
+ provided, a new one will be generated. Passing a correlation_id from
192
+ the caller (e.g., bootstrap) ensures consistent tracing across the
193
+ initialization sequence.
194
+
195
+ Returns:
196
+ ModelRuntimeConfig: Fully validated configuration model with runtime settings.
197
+ Contains event bus configuration, topic names, consumer group, shutdown
198
+ behavior, and logging configuration.
199
+
200
+ Raises:
201
+ ProtocolConfigurationError: If config file exists but cannot be parsed,
202
+ fails validation, or cannot be read due to filesystem errors. Error
203
+ includes correlation_id for tracing and detailed context for debugging.
204
+
205
+ Example:
206
+ >>> contracts_dir = Path("./contracts")
207
+ >>> config = load_runtime_config(contracts_dir)
208
+ >>> print(config.input_topic)
209
+ requests
210
+ >>> print(config.event_bus.type)
211
+ inmemory
212
+
213
+ Example Error:
214
+ >>> # If runtime_config.yaml has invalid YAML syntax
215
+ >>> load_runtime_config(Path("./invalid"))
216
+ ProtocolConfigurationError: Failed to parse runtime config YAML at ./invalid/runtime/runtime_config.yaml
217
+ (correlation_id: 123e4567-e89b-12d3-a456-426614174000)
218
+ """
219
+ config_path = contracts_dir / DEFAULT_RUNTIME_CONFIG
220
+ # Use passed correlation_id for consistent tracing, or generate new one
221
+ effective_correlation_id = correlation_id or generate_correlation_id()
222
+ context = ModelInfraErrorContext(
223
+ transport_type=EnumInfraTransportType.RUNTIME,
224
+ operation="load_config",
225
+ target_name=str(config_path),
226
+ correlation_id=effective_correlation_id,
227
+ )
228
+
229
+ if config_path.exists():
230
+ logger.info(
231
+ "Loading runtime config from %s (correlation_id=%s)",
232
+ config_path,
233
+ effective_correlation_id,
234
+ )
235
+ try:
236
+ with config_path.open(encoding="utf-8") as f:
237
+ raw_config = yaml.safe_load(f) or {}
238
+
239
+ # Type guard: reject non-mapping YAML payloads
240
+ # yaml.safe_load() can return list, str, int, etc. for valid YAML
241
+ # but runtime config must be a dict (mapping) for model validation
242
+ if not isinstance(raw_config, dict):
243
+ raise ProtocolConfigurationError(
244
+ f"Runtime config at {config_path} must be a YAML mapping (dict), "
245
+ f"got {type(raw_config).__name__}",
246
+ context=context,
247
+ config_path=str(config_path),
248
+ error_details=f"Expected dict, got {type(raw_config).__name__}",
249
+ )
250
+
251
+ # Contract validation: validate against schema before Pydantic
252
+ # This provides early, actionable error messages for pattern/range violations
253
+ contract_errors = validate_runtime_config(raw_config)
254
+ if contract_errors:
255
+ error_count = len(contract_errors)
256
+ # Create concise summary for log message (first 3 errors)
257
+ error_summary = "; ".join(contract_errors[:3])
258
+ if error_count > 3:
259
+ error_summary += f" (and {error_count - 3} more...)"
260
+ raise ProtocolConfigurationError(
261
+ f"Contract validation failed at {config_path}: {error_count} error(s). "
262
+ f"First errors: {error_summary}",
263
+ context=context,
264
+ config_path=str(config_path),
265
+ # Full error list for structured debugging (not truncated)
266
+ validation_errors=contract_errors,
267
+ error_count=error_count,
268
+ )
269
+ logger.debug(
270
+ "Contract validation passed (correlation_id=%s)",
271
+ effective_correlation_id,
272
+ )
273
+
274
+ config = ModelRuntimeConfig.model_validate(raw_config)
275
+ logger.debug(
276
+ "Runtime config loaded successfully (correlation_id=%s)",
277
+ effective_correlation_id,
278
+ extra={
279
+ "input_topic": config.input_topic,
280
+ "output_topic": config.output_topic,
281
+ "consumer_group": config.consumer_group,
282
+ "event_bus_type": config.event_bus.type,
283
+ },
284
+ )
285
+ return config
286
+ except yaml.YAMLError as e:
287
+ raise ProtocolConfigurationError(
288
+ f"Failed to parse runtime config YAML at {config_path}: {e}",
289
+ context=context,
290
+ config_path=str(config_path),
291
+ error_details=str(e),
292
+ ) from e
293
+ except ValidationError as e:
294
+ # Extract validation error details for actionable error messages
295
+ error_count = e.error_count()
296
+ # Convert Pydantic errors to list[str] for consistency with contract validation
297
+ # Both validation_errors fields should have the same type: list[str]
298
+ pydantic_errors = [
299
+ f"{'.'.join(str(loc) for loc in err['loc'])}: {err['msg']}"
300
+ for err in e.errors()
301
+ ]
302
+ error_summary = "; ".join(pydantic_errors[:3])
303
+ raise ProtocolConfigurationError(
304
+ f"Runtime config validation failed at {config_path}: {error_count} error(s). "
305
+ f"First errors: {error_summary}",
306
+ context=context,
307
+ config_path=str(config_path),
308
+ validation_errors=pydantic_errors,
309
+ error_count=error_count,
310
+ ) from e
311
+ except UnicodeDecodeError as e:
312
+ raise ProtocolConfigurationError(
313
+ f"Runtime config file contains binary or non-UTF-8 content: {config_path}",
314
+ context=context,
315
+ config_path=str(config_path),
316
+ error_details=f"Encoding error at position {e.start}-{e.end}: {e.reason}",
317
+ ) from e
318
+ except OSError as e:
319
+ raise ProtocolConfigurationError(
320
+ f"Failed to read runtime config at {config_path}: {e}",
321
+ context=context,
322
+ config_path=str(config_path),
323
+ error_details=str(e),
324
+ ) from e
325
+
326
+ # No config file - use environment variables and defaults
327
+ logger.info(
328
+ "No runtime config found at %s, using environment/defaults (correlation_id=%s)",
329
+ config_path,
330
+ effective_correlation_id,
331
+ )
332
+ config = ModelRuntimeConfig(
333
+ input_topic=os.getenv("ONEX_INPUT_TOPIC", DEFAULT_INPUT_TOPIC),
334
+ output_topic=os.getenv("ONEX_OUTPUT_TOPIC", DEFAULT_OUTPUT_TOPIC),
335
+ consumer_group=os.getenv("ONEX_GROUP_ID", DEFAULT_GROUP_ID),
336
+ )
337
+ logger.debug(
338
+ "Runtime config constructed from environment/defaults (correlation_id=%s)",
339
+ effective_correlation_id,
340
+ extra={
341
+ "input_topic": config.input_topic,
342
+ "output_topic": config.output_topic,
343
+ "consumer_group": config.consumer_group,
344
+ },
345
+ )
346
+ return config
347
+
348
+
349
+ async def bootstrap() -> int:
350
+ """Bootstrap the ONEX runtime from contracts.
351
+
352
+ This is the main async entrypoint that orchestrates the complete runtime
353
+ initialization and lifecycle management. The bootstrap process follows a
354
+ structured sequence to ensure proper resource initialization and cleanup.
355
+
356
+ Bootstrap Sequence:
357
+ 1. Determine contracts directory from ONEX_CONTRACTS_DIR environment variable
358
+ 2. Load and validate runtime configuration from contracts or environment
359
+ 3. Create and initialize event bus (EventBusInmemory or EventBusKafka based on config)
360
+ 4. Create ModelONEXContainer and wire infrastructure services (async)
361
+ 5. Resolve RegistryProtocolBinding from container (async)
362
+ 6. Instantiate RuntimeHostProcess with validated configuration and pre-resolved registry
363
+ 7. Setup graceful shutdown signal handlers (SIGINT, SIGTERM)
364
+ 8. Start runtime and HTTP health server for Docker/Kubernetes health probes
365
+ 9. Run runtime until shutdown signal received
366
+ 10. Perform graceful shutdown with configurable timeout
367
+ 11. Clean up resources in finally block to prevent resource leaks
368
+
369
+ Error Handling:
370
+ - Configuration errors: Logged with full context and correlation_id
371
+ - Runtime errors: Caught and logged with detailed error information
372
+ - Unexpected errors: Logged with exception details for debugging
373
+ - All errors include correlation_id for distributed tracing
374
+
375
+ Shutdown Behavior:
376
+ - Health server stopped first (fast, non-blocking operation)
377
+ - Runtime stopped with configurable grace period (default: 30s)
378
+ - Timeout enforcement prevents indefinite shutdown hangs
379
+ - Finally block ensures cleanup even on unexpected errors
380
+
381
+ Returns:
382
+ Exit code (0 for success, non-zero for errors).
383
+ - 0: Clean shutdown after successful operation
384
+ - 1: Configuration error, runtime error, or unexpected failure
385
+
386
+ Environment Variables:
387
+ ONEX_CONTRACTS_DIR: Path to contracts directory (default: ./contracts)
388
+ ONEX_HTTP_PORT: Port for health check server (default: 8085)
389
+ ONEX_LOG_LEVEL: Logging level (default: INFO)
390
+ ONEX_ENVIRONMENT: Environment name (default: local)
391
+ ONEX_INPUT_TOPIC: Input topic override (default: requests)
392
+ ONEX_OUTPUT_TOPIC: Output topic override (default: responses)
393
+ ONEX_GROUP_ID: Consumer group override (default: onex-runtime)
394
+
395
+ Example:
396
+ >>> # Run bootstrap and handle exit code
397
+ >>> exit_code = await bootstrap()
398
+ >>> if exit_code == 0:
399
+ ... print("Runtime shutdown successfully")
400
+ ... else:
401
+ ... print("Runtime encountered errors")
402
+
403
+ Example Startup Log:
404
+ ============================================================
405
+ ONEX Runtime Kernel v0.1.0
406
+ Environment: production
407
+ Contracts: /app/contracts
408
+ Event Bus: inmemory (group: onex-runtime)
409
+ Topics: requests → responses
410
+ Health endpoint: http://0.0.0.0:8085/health
411
+ ============================================================
412
+ """
413
+ # Lazy import to break circular dependency chain - see "Circular Import Note"
414
+ # comment near line 98 for detailed explanation of the import cycle.
415
+ from omnibase_infra.services.service_health import (
416
+ DEFAULT_HTTP_PORT,
417
+ ServiceHealth,
418
+ )
419
+
420
+ # Initialize resources to None for cleanup guard in finally block
421
+ runtime: RuntimeHostProcess | None = None
422
+ health_server: ServiceHealth | None = None
423
+ postgres_pool: asyncpg.Pool | None = None
424
+ introspection_unsubscribe: Callable[[], Awaitable[None]] | None = None
425
+ correlation_id = generate_correlation_id()
426
+ bootstrap_start_time = time.time()
427
+
428
+ try:
429
+ # 1. Determine contracts directory
430
+ contracts_dir = _get_contracts_dir()
431
+ logger.info(
432
+ "ONEX Kernel starting with contracts_dir=%s (correlation_id=%s)",
433
+ contracts_dir,
434
+ correlation_id,
435
+ )
436
+
437
+ # 2. Load runtime configuration (may raise ProtocolConfigurationError)
438
+ # Pass correlation_id for consistent tracing across initialization sequence
439
+ config_start_time = time.time()
440
+ config = load_runtime_config(contracts_dir, correlation_id=correlation_id)
441
+ config_duration = time.time() - config_start_time
442
+ # Log only safe config fields (no credentials or sensitive data)
443
+ # Full config.model_dump() could leak passwords, API keys, connection strings
444
+ logger.debug(
445
+ "Runtime config loaded in %.3fs (correlation_id=%s)",
446
+ config_duration,
447
+ correlation_id,
448
+ extra={
449
+ "duration_seconds": config_duration,
450
+ "input_topic": config.input_topic,
451
+ "output_topic": config.output_topic,
452
+ "consumer_group": config.consumer_group,
453
+ "event_bus_type": config.event_bus.type,
454
+ "shutdown_grace_period": config.shutdown.grace_period_seconds,
455
+ },
456
+ )
457
+
458
+ # 3. Create event bus
459
+ # Dispatch based on configuration or environment variable:
460
+ # - If KAFKA_BOOTSTRAP_SERVERS env var is set, use EventBusKafka
461
+ # - If config.event_bus.type == "kafka", use EventBusKafka
462
+ # - Otherwise, use EventBusInmemory for local development/testing
463
+ # Environment override takes precedence over config for environment field.
464
+ environment = os.getenv("ONEX_ENVIRONMENT") or config.event_bus.environment
465
+ kafka_bootstrap_servers = os.getenv("KAFKA_BOOTSTRAP_SERVERS")
466
+
467
+ # Explicit bool evaluation (not truthy string) for kafka usage.
468
+ # KAFKA_BOOTSTRAP_SERVERS env var takes precedence over config.event_bus.type.
469
+ # This prevents implicit "kafka but localhost" fallback scenarios.
470
+ use_kafka: bool = (
471
+ bool(kafka_bootstrap_servers) or config.event_bus.type == "kafka"
472
+ )
473
+
474
+ # Validate bootstrap_servers is provided when kafka is requested via config
475
+ # This prevents confusing implicit localhost:9092 fallback
476
+ if use_kafka and not kafka_bootstrap_servers:
477
+ context = ModelInfraErrorContext(
478
+ transport_type=EnumInfraTransportType.KAFKA,
479
+ operation="configure_event_bus",
480
+ correlation_id=correlation_id,
481
+ )
482
+ raise ProtocolConfigurationError(
483
+ "Kafka event bus requested (config.event_bus.type='kafka') but "
484
+ "KAFKA_BOOTSTRAP_SERVERS environment variable is not set. "
485
+ "Set KAFKA_BOOTSTRAP_SERVERS to the broker address (e.g., 'kafka:9092') "
486
+ "or use event_bus.type='inmemory' for local development.",
487
+ context=context,
488
+ parameter="KAFKA_BOOTSTRAP_SERVERS",
489
+ )
490
+
491
+ event_bus_start_time = time.time()
492
+ event_bus: EventBusInmemory | EventBusKafka
493
+ event_bus_type: str
494
+
495
+ if use_kafka:
496
+ # Use EventBusKafka for production/integration testing
497
+ # NOTE: bootstrap_servers is guaranteed non-empty at this point due to validation
498
+ # above, but mypy cannot narrow the Optional[str] type through control flow.
499
+ kafka_config = ModelKafkaEventBusConfig(
500
+ bootstrap_servers=kafka_bootstrap_servers, # type: ignore[arg-type] # NOTE: control flow narrowing limitation
501
+ environment=environment,
502
+ group=config.consumer_group,
503
+ circuit_breaker_threshold=config.event_bus.circuit_breaker_threshold,
504
+ )
505
+ event_bus = EventBusKafka(config=kafka_config)
506
+ event_bus_type = "kafka"
507
+
508
+ # Start EventBusKafka to connect to Kafka/Redpanda and enable consumers
509
+ # Without this, the event bus cannot publish or consume messages
510
+ try:
511
+ await event_bus.start()
512
+ logger.debug(
513
+ "EventBusKafka started successfully (correlation_id=%s)",
514
+ correlation_id,
515
+ )
516
+ except Exception as e:
517
+ context = ModelInfraErrorContext(
518
+ transport_type=EnumInfraTransportType.KAFKA,
519
+ operation="start_event_bus",
520
+ correlation_id=correlation_id,
521
+ target_name=kafka_bootstrap_servers,
522
+ )
523
+ raise RuntimeHostError(
524
+ f"Failed to start EventBusKafka: {sanitize_error_message(e)}",
525
+ context=context,
526
+ ) from e
527
+
528
+ logger.info(
529
+ "Using EventBusKafka (correlation_id=%s)",
530
+ correlation_id,
531
+ extra={
532
+ "bootstrap_servers": kafka_bootstrap_servers,
533
+ "environment": environment,
534
+ "consumer_group": config.consumer_group,
535
+ },
536
+ )
537
+ else:
538
+ # Use EventBusInmemory for local development/testing
539
+ event_bus = EventBusInmemory(
540
+ environment=environment,
541
+ group=config.consumer_group,
542
+ )
543
+ event_bus_type = "inmemory"
544
+
545
+ event_bus_duration = time.time() - event_bus_start_time
546
+ logger.debug(
547
+ "Event bus created in %.3fs (correlation_id=%s)",
548
+ event_bus_duration,
549
+ correlation_id,
550
+ extra={
551
+ "duration_seconds": event_bus_duration,
552
+ "event_bus_type": event_bus_type,
553
+ "environment": environment,
554
+ "consumer_group": config.consumer_group,
555
+ },
556
+ )
557
+
558
+ # 4. Create and wire container for dependency injection
559
+ container_start_time = time.time()
560
+ container = ModelONEXContainer()
561
+ if container.service_registry is None:
562
+ logger.warning(
563
+ "DEGRADED_MODE: service_registry is None (omnibase_core circular import bug?), "
564
+ "skipping container wiring (correlation_id=%s)",
565
+ correlation_id,
566
+ extra={
567
+ "error_type": "NoneType",
568
+ "correlation_id": correlation_id,
569
+ "degraded_mode": True,
570
+ "degraded_reason": "service_registry_unavailable",
571
+ "component": "container_wiring",
572
+ },
573
+ )
574
+ wire_summary: dict[str, list[str] | str] = {
575
+ "services": [],
576
+ "status": "degraded",
577
+ } # Empty summary for degraded mode
578
+ else:
579
+ try:
580
+ wire_summary = await wire_infrastructure_services(container)
581
+ except ServiceResolutionError as e:
582
+ # Service resolution failed during wiring - container configuration issue.
583
+ logger.warning(
584
+ "DEGRADED_MODE: Container wiring failed due to service resolution error, "
585
+ "continuing in degraded mode (correlation_id=%s): %s",
586
+ correlation_id,
587
+ e,
588
+ extra={
589
+ "error_type": type(e).__name__,
590
+ "correlation_id": correlation_id,
591
+ "degraded_mode": True,
592
+ "degraded_reason": "service_resolution_error",
593
+ "component": "container_wiring",
594
+ },
595
+ )
596
+ wire_summary = {"services": [], "status": "degraded"}
597
+ except (RuntimeError, AttributeError) as e:
598
+ # Unexpected error during wiring - container internals issue.
599
+ logger.warning(
600
+ "DEGRADED_MODE: Container wiring failed with unexpected error, "
601
+ "continuing in degraded mode (correlation_id=%s): %s",
602
+ correlation_id,
603
+ e,
604
+ extra={
605
+ "error_type": type(e).__name__,
606
+ "correlation_id": correlation_id,
607
+ "degraded_mode": True,
608
+ "degraded_reason": "wiring_error",
609
+ "component": "container_wiring",
610
+ },
611
+ )
612
+ wire_summary = {"services": [], "status": "degraded"}
613
+ container_duration = time.time() - container_start_time
614
+ logger.debug(
615
+ "Container wired in %.3fs (correlation_id=%s)",
616
+ container_duration,
617
+ correlation_id,
618
+ extra={
619
+ "duration_seconds": container_duration,
620
+ "services": wire_summary["services"],
621
+ },
622
+ )
623
+
624
+ # 4.5. Create PostgreSQL pool for projections
625
+ # Only create if POSTGRES_HOST is set (indicates registration should be enabled)
626
+ projector: ProjectorShell | None = None
627
+ introspection_dispatcher: DispatcherNodeIntrospected | None = None
628
+ consul_handler = None # Will be initialized if Consul is configured
629
+
630
+ postgres_host = os.getenv("POSTGRES_HOST")
631
+ if postgres_host:
632
+ postgres_pool_start_time = time.time()
633
+ try:
634
+ postgres_pool = await asyncpg.create_pool(
635
+ user=os.getenv("POSTGRES_USER", "postgres"),
636
+ password=os.getenv("POSTGRES_PASSWORD", ""),
637
+ host=postgres_host,
638
+ port=int(os.getenv("POSTGRES_PORT", "5432")),
639
+ database=os.getenv("POSTGRES_DATABASE", "omninode_bridge"),
640
+ min_size=2,
641
+ max_size=10,
642
+ )
643
+ postgres_pool_duration = time.time() - postgres_pool_start_time
644
+ logger.info(
645
+ "PostgreSQL pool created in %.3fs (correlation_id=%s)",
646
+ postgres_pool_duration,
647
+ correlation_id,
648
+ extra={
649
+ "host": postgres_host,
650
+ "port": os.getenv("POSTGRES_PORT", "5432"),
651
+ "database": os.getenv("POSTGRES_DATABASE", "omninode_bridge"),
652
+ },
653
+ )
654
+
655
+ # 4.6. Load projectors from contracts via ProjectorPluginLoader (OMN-1170/1169)
656
+ #
657
+ # This section implements fully contract-driven projector management. The
658
+ # loader discovers projector contracts from the package's projectors/contracts
659
+ # directory and creates ProjectorShell instances for runtime use.
660
+ #
661
+ # Contract-driven approach:
662
+ # - Projector behavior defined in YAML contracts (registration_projector.yaml)
663
+ # - ProjectorPluginLoader discovers and loads projectors from contracts
664
+ # - ProjectorShell provides generic projection operations (project, partial_update)
665
+ # - Schema initialization is decoupled - SQL executed directly from schema file
666
+ #
667
+ # The registration projector is identified by projector_id="registration-projector"
668
+ # and is passed to wire_registration_handlers() for handler injection.
669
+ #
670
+ projector_contracts_dir = (
671
+ Path(__file__).parent.parent / "projectors" / "contracts"
672
+ )
673
+
674
+ # Try to discover projectors from contracts
675
+ projector_loader = ProjectorPluginLoader(
676
+ config=ModelProjectorPluginLoaderConfig(graceful_mode=True),
677
+ container=container,
678
+ pool=postgres_pool,
679
+ )
680
+
681
+ discovered_projectors: list[ProtocolEventProjector] = []
682
+ if projector_contracts_dir.exists():
683
+ try:
684
+ discovered_projectors = (
685
+ await projector_loader.load_from_directory(
686
+ projector_contracts_dir
687
+ )
688
+ )
689
+ if discovered_projectors:
690
+ logger.info(
691
+ "Discovered %d projector(s) from contracts (correlation_id=%s)",
692
+ len(discovered_projectors),
693
+ correlation_id,
694
+ extra={
695
+ "discovered_count": len(discovered_projectors),
696
+ "contracts_dir": str(projector_contracts_dir),
697
+ "projector_ids": [
698
+ getattr(p, "projector_id", "unknown")
699
+ for p in discovered_projectors
700
+ ],
701
+ },
702
+ )
703
+ else:
704
+ logger.warning(
705
+ "No projector contracts found in %s (correlation_id=%s)",
706
+ projector_contracts_dir,
707
+ correlation_id,
708
+ extra={
709
+ "contracts_dir": str(projector_contracts_dir),
710
+ },
711
+ )
712
+ except Exception as discovery_error:
713
+ # Log warning but continue - projector discovery is best-effort
714
+ # Registration features will be unavailable if discovery fails
715
+ logger.warning(
716
+ "Projector contract discovery failed: %s (correlation_id=%s)",
717
+ sanitize_error_message(discovery_error),
718
+ correlation_id,
719
+ extra={
720
+ "error_type": type(discovery_error).__name__,
721
+ "contracts_dir": str(projector_contracts_dir),
722
+ },
723
+ )
724
+ else:
725
+ logger.debug(
726
+ "Projector contracts directory not found, skipping discovery "
727
+ "(correlation_id=%s)",
728
+ correlation_id,
729
+ extra={
730
+ "contracts_dir": str(projector_contracts_dir),
731
+ },
732
+ )
733
+
734
+ # Extract registration projector from discovered projectors (OMN-1169)
735
+ # This replaces the legacy ProjectorRegistration with contract-loaded ProjectorShell
736
+ registration_projector_id = "registration-projector"
737
+ for discovered in discovered_projectors:
738
+ if (
739
+ getattr(discovered, "projector_id", None)
740
+ == registration_projector_id
741
+ ):
742
+ # Cast to ProjectorShell (loader creates ProjectorShell when pool provided)
743
+ if isinstance(discovered, ProjectorShell):
744
+ projector = discovered
745
+ logger.info(
746
+ "Using contract-loaded ProjectorShell for registration "
747
+ "(correlation_id=%s)",
748
+ correlation_id,
749
+ extra={
750
+ "projector_id": registration_projector_id,
751
+ "aggregate_type": projector.aggregate_type,
752
+ },
753
+ )
754
+ break
755
+
756
+ if projector is None:
757
+ # Fallback: No registration projector discovered from contracts
758
+ logger.warning(
759
+ "Registration projector not found in contracts, "
760
+ "registration features will be unavailable (correlation_id=%s)",
761
+ correlation_id,
762
+ extra={
763
+ "expected_projector_id": registration_projector_id,
764
+ "discovered_count": len(discovered_projectors),
765
+ },
766
+ )
767
+
768
+ # Initialize schema by executing SQL file directly
769
+ # Schema initialization is decoupled from the projector - it just ensures
770
+ # the table and indexes exist. The ProjectorShell uses the schema at runtime.
771
+ schema_file = (
772
+ Path(__file__).parent.parent
773
+ / "schemas"
774
+ / "schema_registration_projection.sql"
775
+ )
776
+ if schema_file.exists():
777
+ try:
778
+ schema_sql = schema_file.read_text()
779
+ async with postgres_pool.acquire() as conn:
780
+ await conn.execute(schema_sql)
781
+ logger.info(
782
+ "Registration projection schema initialized (correlation_id=%s)",
783
+ correlation_id,
784
+ )
785
+ except Exception as schema_error:
786
+ # Log warning but continue - schema may already exist
787
+ logger.warning(
788
+ "Schema initialization encountered error: %s (correlation_id=%s)",
789
+ sanitize_error_message(schema_error),
790
+ correlation_id,
791
+ extra={
792
+ "error_type": type(schema_error).__name__,
793
+ },
794
+ )
795
+ else:
796
+ logger.warning(
797
+ "Schema file not found: %s (correlation_id=%s)",
798
+ schema_file,
799
+ correlation_id,
800
+ )
801
+
802
+ # 4.6.5. Initialize HandlerConsul if Consul is configured
803
+ # CONSUL_HOST determines whether to enable Consul registration
804
+ consul_host = os.getenv("CONSUL_HOST")
805
+ if consul_host:
806
+ # Validate CONSUL_PORT environment variable
807
+ consul_port_str = os.getenv("CONSUL_PORT", "8500")
808
+ try:
809
+ consul_port = int(consul_port_str)
810
+ if not MIN_PORT <= consul_port <= MAX_PORT:
811
+ logger.warning(
812
+ "CONSUL_PORT %d outside valid range %d-%d, using default 8500 (correlation_id=%s)",
813
+ consul_port,
814
+ MIN_PORT,
815
+ MAX_PORT,
816
+ correlation_id,
817
+ )
818
+ consul_port = 8500
819
+ except ValueError:
820
+ logger.warning(
821
+ "Invalid CONSUL_PORT value '%s', using default 8500 (correlation_id=%s)",
822
+ consul_port_str,
823
+ correlation_id,
824
+ )
825
+ consul_port = 8500
826
+
827
+ try:
828
+ # Deferred import: Only load HandlerConsul when Consul is configured.
829
+ # This avoids loading the consul dependency (and its transitive deps)
830
+ # when Consul integration is disabled, reducing startup time.
831
+ from omnibase_infra.handlers import HandlerConsul
832
+
833
+ consul_handler = HandlerConsul()
834
+ await consul_handler.initialize(
835
+ {
836
+ "host": consul_host,
837
+ "port": consul_port,
838
+ }
839
+ )
840
+ logger.info(
841
+ "HandlerConsul initialized for dual registration (correlation_id=%s)",
842
+ correlation_id,
843
+ extra={
844
+ "consul_host": consul_host,
845
+ "consul_port": consul_port,
846
+ },
847
+ )
848
+ except Exception as consul_error:
849
+ # Log warning but continue without Consul (PostgreSQL is source of truth)
850
+ # Use sanitize_error_message to prevent credential leakage in logs
851
+ logger.warning(
852
+ "Failed to initialize HandlerConsul, proceeding without Consul: %s (correlation_id=%s)",
853
+ sanitize_error_message(consul_error),
854
+ correlation_id,
855
+ extra={
856
+ "error_type": type(consul_error).__name__,
857
+ },
858
+ )
859
+ consul_handler = None
860
+ else:
861
+ logger.debug(
862
+ "CONSUL_HOST not set, Consul registration disabled (correlation_id=%s)",
863
+ correlation_id,
864
+ )
865
+
866
+ # 4.7. Wire registration handlers with projector and consul_handler
867
+ registration_summary = await wire_registration_handlers(
868
+ container,
869
+ postgres_pool,
870
+ projector=projector,
871
+ consul_handler=consul_handler,
872
+ )
873
+ logger.info(
874
+ "Registration handlers wired (correlation_id=%s)",
875
+ correlation_id,
876
+ extra={
877
+ "services": registration_summary["services"],
878
+ },
879
+ )
880
+
881
+ # 4.8. Create introspection dispatcher for routing events
882
+ # Deferred import: HandlerNodeIntrospected depends on PostgreSQL and
883
+ # registration infrastructure. Only loaded after PostgreSQL pool is
884
+ # successfully created and registration handlers are wired.
885
+ from omnibase_infra.nodes.node_registration_orchestrator.handlers import (
886
+ HandlerNodeIntrospected,
887
+ )
888
+
889
+ # Check if service_registry is available (may be None in omnibase_core 0.6.x)
890
+ if container.service_registry is None:
891
+ logger.warning(
892
+ "DEGRADED_MODE: ServiceRegistry not available, skipping introspection dispatcher creation (correlation_id=%s)",
893
+ correlation_id,
894
+ extra={
895
+ "error_type": "NoneType",
896
+ "correlation_id": correlation_id,
897
+ "degraded_mode": True,
898
+ "degraded_reason": "service_registry_unavailable",
899
+ "component": "introspection_dispatcher",
900
+ },
901
+ )
902
+ # Set introspection_dispatcher to None and continue without it
903
+ introspection_dispatcher = None
904
+ else:
905
+ logger.debug(
906
+ "Resolving HandlerNodeIntrospected from container (correlation_id=%s)",
907
+ correlation_id,
908
+ )
909
+ handler_introspected: HandlerNodeIntrospected = (
910
+ await container.service_registry.resolve_service(
911
+ HandlerNodeIntrospected
912
+ )
913
+ )
914
+ logger.debug(
915
+ "HandlerNodeIntrospected resolved successfully (correlation_id=%s)",
916
+ correlation_id,
917
+ extra={
918
+ "handler_class": handler_introspected.__class__.__name__,
919
+ },
920
+ )
921
+
922
+ introspection_dispatcher = DispatcherNodeIntrospected(
923
+ handler_introspected
924
+ )
925
+ logger.info(
926
+ "Introspection dispatcher created and wired (correlation_id=%s)",
927
+ correlation_id,
928
+ extra={
929
+ "dispatcher_class": introspection_dispatcher.__class__.__name__,
930
+ "handler_class": handler_introspected.__class__.__name__,
931
+ },
932
+ )
933
+
934
+ except Exception as pool_error:
935
+ # Log warning but continue without registration support
936
+ # Use sanitize_error_message to prevent credential leakage in logs
937
+ # (PostgreSQL connection errors may include DSN with password)
938
+ logger.warning(
939
+ "Failed to initialize PostgreSQL pool for registration: %s (correlation_id=%s)",
940
+ sanitize_error_message(pool_error),
941
+ correlation_id,
942
+ extra={
943
+ "error_type": type(pool_error).__name__,
944
+ },
945
+ )
946
+ if postgres_pool is not None:
947
+ try:
948
+ await postgres_pool.close()
949
+ except Exception as cleanup_error:
950
+ # Sanitize cleanup errors to prevent credential leakage
951
+ # NOTE: Do NOT use exc_info=True here - tracebacks may contain
952
+ # connection strings with credentials from PostgreSQL errors
953
+ logger.warning(
954
+ "Cleanup failed for PostgreSQL pool close: %s (correlation_id=%s)",
955
+ sanitize_error_message(cleanup_error),
956
+ correlation_id,
957
+ )
958
+ postgres_pool = None
959
+ projector = None
960
+ introspection_dispatcher = None
961
+ else:
962
+ logger.debug(
963
+ "POSTGRES_HOST not set, skipping registration handler wiring (correlation_id=%s)",
964
+ correlation_id,
965
+ )
966
+
967
+ # 5. Resolve RegistryProtocolBinding from container or create new instance
968
+ # NOTE: Fallback to creating new instance is intentional degraded mode behavior.
969
+ # The handler registry is optional for basic runtime operation - core event
970
+ # processing continues even without explicit handler bindings. However,
971
+ # ProtocolConfigurationError should NOT be masked as it indicates invalid
972
+ # configuration that would cause undefined behavior.
973
+ handler_registry: RegistryProtocolBinding | None = None
974
+
975
+ # Check if service_registry is available (may be None in omnibase_core 0.6.x)
976
+ if container.service_registry is not None:
977
+ try:
978
+ handler_registry = await container.service_registry.resolve_service(
979
+ RegistryProtocolBinding
980
+ )
981
+ except ServiceResolutionError as e:
982
+ # Service not registered - expected in minimal configurations.
983
+ # Create a new instance directly as fallback.
984
+ logger.warning(
985
+ "DEGRADED_MODE: RegistryProtocolBinding not registered in container, "
986
+ "creating new instance (correlation_id=%s): %s",
987
+ correlation_id,
988
+ e,
989
+ extra={
990
+ "error_type": type(e).__name__,
991
+ "correlation_id": correlation_id,
992
+ "degraded_mode": True,
993
+ "degraded_reason": "service_not_registered",
994
+ "component": "handler_registry",
995
+ },
996
+ )
997
+ handler_registry = RegistryProtocolBinding()
998
+ except (RuntimeError, AttributeError) as e:
999
+ # Unexpected resolution failure - container internals issue.
1000
+ # Log with more diagnostic context but still allow degraded operation.
1001
+ logger.warning(
1002
+ "DEGRADED_MODE: Unexpected error resolving RegistryProtocolBinding, "
1003
+ "creating new instance (correlation_id=%s): %s",
1004
+ correlation_id,
1005
+ e,
1006
+ extra={
1007
+ "error_type": type(e).__name__,
1008
+ "correlation_id": correlation_id,
1009
+ "degraded_mode": True,
1010
+ "degraded_reason": "resolution_error",
1011
+ "component": "handler_registry",
1012
+ },
1013
+ )
1014
+ handler_registry = RegistryProtocolBinding()
1015
+ # NOTE: ProtocolConfigurationError is NOT caught here - configuration
1016
+ # errors should propagate and stop startup to prevent undefined behavior.
1017
+ else:
1018
+ # ServiceRegistry not available, create a new RegistryProtocolBinding directly
1019
+ logger.warning(
1020
+ "DEGRADED_MODE: ServiceRegistry not available, creating RegistryProtocolBinding directly (correlation_id=%s)",
1021
+ correlation_id,
1022
+ extra={
1023
+ "error_type": "NoneType",
1024
+ "correlation_id": correlation_id,
1025
+ "degraded_mode": True,
1026
+ "degraded_reason": "service_registry_unavailable",
1027
+ "component": "handler_registry",
1028
+ },
1029
+ )
1030
+ handler_registry = RegistryProtocolBinding()
1031
+
1032
+ # 6. Create runtime host process with config and pre-resolved registry
1033
+ # RuntimeHostProcess accepts config as dict; cast model_dump() result to
1034
+ # dict[str, object] to avoid implicit Any typing (Pydantic's model_dump()
1035
+ # returns dict[str, Any] but all our model fields are strongly typed)
1036
+ runtime_create_start_time = time.time()
1037
+ runtime = RuntimeHostProcess(
1038
+ container=container,
1039
+ event_bus=event_bus,
1040
+ input_topic=config.input_topic,
1041
+ output_topic=config.output_topic,
1042
+ config=cast("dict[str, object]", config.model_dump()),
1043
+ handler_registry=handler_registry,
1044
+ # Pass contracts directory for handler discovery (OMN-1317)
1045
+ # This enables contract-based handler registration instead of
1046
+ # falling back to wire_handlers() with an empty registry
1047
+ contract_paths=[str(contracts_dir)],
1048
+ )
1049
+ runtime_create_duration = time.time() - runtime_create_start_time
1050
+ logger.debug(
1051
+ "Runtime host process created in %.3fs (correlation_id=%s)",
1052
+ runtime_create_duration,
1053
+ correlation_id,
1054
+ extra={
1055
+ "duration_seconds": runtime_create_duration,
1056
+ "input_topic": config.input_topic,
1057
+ "output_topic": config.output_topic,
1058
+ },
1059
+ )
1060
+
1061
+ # 7. Setup graceful shutdown
1062
+ shutdown_event = asyncio.Event()
1063
+ loop = asyncio.get_running_loop()
1064
+
1065
+ def handle_shutdown(sig: signal.Signals) -> None:
1066
+ """Handle shutdown signal with correlation tracking."""
1067
+ logger.info(
1068
+ "Received %s, initiating graceful shutdown... (correlation_id=%s)",
1069
+ sig.name,
1070
+ correlation_id,
1071
+ )
1072
+ shutdown_event.set()
1073
+
1074
+ # Register signal handlers for graceful shutdown
1075
+ if sys.platform != "win32":
1076
+ # Unix: Use asyncio's signal handler for proper event loop integration
1077
+ for sig in (signal.SIGINT, signal.SIGTERM):
1078
+ loop.add_signal_handler(sig, handle_shutdown, sig)
1079
+ else:
1080
+ # Windows: asyncio signal handlers not supported, use signal.signal()
1081
+ # for SIGINT (Ctrl+C). Note: SIGTERM not available on Windows.
1082
+ #
1083
+ # Thread-safety: On Windows, signal.signal() handlers execute in a
1084
+ # different thread than the event loop. While asyncio.Event.set() is
1085
+ # documented as thread-safe, we use loop.call_soon_threadsafe() to
1086
+ # schedule the set() call on the event loop thread. This ensures
1087
+ # proper cross-thread communication and avoids potential race
1088
+ # conditions with any event loop state inspection.
1089
+ def windows_handler(signum: int, frame: object) -> None:
1090
+ """Windows-compatible signal handler wrapper.
1091
+
1092
+ Uses call_soon_threadsafe to safely communicate with the event
1093
+ loop from the signal handler thread.
1094
+ """
1095
+ sig = signal.Signals(signum)
1096
+ logger.info(
1097
+ "Received %s, initiating graceful shutdown... (correlation_id=%s)",
1098
+ sig.name,
1099
+ correlation_id,
1100
+ )
1101
+ loop.call_soon_threadsafe(shutdown_event.set)
1102
+
1103
+ signal.signal(signal.SIGINT, windows_handler)
1104
+
1105
+ # 8. Start runtime and health server
1106
+ runtime_start_time = time.time()
1107
+ logger.info(
1108
+ "Starting ONEX runtime... (correlation_id=%s)",
1109
+ correlation_id,
1110
+ )
1111
+ await runtime.start()
1112
+ runtime_start_duration = time.time() - runtime_start_time
1113
+ logger.debug(
1114
+ "Runtime started in %.3fs (correlation_id=%s)",
1115
+ runtime_start_duration,
1116
+ correlation_id,
1117
+ extra={
1118
+ "duration_seconds": runtime_start_duration,
1119
+ },
1120
+ )
1121
+
1122
+ # 9. Start HTTP health server for Docker/K8s probes
1123
+ # Port can be configured via ONEX_HTTP_PORT environment variable
1124
+ http_port_str = os.getenv("ONEX_HTTP_PORT", str(DEFAULT_HTTP_PORT))
1125
+ try:
1126
+ http_port = int(http_port_str)
1127
+ if not MIN_PORT <= http_port <= MAX_PORT:
1128
+ logger.warning(
1129
+ "ONEX_HTTP_PORT %d outside valid range %d-%d, using default %d (correlation_id=%s)",
1130
+ http_port,
1131
+ MIN_PORT,
1132
+ MAX_PORT,
1133
+ DEFAULT_HTTP_PORT,
1134
+ correlation_id,
1135
+ )
1136
+ http_port = DEFAULT_HTTP_PORT
1137
+ except ValueError:
1138
+ logger.warning(
1139
+ "Invalid ONEX_HTTP_PORT value '%s', using default %d (correlation_id=%s)",
1140
+ http_port_str,
1141
+ DEFAULT_HTTP_PORT,
1142
+ correlation_id,
1143
+ )
1144
+ http_port = DEFAULT_HTTP_PORT
1145
+
1146
+ health_server = ServiceHealth(
1147
+ container=container,
1148
+ runtime=runtime,
1149
+ port=http_port,
1150
+ version=KERNEL_VERSION,
1151
+ )
1152
+ health_start_time = time.time()
1153
+ await health_server.start()
1154
+ health_start_duration = time.time() - health_start_time
1155
+ logger.debug(
1156
+ "Health server started in %.3fs (correlation_id=%s)",
1157
+ health_start_duration,
1158
+ correlation_id,
1159
+ extra={
1160
+ "duration_seconds": health_start_duration,
1161
+ "port": http_port,
1162
+ },
1163
+ )
1164
+
1165
+ # 9.5. Start introspection event consumer if dispatcher is available
1166
+ # This consumer subscribes to the input topic and routes introspection
1167
+ # events to the HandlerNodeIntrospected via DispatcherNodeIntrospected.
1168
+ # Unlike RuntimeHostProcess which routes based on handler_type field,
1169
+ # this consumer directly parses introspection events from JSON.
1170
+ #
1171
+ # The message handler is extracted to IntrospectionMessageHandler for
1172
+ # better testability and separation of concerns (PR #101 code quality).
1173
+ #
1174
+ # Duck typing approach per CLAUDE.md architectural guidelines:
1175
+ # Check for subscribe() capability via hasattr/callable instead of isinstance.
1176
+ # This enables any event bus implementing subscribe() to participate in
1177
+ # introspection event consumption, following protocol-based polymorphism.
1178
+ #
1179
+ # Production considerations:
1180
+ # - EventBusKafka: Uses distributed consumer groups for production workloads
1181
+ # - EventBusInmemory: subscribe() works for testing scenarios
1182
+ # - Other implementations: Will work if they implement subscribe()
1183
+ #
1184
+ # The duck typing approach allows new event bus implementations to
1185
+ # participate in introspection without modifying this code.
1186
+ has_subscribe = hasattr(event_bus, "subscribe") and callable(
1187
+ getattr(event_bus, "subscribe", None)
1188
+ )
1189
+ if introspection_dispatcher is not None and has_subscribe:
1190
+ # Create extracted event router with container-based DI pattern
1191
+ # Dependencies are passed explicitly since they are created at runtime
1192
+ # by the kernel and may not be registered in the container yet
1193
+ introspection_event_router = IntrospectionEventRouter(
1194
+ container=container,
1195
+ output_topic=config.output_topic,
1196
+ dispatcher=introspection_dispatcher,
1197
+ event_bus=event_bus,
1198
+ )
1199
+
1200
+ # Subscribe with callback - returns unsubscribe function
1201
+ subscribe_start_time = time.time()
1202
+ logger.info(
1203
+ "Subscribing to introspection events on event bus (correlation_id=%s)",
1204
+ correlation_id,
1205
+ extra={
1206
+ "topic": config.input_topic,
1207
+ "consumer_group": f"{config.consumer_group}-introspection",
1208
+ "event_bus_type": event_bus_type,
1209
+ },
1210
+ )
1211
+
1212
+ introspection_unsubscribe = await event_bus.subscribe(
1213
+ topic=config.input_topic,
1214
+ group_id=f"{config.consumer_group}-introspection",
1215
+ on_message=introspection_event_router.handle_message,
1216
+ )
1217
+ subscribe_duration = time.time() - subscribe_start_time
1218
+
1219
+ logger.info(
1220
+ "Introspection event consumer started successfully in %.3fs (correlation_id=%s)",
1221
+ subscribe_duration,
1222
+ correlation_id,
1223
+ extra={
1224
+ "topic": config.input_topic,
1225
+ "consumer_group": f"{config.consumer_group}-introspection",
1226
+ "subscribe_duration_seconds": subscribe_duration,
1227
+ "event_bus_type": event_bus_type,
1228
+ },
1229
+ )
1230
+
1231
+ # Calculate total bootstrap time
1232
+ bootstrap_duration = time.time() - bootstrap_start_time
1233
+
1234
+ # Display startup banner with key configuration
1235
+ if introspection_dispatcher is not None:
1236
+ if consul_handler is not None:
1237
+ registration_status = "enabled (PostgreSQL + Consul)"
1238
+ else:
1239
+ registration_status = "enabled (PostgreSQL only)"
1240
+ else:
1241
+ registration_status = "disabled"
1242
+ banner_lines = [
1243
+ "=" * 60,
1244
+ f"ONEX Runtime Kernel v{KERNEL_VERSION}",
1245
+ f"Environment: {environment}",
1246
+ f"Contracts: {contracts_dir}",
1247
+ f"Event Bus: {event_bus_type} (group: {config.consumer_group})",
1248
+ f"Topics: {config.input_topic} → {config.output_topic}",
1249
+ f"Registration: {registration_status}",
1250
+ f"Health endpoint: http://0.0.0.0:{http_port}/health",
1251
+ f"Bootstrap time: {bootstrap_duration:.3f}s",
1252
+ f"Correlation ID: {correlation_id}",
1253
+ "=" * 60,
1254
+ ]
1255
+ banner = "\n".join(banner_lines)
1256
+ logger.info("\n%s", banner)
1257
+
1258
+ logger.info(
1259
+ "ONEX runtime started successfully in %.3fs (correlation_id=%s)",
1260
+ bootstrap_duration,
1261
+ correlation_id,
1262
+ extra={
1263
+ "bootstrap_duration_seconds": bootstrap_duration,
1264
+ "config_load_seconds": config_duration,
1265
+ "event_bus_create_seconds": event_bus_duration,
1266
+ "container_wire_seconds": container_duration,
1267
+ "runtime_create_seconds": runtime_create_duration,
1268
+ "runtime_start_seconds": runtime_start_duration,
1269
+ "health_start_seconds": health_start_duration,
1270
+ },
1271
+ )
1272
+
1273
+ # Wait for shutdown signal
1274
+ await shutdown_event.wait()
1275
+
1276
+ grace_period = config.shutdown.grace_period_seconds
1277
+ shutdown_start_time = time.time()
1278
+ logger.info(
1279
+ "Shutdown signal received, stopping runtime (timeout=%ss, correlation_id=%s)",
1280
+ grace_period,
1281
+ correlation_id,
1282
+ )
1283
+
1284
+ # Stop introspection consumer first (fast)
1285
+ if introspection_unsubscribe is not None:
1286
+ try:
1287
+ await introspection_unsubscribe()
1288
+ logger.debug(
1289
+ "Introspection consumer stopped (correlation_id=%s)",
1290
+ correlation_id,
1291
+ )
1292
+ except Exception as consumer_stop_error:
1293
+ logger.warning(
1294
+ "Failed to stop introspection consumer: %s (correlation_id=%s)",
1295
+ sanitize_error_message(consumer_stop_error),
1296
+ correlation_id,
1297
+ )
1298
+ introspection_unsubscribe = None
1299
+
1300
+ # Stop health server (fast, non-blocking)
1301
+ if health_server is not None:
1302
+ try:
1303
+ health_stop_start_time = time.time()
1304
+ await health_server.stop()
1305
+ health_stop_duration = time.time() - health_stop_start_time
1306
+ logger.debug(
1307
+ "Health server stopped in %.3fs (correlation_id=%s)",
1308
+ health_stop_duration,
1309
+ correlation_id,
1310
+ extra={
1311
+ "duration_seconds": health_stop_duration,
1312
+ },
1313
+ )
1314
+ except Exception as health_stop_error:
1315
+ logger.warning(
1316
+ "Failed to stop health server: %s (correlation_id=%s)",
1317
+ health_stop_error,
1318
+ correlation_id,
1319
+ extra={
1320
+ "error_type": type(health_stop_error).__name__,
1321
+ },
1322
+ )
1323
+ health_server = None
1324
+
1325
+ # Stop runtime with timeout
1326
+ try:
1327
+ runtime_stop_start_time = time.time()
1328
+ await asyncio.wait_for(runtime.stop(), timeout=grace_period)
1329
+ runtime_stop_duration = time.time() - runtime_stop_start_time
1330
+ logger.debug(
1331
+ "Runtime stopped in %.3fs (correlation_id=%s)",
1332
+ runtime_stop_duration,
1333
+ correlation_id,
1334
+ extra={
1335
+ "duration_seconds": runtime_stop_duration,
1336
+ },
1337
+ )
1338
+ except TimeoutError:
1339
+ logger.warning(
1340
+ "Graceful shutdown timed out after %s seconds, forcing stop (correlation_id=%s)",
1341
+ grace_period,
1342
+ correlation_id,
1343
+ )
1344
+ runtime = None # Mark as stopped to prevent double-stop in finally
1345
+
1346
+ # Close PostgreSQL pool
1347
+ if postgres_pool is not None:
1348
+ try:
1349
+ pool_close_start_time = time.time()
1350
+ await postgres_pool.close()
1351
+ pool_close_duration = time.time() - pool_close_start_time
1352
+ logger.debug(
1353
+ "PostgreSQL pool closed in %.3fs (correlation_id=%s)",
1354
+ pool_close_duration,
1355
+ correlation_id,
1356
+ )
1357
+ except Exception as pool_close_error:
1358
+ # Sanitize to prevent credential leakage
1359
+ logger.warning(
1360
+ "Failed to close PostgreSQL pool: %s (correlation_id=%s)",
1361
+ sanitize_error_message(pool_close_error),
1362
+ correlation_id,
1363
+ )
1364
+ postgres_pool = None
1365
+
1366
+ shutdown_duration = time.time() - shutdown_start_time
1367
+ logger.info(
1368
+ "ONEX runtime stopped successfully in %.3fs (correlation_id=%s)",
1369
+ shutdown_duration,
1370
+ correlation_id,
1371
+ extra={
1372
+ "shutdown_duration_seconds": shutdown_duration,
1373
+ },
1374
+ )
1375
+ return 0
1376
+
1377
+ except ProtocolConfigurationError as e:
1378
+ # Configuration errors already have proper context and chaining
1379
+ logger.exception(
1380
+ "ONEX runtime configuration failed (correlation_id=%s)",
1381
+ correlation_id,
1382
+ extra={
1383
+ "error_type": type(e).__name__,
1384
+ "error_code": e.model.error_code.name if hasattr(e, "model") else None,
1385
+ },
1386
+ )
1387
+ return 1
1388
+
1389
+ except RuntimeHostError as e:
1390
+ # Runtime host errors already have proper structure
1391
+ logger.exception(
1392
+ "ONEX runtime host error (correlation_id=%s)",
1393
+ correlation_id,
1394
+ extra={
1395
+ "error_type": type(e).__name__,
1396
+ "error_code": e.model.error_code.name if hasattr(e, "model") else None,
1397
+ },
1398
+ )
1399
+ return 1
1400
+
1401
+ except Exception as e:
1402
+ # Unexpected errors: log with full context and return error code
1403
+ # (consistent with ProtocolConfigurationError and RuntimeHostError handlers)
1404
+ # Sanitize error message to prevent credential leakage
1405
+ logger.exception(
1406
+ "ONEX runtime failed with unexpected error: %s (correlation_id=%s)",
1407
+ sanitize_error_message(e),
1408
+ correlation_id,
1409
+ extra={
1410
+ "error_type": type(e).__name__,
1411
+ },
1412
+ )
1413
+ return 1
1414
+
1415
+ finally:
1416
+ # Guard cleanup - stop all resources if not already stopped
1417
+ # Order: introspection consumer -> health server -> runtime -> pool
1418
+
1419
+ if introspection_unsubscribe is not None:
1420
+ try:
1421
+ await introspection_unsubscribe()
1422
+ except Exception as cleanup_error:
1423
+ logger.warning(
1424
+ "Failed to stop introspection consumer during cleanup: %s (correlation_id=%s)",
1425
+ sanitize_error_message(cleanup_error),
1426
+ correlation_id,
1427
+ )
1428
+
1429
+ if health_server is not None:
1430
+ try:
1431
+ await health_server.stop()
1432
+ except Exception as cleanup_error:
1433
+ logger.warning(
1434
+ "Failed to stop health server during cleanup: %s (correlation_id=%s)",
1435
+ sanitize_error_message(cleanup_error),
1436
+ correlation_id,
1437
+ )
1438
+
1439
+ if runtime is not None:
1440
+ try:
1441
+ await runtime.stop()
1442
+ except Exception as cleanup_error:
1443
+ # Log cleanup failures with context instead of suppressing them
1444
+ # Sanitize to prevent potential credential leakage from runtime errors
1445
+ logger.warning(
1446
+ "Failed to stop runtime during cleanup: %s (correlation_id=%s)",
1447
+ sanitize_error_message(cleanup_error),
1448
+ correlation_id,
1449
+ )
1450
+
1451
+ if postgres_pool is not None:
1452
+ try:
1453
+ await postgres_pool.close()
1454
+ except Exception as cleanup_error:
1455
+ # Sanitize to prevent credential leakage from PostgreSQL errors
1456
+ logger.warning(
1457
+ "Failed to close PostgreSQL pool during cleanup: %s (correlation_id=%s)",
1458
+ sanitize_error_message(cleanup_error),
1459
+ correlation_id,
1460
+ )
1461
+
1462
+
1463
+ def configure_logging() -> None:
1464
+ """Configure logging for the kernel with structured format.
1465
+
1466
+ Sets up structured logging with appropriate log level from the
1467
+ ONEX_LOG_LEVEL environment variable (default: INFO). This function
1468
+ must be called early in the bootstrap process to ensure logging
1469
+ is available for all subsequent operations.
1470
+
1471
+ Logging Configuration:
1472
+ - Log Level: Controlled by ONEX_LOG_LEVEL environment variable
1473
+ - Format: Timestamp, level, logger name, message, extras
1474
+ - Date Format: ISO-8601 compatible (YYYY-MM-DD HH:MM:SS)
1475
+ - Structured Extras: Support for correlation_id and custom fields
1476
+
1477
+ Bootstrap Order Rationale:
1478
+ This function is called BEFORE runtime config is loaded because logging
1479
+ must be available during config loading itself (to log errors, warnings,
1480
+ and info about config discovery). Therefore, logging configuration uses
1481
+ environment variables rather than contract-based config values.
1482
+
1483
+ This is a deliberate chicken-and-egg solution:
1484
+ - Environment variables control early bootstrap logging
1485
+ - Contract config controls runtime behavior after bootstrap
1486
+
1487
+ Environment Variables:
1488
+ ONEX_LOG_LEVEL: Logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
1489
+ Default: INFO
1490
+
1491
+ Log Format Example:
1492
+ 2025-01-15 10:30:45 [INFO] omnibase_infra.runtime.service_kernel: ONEX Kernel v0.1.0
1493
+ 2025-01-15 10:30:45 [DEBUG] omnibase_infra.runtime.service_kernel: Runtime config loaded
1494
+ (correlation_id=123e4567-e89b-12d3-a456-426614174000)
1495
+
1496
+ Structured Logging Extras:
1497
+ All log calls support structured extras for observability:
1498
+ - correlation_id: UUID for distributed tracing
1499
+ - duration_seconds: Operation timing metrics
1500
+ - error_type: Exception class name for error analysis
1501
+ - Custom fields: Any JSON-serializable data
1502
+
1503
+ Example:
1504
+ >>> configure_logging()
1505
+ >>> logger.info("Operation completed", extra={"duration_seconds": 1.234})
1506
+ """
1507
+ log_level = os.getenv("ONEX_LOG_LEVEL", "INFO").upper()
1508
+
1509
+ # Validate log level and provide helpful error if invalid
1510
+ valid_levels = {"DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"}
1511
+ if log_level not in valid_levels:
1512
+ print(
1513
+ f"Warning: Invalid ONEX_LOG_LEVEL '{log_level}', using INFO. "
1514
+ f"Valid levels: {', '.join(sorted(valid_levels))}",
1515
+ file=sys.stderr,
1516
+ )
1517
+ log_level = "INFO"
1518
+
1519
+ logging.basicConfig(
1520
+ level=getattr(logging, log_level, logging.INFO),
1521
+ format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
1522
+ datefmt="%Y-%m-%d %H:%M:%S",
1523
+ )
1524
+
1525
+
1526
+ def main() -> None:
1527
+ """Entry point for the ONEX runtime kernel.
1528
+
1529
+ This is the synchronous entry point for the kernel. It configures
1530
+ logging, initiates the async bootstrap process, and handles the
1531
+ final exit code.
1532
+
1533
+ Execution Flow:
1534
+ 1. Configure logging from environment variables
1535
+ 2. Log kernel version for startup identification
1536
+ 3. Run async bootstrap function in event loop
1537
+ 4. Exit with appropriate exit code (0=success, 1=error)
1538
+
1539
+ Exit Codes:
1540
+ 0: Successful startup and clean shutdown
1541
+ 1: Configuration error, runtime error, or unexpected failure
1542
+
1543
+ This function is the target for:
1544
+ - The installed entrypoint: `onex-runtime`
1545
+ - Direct module execution: `python -m omnibase_infra.runtime.service_kernel`
1546
+ - Docker CMD/ENTRYPOINT in container deployments
1547
+
1548
+ Example:
1549
+ >>> # From command line
1550
+ >>> python -m omnibase_infra.runtime.service_kernel
1551
+ >>> # Or via installed entrypoint
1552
+ >>> onex-runtime
1553
+
1554
+ Docker Usage:
1555
+ CMD ["onex-runtime"]
1556
+ # Container will start runtime and expose health endpoint
1557
+ """
1558
+ configure_logging()
1559
+ logger.info("ONEX Kernel v%s initializing...", KERNEL_VERSION)
1560
+ exit_code = asyncio.run(bootstrap())
1561
+ sys.exit(exit_code)
1562
+
1563
+
1564
+ if __name__ == "__main__":
1565
+ main()
1566
+
1567
+
1568
+ __all__: list[str] = [
1569
+ "ENV_CONTRACTS_DIR",
1570
+ "bootstrap",
1571
+ "load_runtime_config",
1572
+ "main",
1573
+ ]