omnibase_infra 0.2.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- omnibase_infra/__init__.py +101 -0
- omnibase_infra/adapters/adapter_onex_tool_execution.py +451 -0
- omnibase_infra/capabilities/__init__.py +15 -0
- omnibase_infra/capabilities/capability_inference_rules.py +211 -0
- omnibase_infra/capabilities/contract_capability_extractor.py +221 -0
- omnibase_infra/capabilities/intent_type_extractor.py +160 -0
- omnibase_infra/cli/__init__.py +1 -0
- omnibase_infra/cli/commands.py +216 -0
- omnibase_infra/clients/__init__.py +0 -0
- omnibase_infra/configs/widget_mapping.yaml +176 -0
- omnibase_infra/constants_topic_patterns.py +26 -0
- omnibase_infra/contracts/handlers/filesystem/handler_contract.yaml +264 -0
- omnibase_infra/contracts/handlers/mcp/handler_contract.yaml +141 -0
- omnibase_infra/decorators/__init__.py +29 -0
- omnibase_infra/decorators/allow_any.py +109 -0
- omnibase_infra/dlq/__init__.py +90 -0
- omnibase_infra/dlq/constants_dlq.py +57 -0
- omnibase_infra/dlq/models/__init__.py +26 -0
- omnibase_infra/dlq/models/enum_replay_status.py +37 -0
- omnibase_infra/dlq/models/model_dlq_replay_record.py +135 -0
- omnibase_infra/dlq/models/model_dlq_tracking_config.py +184 -0
- omnibase_infra/dlq/service_dlq_tracking.py +611 -0
- omnibase_infra/enums/__init__.py +132 -0
- omnibase_infra/enums/enum_any_type_violation.py +104 -0
- omnibase_infra/enums/enum_backend_type.py +27 -0
- omnibase_infra/enums/enum_capture_outcome.py +42 -0
- omnibase_infra/enums/enum_capture_state.py +88 -0
- omnibase_infra/enums/enum_chain_violation_type.py +119 -0
- omnibase_infra/enums/enum_circuit_state.py +51 -0
- omnibase_infra/enums/enum_confirmation_event_type.py +27 -0
- omnibase_infra/enums/enum_consumer_group_purpose.py +92 -0
- omnibase_infra/enums/enum_contract_type.py +84 -0
- omnibase_infra/enums/enum_dedupe_strategy.py +46 -0
- omnibase_infra/enums/enum_dispatch_status.py +191 -0
- omnibase_infra/enums/enum_environment.py +46 -0
- omnibase_infra/enums/enum_execution_shape_violation.py +103 -0
- omnibase_infra/enums/enum_handler_error_type.py +111 -0
- omnibase_infra/enums/enum_handler_loader_error.py +178 -0
- omnibase_infra/enums/enum_handler_source_mode.py +86 -0
- omnibase_infra/enums/enum_handler_source_type.py +87 -0
- omnibase_infra/enums/enum_handler_type.py +77 -0
- omnibase_infra/enums/enum_handler_type_category.py +61 -0
- omnibase_infra/enums/enum_infra_transport_type.py +73 -0
- omnibase_infra/enums/enum_introspection_reason.py +154 -0
- omnibase_infra/enums/enum_kafka_acks.py +99 -0
- omnibase_infra/enums/enum_message_category.py +213 -0
- omnibase_infra/enums/enum_node_archetype.py +74 -0
- omnibase_infra/enums/enum_node_output_type.py +185 -0
- omnibase_infra/enums/enum_non_retryable_error_category.py +224 -0
- omnibase_infra/enums/enum_policy_type.py +32 -0
- omnibase_infra/enums/enum_registration_state.py +261 -0
- omnibase_infra/enums/enum_registration_status.py +33 -0
- omnibase_infra/enums/enum_registry_response_status.py +28 -0
- omnibase_infra/enums/enum_response_status.py +26 -0
- omnibase_infra/enums/enum_retry_error_category.py +98 -0
- omnibase_infra/enums/enum_security_rule_id.py +103 -0
- omnibase_infra/enums/enum_selection_strategy.py +91 -0
- omnibase_infra/enums/enum_topic_standard.py +42 -0
- omnibase_infra/enums/enum_validation_severity.py +78 -0
- omnibase_infra/errors/__init__.py +160 -0
- omnibase_infra/errors/error_architecture_violation.py +152 -0
- omnibase_infra/errors/error_binding_resolution.py +128 -0
- omnibase_infra/errors/error_chain_propagation.py +188 -0
- omnibase_infra/errors/error_compute_registry.py +95 -0
- omnibase_infra/errors/error_consul.py +132 -0
- omnibase_infra/errors/error_container_wiring.py +243 -0
- omnibase_infra/errors/error_event_bus_registry.py +105 -0
- omnibase_infra/errors/error_infra.py +610 -0
- omnibase_infra/errors/error_message_type_registry.py +101 -0
- omnibase_infra/errors/error_policy_registry.py +115 -0
- omnibase_infra/errors/error_vault.py +123 -0
- omnibase_infra/event_bus/__init__.py +72 -0
- omnibase_infra/event_bus/configs/kafka_event_bus_config.yaml +84 -0
- omnibase_infra/event_bus/event_bus_inmemory.py +797 -0
- omnibase_infra/event_bus/event_bus_kafka.py +1716 -0
- omnibase_infra/event_bus/mixin_kafka_broadcast.py +180 -0
- omnibase_infra/event_bus/mixin_kafka_dlq.py +771 -0
- omnibase_infra/event_bus/models/__init__.py +29 -0
- omnibase_infra/event_bus/models/config/__init__.py +20 -0
- omnibase_infra/event_bus/models/config/model_kafka_event_bus_config.py +693 -0
- omnibase_infra/event_bus/models/model_dlq_event.py +206 -0
- omnibase_infra/event_bus/models/model_dlq_metrics.py +304 -0
- omnibase_infra/event_bus/models/model_event_headers.py +115 -0
- omnibase_infra/event_bus/models/model_event_message.py +60 -0
- omnibase_infra/event_bus/testing/__init__.py +26 -0
- omnibase_infra/event_bus/testing/adapter_protocol_event_publisher_inmemory.py +418 -0
- omnibase_infra/event_bus/testing/model_publisher_metrics.py +64 -0
- omnibase_infra/event_bus/topic_constants.py +376 -0
- omnibase_infra/handlers/__init__.py +82 -0
- omnibase_infra/handlers/filesystem/__init__.py +48 -0
- omnibase_infra/handlers/filesystem/enum_file_system_operation.py +35 -0
- omnibase_infra/handlers/filesystem/model_file_system_request.py +298 -0
- omnibase_infra/handlers/filesystem/model_file_system_result.py +166 -0
- omnibase_infra/handlers/handler_consul.py +795 -0
- omnibase_infra/handlers/handler_db.py +1046 -0
- omnibase_infra/handlers/handler_filesystem.py +1478 -0
- omnibase_infra/handlers/handler_graph.py +2015 -0
- omnibase_infra/handlers/handler_http.py +926 -0
- omnibase_infra/handlers/handler_intent.py +387 -0
- omnibase_infra/handlers/handler_manifest_persistence.contract.yaml +184 -0
- omnibase_infra/handlers/handler_manifest_persistence.py +1539 -0
- omnibase_infra/handlers/handler_mcp.py +1430 -0
- omnibase_infra/handlers/handler_qdrant.py +1076 -0
- omnibase_infra/handlers/handler_vault.py +428 -0
- omnibase_infra/handlers/mcp/__init__.py +19 -0
- omnibase_infra/handlers/mcp/adapter_onex_to_mcp.py +446 -0
- omnibase_infra/handlers/mcp/protocols.py +178 -0
- omnibase_infra/handlers/mcp/transport_streamable_http.py +352 -0
- omnibase_infra/handlers/mixins/__init__.py +47 -0
- omnibase_infra/handlers/mixins/mixin_consul_initialization.py +349 -0
- omnibase_infra/handlers/mixins/mixin_consul_kv.py +338 -0
- omnibase_infra/handlers/mixins/mixin_consul_service.py +542 -0
- omnibase_infra/handlers/mixins/mixin_consul_topic_index.py +585 -0
- omnibase_infra/handlers/mixins/mixin_vault_initialization.py +338 -0
- omnibase_infra/handlers/mixins/mixin_vault_retry.py +412 -0
- omnibase_infra/handlers/mixins/mixin_vault_secrets.py +450 -0
- omnibase_infra/handlers/mixins/mixin_vault_token.py +365 -0
- omnibase_infra/handlers/models/__init__.py +286 -0
- omnibase_infra/handlers/models/consul/__init__.py +81 -0
- omnibase_infra/handlers/models/consul/enum_consul_operation_type.py +57 -0
- omnibase_infra/handlers/models/consul/model_consul_deregister_payload.py +51 -0
- omnibase_infra/handlers/models/consul/model_consul_handler_config.py +153 -0
- omnibase_infra/handlers/models/consul/model_consul_handler_payload.py +89 -0
- omnibase_infra/handlers/models/consul/model_consul_kv_get_found_payload.py +55 -0
- omnibase_infra/handlers/models/consul/model_consul_kv_get_not_found_payload.py +49 -0
- omnibase_infra/handlers/models/consul/model_consul_kv_get_recurse_payload.py +50 -0
- omnibase_infra/handlers/models/consul/model_consul_kv_item.py +33 -0
- omnibase_infra/handlers/models/consul/model_consul_kv_put_payload.py +41 -0
- omnibase_infra/handlers/models/consul/model_consul_register_payload.py +53 -0
- omnibase_infra/handlers/models/consul/model_consul_retry_config.py +66 -0
- omnibase_infra/handlers/models/consul/model_payload_consul.py +66 -0
- omnibase_infra/handlers/models/consul/registry_payload_consul.py +214 -0
- omnibase_infra/handlers/models/graph/__init__.py +35 -0
- omnibase_infra/handlers/models/graph/enum_graph_operation_type.py +20 -0
- omnibase_infra/handlers/models/graph/model_graph_execute_payload.py +38 -0
- omnibase_infra/handlers/models/graph/model_graph_handler_config.py +54 -0
- omnibase_infra/handlers/models/graph/model_graph_handler_payload.py +44 -0
- omnibase_infra/handlers/models/graph/model_graph_query_payload.py +40 -0
- omnibase_infra/handlers/models/graph/model_graph_record.py +22 -0
- omnibase_infra/handlers/models/http/__init__.py +50 -0
- omnibase_infra/handlers/models/http/enum_http_operation_type.py +29 -0
- omnibase_infra/handlers/models/http/model_http_body_content.py +45 -0
- omnibase_infra/handlers/models/http/model_http_get_payload.py +88 -0
- omnibase_infra/handlers/models/http/model_http_handler_payload.py +90 -0
- omnibase_infra/handlers/models/http/model_http_post_payload.py +88 -0
- omnibase_infra/handlers/models/http/model_payload_http.py +66 -0
- omnibase_infra/handlers/models/http/registry_payload_http.py +212 -0
- omnibase_infra/handlers/models/mcp/__init__.py +23 -0
- omnibase_infra/handlers/models/mcp/enum_mcp_operation_type.py +24 -0
- omnibase_infra/handlers/models/mcp/model_mcp_handler_config.py +40 -0
- omnibase_infra/handlers/models/mcp/model_mcp_tool_call.py +32 -0
- omnibase_infra/handlers/models/mcp/model_mcp_tool_result.py +45 -0
- omnibase_infra/handlers/models/model_consul_handler_response.py +96 -0
- omnibase_infra/handlers/models/model_db_describe_response.py +83 -0
- omnibase_infra/handlers/models/model_db_query_payload.py +95 -0
- omnibase_infra/handlers/models/model_db_query_response.py +60 -0
- omnibase_infra/handlers/models/model_filesystem_config.py +98 -0
- omnibase_infra/handlers/models/model_filesystem_delete_payload.py +54 -0
- omnibase_infra/handlers/models/model_filesystem_delete_result.py +77 -0
- omnibase_infra/handlers/models/model_filesystem_directory_entry.py +75 -0
- omnibase_infra/handlers/models/model_filesystem_ensure_directory_payload.py +54 -0
- omnibase_infra/handlers/models/model_filesystem_ensure_directory_result.py +60 -0
- omnibase_infra/handlers/models/model_filesystem_list_directory_payload.py +60 -0
- omnibase_infra/handlers/models/model_filesystem_list_directory_result.py +68 -0
- omnibase_infra/handlers/models/model_filesystem_read_payload.py +62 -0
- omnibase_infra/handlers/models/model_filesystem_read_result.py +61 -0
- omnibase_infra/handlers/models/model_filesystem_write_payload.py +70 -0
- omnibase_infra/handlers/models/model_filesystem_write_result.py +55 -0
- omnibase_infra/handlers/models/model_graph_handler_response.py +98 -0
- omnibase_infra/handlers/models/model_handler_response.py +103 -0
- omnibase_infra/handlers/models/model_http_handler_response.py +101 -0
- omnibase_infra/handlers/models/model_manifest_metadata.py +75 -0
- omnibase_infra/handlers/models/model_manifest_persistence_config.py +62 -0
- omnibase_infra/handlers/models/model_manifest_query_payload.py +90 -0
- omnibase_infra/handlers/models/model_manifest_query_result.py +97 -0
- omnibase_infra/handlers/models/model_manifest_retrieve_payload.py +44 -0
- omnibase_infra/handlers/models/model_manifest_retrieve_result.py +98 -0
- omnibase_infra/handlers/models/model_manifest_store_payload.py +47 -0
- omnibase_infra/handlers/models/model_manifest_store_result.py +67 -0
- omnibase_infra/handlers/models/model_operation_context.py +187 -0
- omnibase_infra/handlers/models/model_qdrant_handler_response.py +98 -0
- omnibase_infra/handlers/models/model_retry_state.py +162 -0
- omnibase_infra/handlers/models/model_vault_handler_response.py +98 -0
- omnibase_infra/handlers/models/qdrant/__init__.py +44 -0
- omnibase_infra/handlers/models/qdrant/enum_qdrant_operation_type.py +26 -0
- omnibase_infra/handlers/models/qdrant/model_qdrant_collection_payload.py +42 -0
- omnibase_infra/handlers/models/qdrant/model_qdrant_delete_payload.py +36 -0
- omnibase_infra/handlers/models/qdrant/model_qdrant_handler_config.py +42 -0
- omnibase_infra/handlers/models/qdrant/model_qdrant_handler_payload.py +54 -0
- omnibase_infra/handlers/models/qdrant/model_qdrant_search_payload.py +42 -0
- omnibase_infra/handlers/models/qdrant/model_qdrant_search_result.py +30 -0
- omnibase_infra/handlers/models/qdrant/model_qdrant_upsert_payload.py +36 -0
- omnibase_infra/handlers/models/vault/__init__.py +69 -0
- omnibase_infra/handlers/models/vault/enum_vault_operation_type.py +35 -0
- omnibase_infra/handlers/models/vault/model_payload_vault.py +66 -0
- omnibase_infra/handlers/models/vault/model_vault_delete_payload.py +57 -0
- omnibase_infra/handlers/models/vault/model_vault_handler_config.py +148 -0
- omnibase_infra/handlers/models/vault/model_vault_handler_payload.py +101 -0
- omnibase_infra/handlers/models/vault/model_vault_list_payload.py +58 -0
- omnibase_infra/handlers/models/vault/model_vault_renew_token_payload.py +67 -0
- omnibase_infra/handlers/models/vault/model_vault_retry_config.py +66 -0
- omnibase_infra/handlers/models/vault/model_vault_secret_payload.py +106 -0
- omnibase_infra/handlers/models/vault/model_vault_write_payload.py +66 -0
- omnibase_infra/handlers/models/vault/registry_payload_vault.py +213 -0
- omnibase_infra/handlers/registration_storage/__init__.py +43 -0
- omnibase_infra/handlers/registration_storage/handler_registration_storage_mock.py +392 -0
- omnibase_infra/handlers/registration_storage/handler_registration_storage_postgres.py +922 -0
- omnibase_infra/handlers/registration_storage/models/__init__.py +23 -0
- omnibase_infra/handlers/registration_storage/models/model_delete_registration_request.py +58 -0
- omnibase_infra/handlers/registration_storage/models/model_update_registration_request.py +73 -0
- omnibase_infra/handlers/registration_storage/protocol_registration_persistence.py +191 -0
- omnibase_infra/handlers/service_discovery/__init__.py +43 -0
- omnibase_infra/handlers/service_discovery/handler_service_discovery_consul.py +1051 -0
- omnibase_infra/handlers/service_discovery/handler_service_discovery_mock.py +258 -0
- omnibase_infra/handlers/service_discovery/models/__init__.py +22 -0
- omnibase_infra/handlers/service_discovery/models/model_discovery_result.py +64 -0
- omnibase_infra/handlers/service_discovery/models/model_registration_result.py +138 -0
- omnibase_infra/handlers/service_discovery/models/model_service_info.py +109 -0
- omnibase_infra/handlers/service_discovery/protocol_discovery_operations.py +170 -0
- omnibase_infra/idempotency/__init__.py +94 -0
- omnibase_infra/idempotency/models/__init__.py +43 -0
- omnibase_infra/idempotency/models/model_idempotency_check_result.py +85 -0
- omnibase_infra/idempotency/models/model_idempotency_guard_config.py +130 -0
- omnibase_infra/idempotency/models/model_idempotency_record.py +86 -0
- omnibase_infra/idempotency/models/model_idempotency_store_health_check_result.py +81 -0
- omnibase_infra/idempotency/models/model_idempotency_store_metrics.py +140 -0
- omnibase_infra/idempotency/models/model_postgres_idempotency_store_config.py +299 -0
- omnibase_infra/idempotency/protocol_idempotency_store.py +184 -0
- omnibase_infra/idempotency/store_inmemory.py +265 -0
- omnibase_infra/idempotency/store_postgres.py +923 -0
- omnibase_infra/infrastructure/__init__.py +0 -0
- omnibase_infra/migrations/001_create_event_ledger.sql +166 -0
- omnibase_infra/migrations/001_drop_event_ledger.sql +18 -0
- omnibase_infra/mixins/__init__.py +71 -0
- omnibase_infra/mixins/mixin_async_circuit_breaker.py +656 -0
- omnibase_infra/mixins/mixin_dict_like_accessors.py +146 -0
- omnibase_infra/mixins/mixin_envelope_extraction.py +119 -0
- omnibase_infra/mixins/mixin_node_introspection.py +2670 -0
- omnibase_infra/mixins/mixin_retry_execution.py +386 -0
- omnibase_infra/mixins/protocol_circuit_breaker_aware.py +133 -0
- omnibase_infra/models/__init__.py +144 -0
- omnibase_infra/models/bindings/__init__.py +59 -0
- omnibase_infra/models/bindings/constants.py +144 -0
- omnibase_infra/models/bindings/model_binding_resolution_result.py +103 -0
- omnibase_infra/models/bindings/model_operation_binding.py +44 -0
- omnibase_infra/models/bindings/model_operation_bindings_subcontract.py +152 -0
- omnibase_infra/models/bindings/model_parsed_binding.py +52 -0
- omnibase_infra/models/corpus/__init__.py +17 -0
- omnibase_infra/models/corpus/model_capture_config.py +133 -0
- omnibase_infra/models/corpus/model_capture_result.py +86 -0
- omnibase_infra/models/discovery/__init__.py +42 -0
- omnibase_infra/models/discovery/model_dependency_spec.py +319 -0
- omnibase_infra/models/discovery/model_discovered_capabilities.py +50 -0
- omnibase_infra/models/discovery/model_introspection_config.py +330 -0
- omnibase_infra/models/discovery/model_introspection_performance_metrics.py +169 -0
- omnibase_infra/models/discovery/model_introspection_task_config.py +116 -0
- omnibase_infra/models/dispatch/__init__.py +155 -0
- omnibase_infra/models/dispatch/model_debug_trace_snapshot.py +114 -0
- omnibase_infra/models/dispatch/model_dispatch_context.py +439 -0
- omnibase_infra/models/dispatch/model_dispatch_error.py +336 -0
- omnibase_infra/models/dispatch/model_dispatch_log_context.py +400 -0
- omnibase_infra/models/dispatch/model_dispatch_metadata.py +228 -0
- omnibase_infra/models/dispatch/model_dispatch_metrics.py +496 -0
- omnibase_infra/models/dispatch/model_dispatch_outcome.py +317 -0
- omnibase_infra/models/dispatch/model_dispatch_outputs.py +231 -0
- omnibase_infra/models/dispatch/model_dispatch_result.py +436 -0
- omnibase_infra/models/dispatch/model_dispatch_route.py +279 -0
- omnibase_infra/models/dispatch/model_dispatcher_metrics.py +275 -0
- omnibase_infra/models/dispatch/model_dispatcher_registration.py +352 -0
- omnibase_infra/models/dispatch/model_materialized_dispatch.py +141 -0
- omnibase_infra/models/dispatch/model_parsed_topic.py +135 -0
- omnibase_infra/models/dispatch/model_topic_parser.py +725 -0
- omnibase_infra/models/dispatch/model_tracing_context.py +285 -0
- omnibase_infra/models/errors/__init__.py +45 -0
- omnibase_infra/models/errors/model_handler_validation_error.py +594 -0
- omnibase_infra/models/errors/model_infra_error_context.py +99 -0
- omnibase_infra/models/errors/model_message_type_registry_error_context.py +71 -0
- omnibase_infra/models/errors/model_timeout_error_context.py +110 -0
- omnibase_infra/models/handlers/__init__.py +80 -0
- omnibase_infra/models/handlers/model_bootstrap_handler_descriptor.py +162 -0
- omnibase_infra/models/handlers/model_contract_discovery_result.py +82 -0
- omnibase_infra/models/handlers/model_handler_descriptor.py +200 -0
- omnibase_infra/models/handlers/model_handler_identifier.py +215 -0
- omnibase_infra/models/handlers/model_handler_source_config.py +220 -0
- omnibase_infra/models/health/__init__.py +9 -0
- omnibase_infra/models/health/model_health_check_result.py +40 -0
- omnibase_infra/models/lifecycle/__init__.py +39 -0
- omnibase_infra/models/logging/__init__.py +51 -0
- omnibase_infra/models/logging/model_log_context.py +756 -0
- omnibase_infra/models/mcp/__init__.py +15 -0
- omnibase_infra/models/mcp/model_mcp_contract_config.py +80 -0
- omnibase_infra/models/mcp/model_mcp_server_config.py +67 -0
- omnibase_infra/models/mcp/model_mcp_tool_definition.py +73 -0
- omnibase_infra/models/mcp/model_mcp_tool_parameter.py +35 -0
- omnibase_infra/models/model_node_identity.py +126 -0
- omnibase_infra/models/model_retry_error_classification.py +78 -0
- omnibase_infra/models/projection/__init__.py +43 -0
- omnibase_infra/models/projection/model_capability_fields.py +112 -0
- omnibase_infra/models/projection/model_registration_projection.py +434 -0
- omnibase_infra/models/projection/model_registration_snapshot.py +322 -0
- omnibase_infra/models/projection/model_sequence_info.py +182 -0
- omnibase_infra/models/projection/model_snapshot_topic_config.py +591 -0
- omnibase_infra/models/projectors/__init__.py +41 -0
- omnibase_infra/models/projectors/model_projector_column.py +289 -0
- omnibase_infra/models/projectors/model_projector_discovery_result.py +65 -0
- omnibase_infra/models/projectors/model_projector_index.py +270 -0
- omnibase_infra/models/projectors/model_projector_schema.py +415 -0
- omnibase_infra/models/projectors/model_projector_validation_error.py +63 -0
- omnibase_infra/models/projectors/util_sql_identifiers.py +115 -0
- omnibase_infra/models/registration/__init__.py +68 -0
- omnibase_infra/models/registration/commands/__init__.py +15 -0
- omnibase_infra/models/registration/commands/model_node_registration_acked.py +108 -0
- omnibase_infra/models/registration/events/__init__.py +56 -0
- omnibase_infra/models/registration/events/model_node_became_active.py +103 -0
- omnibase_infra/models/registration/events/model_node_liveness_expired.py +103 -0
- omnibase_infra/models/registration/events/model_node_registration_accepted.py +98 -0
- omnibase_infra/models/registration/events/model_node_registration_ack_received.py +98 -0
- omnibase_infra/models/registration/events/model_node_registration_ack_timed_out.py +112 -0
- omnibase_infra/models/registration/events/model_node_registration_initiated.py +107 -0
- omnibase_infra/models/registration/events/model_node_registration_rejected.py +104 -0
- omnibase_infra/models/registration/model_event_bus_topic_entry.py +59 -0
- omnibase_infra/models/registration/model_introspection_metrics.py +253 -0
- omnibase_infra/models/registration/model_node_capabilities.py +190 -0
- omnibase_infra/models/registration/model_node_event_bus_config.py +99 -0
- omnibase_infra/models/registration/model_node_heartbeat_event.py +126 -0
- omnibase_infra/models/registration/model_node_introspection_event.py +195 -0
- omnibase_infra/models/registration/model_node_metadata.py +79 -0
- omnibase_infra/models/registration/model_node_registration.py +162 -0
- omnibase_infra/models/registration/model_node_registration_record.py +162 -0
- omnibase_infra/models/registry/__init__.py +29 -0
- omnibase_infra/models/registry/model_domain_constraint.py +202 -0
- omnibase_infra/models/registry/model_message_type_entry.py +271 -0
- omnibase_infra/models/resilience/__init__.py +9 -0
- omnibase_infra/models/resilience/model_circuit_breaker_config.py +227 -0
- omnibase_infra/models/routing/__init__.py +25 -0
- omnibase_infra/models/routing/model_routing_entry.py +52 -0
- omnibase_infra/models/routing/model_routing_subcontract.py +70 -0
- omnibase_infra/models/runtime/__init__.py +49 -0
- omnibase_infra/models/runtime/model_contract_security_config.py +41 -0
- omnibase_infra/models/runtime/model_discovery_error.py +81 -0
- omnibase_infra/models/runtime/model_discovery_result.py +162 -0
- omnibase_infra/models/runtime/model_discovery_warning.py +74 -0
- omnibase_infra/models/runtime/model_failed_plugin_load.py +63 -0
- omnibase_infra/models/runtime/model_handler_contract.py +296 -0
- omnibase_infra/models/runtime/model_loaded_handler.py +129 -0
- omnibase_infra/models/runtime/model_plugin_load_context.py +93 -0
- omnibase_infra/models/runtime/model_plugin_load_summary.py +124 -0
- omnibase_infra/models/security/__init__.py +50 -0
- omnibase_infra/models/security/classification_levels.py +99 -0
- omnibase_infra/models/security/model_environment_policy.py +145 -0
- omnibase_infra/models/security/model_handler_security_policy.py +107 -0
- omnibase_infra/models/security/model_security_error.py +81 -0
- omnibase_infra/models/security/model_security_validation_result.py +328 -0
- omnibase_infra/models/security/model_security_warning.py +67 -0
- omnibase_infra/models/snapshot/__init__.py +27 -0
- omnibase_infra/models/snapshot/model_field_change.py +65 -0
- omnibase_infra/models/snapshot/model_snapshot.py +270 -0
- omnibase_infra/models/snapshot/model_snapshot_diff.py +203 -0
- omnibase_infra/models/snapshot/model_subject_ref.py +81 -0
- omnibase_infra/models/types/__init__.py +71 -0
- omnibase_infra/models/validation/__init__.py +89 -0
- omnibase_infra/models/validation/model_any_type_validation_result.py +118 -0
- omnibase_infra/models/validation/model_any_type_violation.py +141 -0
- omnibase_infra/models/validation/model_category_match_result.py +345 -0
- omnibase_infra/models/validation/model_chain_violation.py +166 -0
- omnibase_infra/models/validation/model_coverage_metrics.py +316 -0
- omnibase_infra/models/validation/model_execution_shape_rule.py +159 -0
- omnibase_infra/models/validation/model_execution_shape_validation.py +208 -0
- omnibase_infra/models/validation/model_execution_shape_validation_result.py +294 -0
- omnibase_infra/models/validation/model_execution_shape_violation.py +122 -0
- omnibase_infra/models/validation/model_localhandler_validation_result.py +139 -0
- omnibase_infra/models/validation/model_localhandler_violation.py +100 -0
- omnibase_infra/models/validation/model_output_validation_params.py +74 -0
- omnibase_infra/models/validation/model_validate_and_raise_params.py +84 -0
- omnibase_infra/models/validation/model_validation_error_params.py +84 -0
- omnibase_infra/models/validation/model_validation_outcome.py +287 -0
- omnibase_infra/nodes/__init__.py +57 -0
- omnibase_infra/nodes/architecture_validator/__init__.py +79 -0
- omnibase_infra/nodes/architecture_validator/contract.yaml +252 -0
- omnibase_infra/nodes/architecture_validator/contract_architecture_validator.yaml +203 -0
- omnibase_infra/nodes/architecture_validator/mixins/__init__.py +16 -0
- omnibase_infra/nodes/architecture_validator/mixins/mixin_file_path_rule.py +92 -0
- omnibase_infra/nodes/architecture_validator/models/__init__.py +36 -0
- omnibase_infra/nodes/architecture_validator/models/model_architecture_validation_request.py +56 -0
- omnibase_infra/nodes/architecture_validator/models/model_architecture_validation_result.py +311 -0
- omnibase_infra/nodes/architecture_validator/models/model_architecture_violation.py +163 -0
- omnibase_infra/nodes/architecture_validator/models/model_rule_check_result.py +265 -0
- omnibase_infra/nodes/architecture_validator/models/model_validation_request.py +105 -0
- omnibase_infra/nodes/architecture_validator/models/model_validation_result.py +314 -0
- omnibase_infra/nodes/architecture_validator/node.py +262 -0
- omnibase_infra/nodes/architecture_validator/node_architecture_validator.py +383 -0
- omnibase_infra/nodes/architecture_validator/protocols/__init__.py +9 -0
- omnibase_infra/nodes/architecture_validator/protocols/protocol_architecture_rule.py +225 -0
- omnibase_infra/nodes/architecture_validator/registry/__init__.py +28 -0
- omnibase_infra/nodes/architecture_validator/registry/registry_infra_architecture_validator.py +106 -0
- omnibase_infra/nodes/architecture_validator/validators/__init__.py +104 -0
- omnibase_infra/nodes/architecture_validator/validators/validator_no_direct_dispatch.py +422 -0
- omnibase_infra/nodes/architecture_validator/validators/validator_no_handler_publishing.py +481 -0
- omnibase_infra/nodes/architecture_validator/validators/validator_no_orchestrator_fsm.py +491 -0
- omnibase_infra/nodes/contract_registry_reducer/__init__.py +29 -0
- omnibase_infra/nodes/contract_registry_reducer/contract.yaml +255 -0
- omnibase_infra/nodes/contract_registry_reducer/models/__init__.py +38 -0
- omnibase_infra/nodes/contract_registry_reducer/models/model_contract_registry_state.py +266 -0
- omnibase_infra/nodes/contract_registry_reducer/models/model_payload_cleanup_topic_references.py +55 -0
- omnibase_infra/nodes/contract_registry_reducer/models/model_payload_deactivate_contract.py +58 -0
- omnibase_infra/nodes/contract_registry_reducer/models/model_payload_mark_stale.py +49 -0
- omnibase_infra/nodes/contract_registry_reducer/models/model_payload_update_heartbeat.py +71 -0
- omnibase_infra/nodes/contract_registry_reducer/models/model_payload_update_topic.py +66 -0
- omnibase_infra/nodes/contract_registry_reducer/models/model_payload_upsert_contract.py +92 -0
- omnibase_infra/nodes/contract_registry_reducer/node.py +121 -0
- omnibase_infra/nodes/contract_registry_reducer/reducer.py +784 -0
- omnibase_infra/nodes/contract_registry_reducer/registry/__init__.py +9 -0
- omnibase_infra/nodes/contract_registry_reducer/registry/registry_infra_contract_registry_reducer.py +101 -0
- omnibase_infra/nodes/effects/README.md +358 -0
- omnibase_infra/nodes/effects/__init__.py +26 -0
- omnibase_infra/nodes/effects/contract.yaml +167 -0
- omnibase_infra/nodes/effects/models/__init__.py +32 -0
- omnibase_infra/nodes/effects/models/model_backend_result.py +190 -0
- omnibase_infra/nodes/effects/models/model_effect_idempotency_config.py +92 -0
- omnibase_infra/nodes/effects/models/model_registry_request.py +132 -0
- omnibase_infra/nodes/effects/models/model_registry_response.py +263 -0
- omnibase_infra/nodes/effects/protocol_consul_client.py +89 -0
- omnibase_infra/nodes/effects/protocol_effect_idempotency_store.py +143 -0
- omnibase_infra/nodes/effects/protocol_postgres_adapter.py +96 -0
- omnibase_infra/nodes/effects/registry_effect.py +525 -0
- omnibase_infra/nodes/effects/store_effect_idempotency_inmemory.py +425 -0
- omnibase_infra/nodes/handlers/consul/contract.yaml +85 -0
- omnibase_infra/nodes/handlers/db/contract.yaml +72 -0
- omnibase_infra/nodes/handlers/graph/contract.yaml +127 -0
- omnibase_infra/nodes/handlers/http/contract.yaml +74 -0
- omnibase_infra/nodes/handlers/intent/contract.yaml +66 -0
- omnibase_infra/nodes/handlers/mcp/contract.yaml +69 -0
- omnibase_infra/nodes/handlers/vault/contract.yaml +91 -0
- omnibase_infra/nodes/node_intent_storage_effect/__init__.py +50 -0
- omnibase_infra/nodes/node_intent_storage_effect/contract.yaml +194 -0
- omnibase_infra/nodes/node_intent_storage_effect/models/__init__.py +24 -0
- omnibase_infra/nodes/node_intent_storage_effect/models/model_intent_storage_input.py +141 -0
- omnibase_infra/nodes/node_intent_storage_effect/models/model_intent_storage_output.py +130 -0
- omnibase_infra/nodes/node_intent_storage_effect/node.py +94 -0
- omnibase_infra/nodes/node_intent_storage_effect/registry/__init__.py +35 -0
- omnibase_infra/nodes/node_intent_storage_effect/registry/registry_infra_intent_storage.py +294 -0
- omnibase_infra/nodes/node_ledger_projection_compute/__init__.py +50 -0
- omnibase_infra/nodes/node_ledger_projection_compute/contract.yaml +104 -0
- omnibase_infra/nodes/node_ledger_projection_compute/node.py +284 -0
- omnibase_infra/nodes/node_ledger_projection_compute/registry/__init__.py +29 -0
- omnibase_infra/nodes/node_ledger_projection_compute/registry/registry_infra_ledger_projection.py +118 -0
- omnibase_infra/nodes/node_ledger_write_effect/__init__.py +82 -0
- omnibase_infra/nodes/node_ledger_write_effect/contract.yaml +200 -0
- omnibase_infra/nodes/node_ledger_write_effect/handlers/__init__.py +22 -0
- omnibase_infra/nodes/node_ledger_write_effect/handlers/handler_ledger_append.py +372 -0
- omnibase_infra/nodes/node_ledger_write_effect/handlers/handler_ledger_query.py +597 -0
- omnibase_infra/nodes/node_ledger_write_effect/models/__init__.py +31 -0
- omnibase_infra/nodes/node_ledger_write_effect/models/model_ledger_append_result.py +54 -0
- omnibase_infra/nodes/node_ledger_write_effect/models/model_ledger_entry.py +92 -0
- omnibase_infra/nodes/node_ledger_write_effect/models/model_ledger_query.py +53 -0
- omnibase_infra/nodes/node_ledger_write_effect/models/model_ledger_query_result.py +41 -0
- omnibase_infra/nodes/node_ledger_write_effect/node.py +89 -0
- omnibase_infra/nodes/node_ledger_write_effect/protocols/__init__.py +13 -0
- omnibase_infra/nodes/node_ledger_write_effect/protocols/protocol_ledger_persistence.py +127 -0
- omnibase_infra/nodes/node_ledger_write_effect/registry/__init__.py +9 -0
- omnibase_infra/nodes/node_ledger_write_effect/registry/registry_infra_ledger_write.py +121 -0
- omnibase_infra/nodes/node_registration_orchestrator/README.md +542 -0
- omnibase_infra/nodes/node_registration_orchestrator/__init__.py +120 -0
- omnibase_infra/nodes/node_registration_orchestrator/contract.yaml +482 -0
- omnibase_infra/nodes/node_registration_orchestrator/dispatchers/__init__.py +53 -0
- omnibase_infra/nodes/node_registration_orchestrator/dispatchers/dispatcher_node_introspected.py +376 -0
- omnibase_infra/nodes/node_registration_orchestrator/dispatchers/dispatcher_node_registration_acked.py +376 -0
- omnibase_infra/nodes/node_registration_orchestrator/dispatchers/dispatcher_runtime_tick.py +373 -0
- omnibase_infra/nodes/node_registration_orchestrator/handlers/__init__.py +62 -0
- omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_heartbeat.py +376 -0
- omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_introspected.py +694 -0
- omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_registration_acked.py +458 -0
- omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_runtime_tick.py +364 -0
- omnibase_infra/nodes/node_registration_orchestrator/introspection_event_router.py +544 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/__init__.py +75 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_consul_intent_payload.py +194 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_consul_registration_intent.py +67 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_intent_execution_result.py +50 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_node_liveness_expired.py +107 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_orchestrator_config.py +67 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_orchestrator_input.py +41 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_orchestrator_output.py +166 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_postgres_intent_payload.py +235 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_postgres_upsert_intent.py +68 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_reducer_execution_result.py +384 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_reducer_state.py +60 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_registration_intent.py +177 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_registry_intent.py +247 -0
- omnibase_infra/nodes/node_registration_orchestrator/node.py +195 -0
- omnibase_infra/nodes/node_registration_orchestrator/plugin.py +909 -0
- omnibase_infra/nodes/node_registration_orchestrator/protocols.py +439 -0
- omnibase_infra/nodes/node_registration_orchestrator/registry/__init__.py +41 -0
- omnibase_infra/nodes/node_registration_orchestrator/registry/registry_infra_node_registration_orchestrator.py +528 -0
- omnibase_infra/nodes/node_registration_orchestrator/timeout_coordinator.py +393 -0
- omnibase_infra/nodes/node_registration_orchestrator/wiring.py +743 -0
- omnibase_infra/nodes/node_registration_reducer/__init__.py +15 -0
- omnibase_infra/nodes/node_registration_reducer/contract.yaml +301 -0
- omnibase_infra/nodes/node_registration_reducer/models/__init__.py +38 -0
- omnibase_infra/nodes/node_registration_reducer/models/model_validation_result.py +113 -0
- omnibase_infra/nodes/node_registration_reducer/node.py +139 -0
- omnibase_infra/nodes/node_registration_reducer/registry/__init__.py +9 -0
- omnibase_infra/nodes/node_registration_reducer/registry/registry_infra_node_registration_reducer.py +79 -0
- omnibase_infra/nodes/node_registration_storage_effect/__init__.py +41 -0
- omnibase_infra/nodes/node_registration_storage_effect/contract.yaml +220 -0
- omnibase_infra/nodes/node_registration_storage_effect/models/__init__.py +44 -0
- omnibase_infra/nodes/node_registration_storage_effect/models/model_delete_result.py +132 -0
- omnibase_infra/nodes/node_registration_storage_effect/models/model_registration_record.py +199 -0
- omnibase_infra/nodes/node_registration_storage_effect/models/model_registration_update.py +155 -0
- omnibase_infra/nodes/node_registration_storage_effect/models/model_storage_health_check_details.py +123 -0
- omnibase_infra/nodes/node_registration_storage_effect/models/model_storage_health_check_result.py +117 -0
- omnibase_infra/nodes/node_registration_storage_effect/models/model_storage_query.py +100 -0
- omnibase_infra/nodes/node_registration_storage_effect/models/model_storage_result.py +136 -0
- omnibase_infra/nodes/node_registration_storage_effect/models/model_upsert_result.py +127 -0
- omnibase_infra/nodes/node_registration_storage_effect/node.py +112 -0
- omnibase_infra/nodes/node_registration_storage_effect/protocols/__init__.py +22 -0
- omnibase_infra/nodes/node_registration_storage_effect/protocols/protocol_registration_persistence.py +333 -0
- omnibase_infra/nodes/node_registration_storage_effect/registry/__init__.py +23 -0
- omnibase_infra/nodes/node_registration_storage_effect/registry/registry_infra_registration_storage.py +215 -0
- omnibase_infra/nodes/node_registry_effect/__init__.py +85 -0
- omnibase_infra/nodes/node_registry_effect/contract.yaml +677 -0
- omnibase_infra/nodes/node_registry_effect/handlers/__init__.py +70 -0
- omnibase_infra/nodes/node_registry_effect/handlers/handler_consul_deregister.py +211 -0
- omnibase_infra/nodes/node_registry_effect/handlers/handler_consul_register.py +212 -0
- omnibase_infra/nodes/node_registry_effect/handlers/handler_partial_retry.py +417 -0
- omnibase_infra/nodes/node_registry_effect/handlers/handler_postgres_deactivate.py +215 -0
- omnibase_infra/nodes/node_registry_effect/handlers/handler_postgres_upsert.py +208 -0
- omnibase_infra/nodes/node_registry_effect/models/__init__.py +43 -0
- omnibase_infra/nodes/node_registry_effect/models/model_partial_retry_request.py +92 -0
- omnibase_infra/nodes/node_registry_effect/node.py +165 -0
- omnibase_infra/nodes/node_registry_effect/registry/__init__.py +27 -0
- omnibase_infra/nodes/node_registry_effect/registry/registry_infra_registry_effect.py +196 -0
- omnibase_infra/nodes/node_service_discovery_effect/__init__.py +111 -0
- omnibase_infra/nodes/node_service_discovery_effect/contract.yaml +246 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/__init__.py +67 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/enum_health_status.py +72 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/enum_service_discovery_operation.py +58 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/model_discovery_query.py +99 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/model_discovery_result.py +98 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/model_health_check_config.py +121 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/model_query_metadata.py +63 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/model_registration_result.py +130 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/model_service_discovery_health_check_details.py +111 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/model_service_discovery_health_check_result.py +119 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/model_service_info.py +106 -0
- omnibase_infra/nodes/node_service_discovery_effect/models/model_service_registration.py +121 -0
- omnibase_infra/nodes/node_service_discovery_effect/node.py +111 -0
- omnibase_infra/nodes/node_service_discovery_effect/protocols/__init__.py +14 -0
- omnibase_infra/nodes/node_service_discovery_effect/protocols/protocol_discovery_operations.py +279 -0
- omnibase_infra/nodes/node_service_discovery_effect/registry/__init__.py +13 -0
- omnibase_infra/nodes/node_service_discovery_effect/registry/registry_infra_service_discovery.py +222 -0
- omnibase_infra/nodes/reducers/__init__.py +30 -0
- omnibase_infra/nodes/reducers/models/__init__.py +37 -0
- omnibase_infra/nodes/reducers/models/model_payload_consul_register.py +87 -0
- omnibase_infra/nodes/reducers/models/model_payload_ledger_append.py +133 -0
- omnibase_infra/nodes/reducers/models/model_payload_postgres_upsert_registration.py +60 -0
- omnibase_infra/nodes/reducers/models/model_registration_confirmation.py +166 -0
- omnibase_infra/nodes/reducers/models/model_registration_state.py +433 -0
- omnibase_infra/nodes/reducers/registration_reducer.py +1138 -0
- omnibase_infra/observability/__init__.py +143 -0
- omnibase_infra/observability/constants_metrics.py +91 -0
- omnibase_infra/observability/factory_observability_sink.py +525 -0
- omnibase_infra/observability/handlers/__init__.py +118 -0
- omnibase_infra/observability/handlers/handler_logging_structured.py +967 -0
- omnibase_infra/observability/handlers/handler_metrics_prometheus.py +1120 -0
- omnibase_infra/observability/handlers/model_logging_handler_config.py +71 -0
- omnibase_infra/observability/handlers/model_logging_handler_response.py +77 -0
- omnibase_infra/observability/handlers/model_metrics_handler_config.py +172 -0
- omnibase_infra/observability/handlers/model_metrics_handler_payload.py +135 -0
- omnibase_infra/observability/handlers/model_metrics_handler_response.py +101 -0
- omnibase_infra/observability/hooks/__init__.py +74 -0
- omnibase_infra/observability/hooks/hook_observability.py +1223 -0
- omnibase_infra/observability/models/__init__.py +30 -0
- omnibase_infra/observability/models/enum_required_log_context_key.py +77 -0
- omnibase_infra/observability/models/model_buffered_log_entry.py +117 -0
- omnibase_infra/observability/models/model_logging_sink_config.py +73 -0
- omnibase_infra/observability/models/model_metrics_sink_config.py +156 -0
- omnibase_infra/observability/sinks/__init__.py +69 -0
- omnibase_infra/observability/sinks/sink_logging_structured.py +809 -0
- omnibase_infra/observability/sinks/sink_metrics_prometheus.py +710 -0
- omnibase_infra/plugins/__init__.py +27 -0
- omnibase_infra/plugins/examples/__init__.py +28 -0
- omnibase_infra/plugins/examples/plugin_json_normalizer.py +271 -0
- omnibase_infra/plugins/examples/plugin_json_normalizer_error_handling.py +210 -0
- omnibase_infra/plugins/models/__init__.py +21 -0
- omnibase_infra/plugins/models/model_plugin_context.py +76 -0
- omnibase_infra/plugins/models/model_plugin_input_data.py +58 -0
- omnibase_infra/plugins/models/model_plugin_output_data.py +62 -0
- omnibase_infra/plugins/plugin_compute_base.py +449 -0
- omnibase_infra/projectors/__init__.py +30 -0
- omnibase_infra/projectors/contracts/__init__.py +63 -0
- omnibase_infra/projectors/contracts/registration_projector.yaml +370 -0
- omnibase_infra/projectors/projection_reader_registration.py +1559 -0
- omnibase_infra/projectors/snapshot_publisher_registration.py +1329 -0
- omnibase_infra/protocols/__init__.py +104 -0
- omnibase_infra/protocols/protocol_capability_projection.py +253 -0
- omnibase_infra/protocols/protocol_capability_query.py +251 -0
- omnibase_infra/protocols/protocol_container_aware.py +200 -0
- omnibase_infra/protocols/protocol_dispatch_engine.py +152 -0
- omnibase_infra/protocols/protocol_event_bus_like.py +127 -0
- omnibase_infra/protocols/protocol_event_projector.py +96 -0
- omnibase_infra/protocols/protocol_idempotency_store.py +142 -0
- omnibase_infra/protocols/protocol_message_dispatcher.py +247 -0
- omnibase_infra/protocols/protocol_message_type_registry.py +306 -0
- omnibase_infra/protocols/protocol_plugin_compute.py +368 -0
- omnibase_infra/protocols/protocol_projector_schema_validator.py +82 -0
- omnibase_infra/protocols/protocol_registry_metrics.py +215 -0
- omnibase_infra/protocols/protocol_snapshot_publisher.py +396 -0
- omnibase_infra/protocols/protocol_snapshot_store.py +567 -0
- omnibase_infra/runtime/__init__.py +445 -0
- omnibase_infra/runtime/binding_config_resolver.py +2771 -0
- omnibase_infra/runtime/binding_resolver.py +753 -0
- omnibase_infra/runtime/chain_aware_dispatch.py +467 -0
- omnibase_infra/runtime/constants_notification.py +75 -0
- omnibase_infra/runtime/constants_security.py +70 -0
- omnibase_infra/runtime/contract_handler_discovery.py +587 -0
- omnibase_infra/runtime/contract_loaders/__init__.py +51 -0
- omnibase_infra/runtime/contract_loaders/handler_routing_loader.py +464 -0
- omnibase_infra/runtime/contract_loaders/operation_bindings_loader.py +789 -0
- omnibase_infra/runtime/dispatch_context_enforcer.py +427 -0
- omnibase_infra/runtime/emit_daemon/__init__.py +97 -0
- omnibase_infra/runtime/emit_daemon/cli.py +844 -0
- omnibase_infra/runtime/emit_daemon/client.py +811 -0
- omnibase_infra/runtime/emit_daemon/config.py +535 -0
- omnibase_infra/runtime/emit_daemon/daemon.py +812 -0
- omnibase_infra/runtime/emit_daemon/event_registry.py +477 -0
- omnibase_infra/runtime/emit_daemon/model_daemon_request.py +139 -0
- omnibase_infra/runtime/emit_daemon/model_daemon_response.py +191 -0
- omnibase_infra/runtime/emit_daemon/queue.py +618 -0
- omnibase_infra/runtime/enums/__init__.py +18 -0
- omnibase_infra/runtime/enums/enum_config_ref_scheme.py +33 -0
- omnibase_infra/runtime/enums/enum_scheduler_status.py +170 -0
- omnibase_infra/runtime/envelope_validator.py +179 -0
- omnibase_infra/runtime/event_bus_subcontract_wiring.py +466 -0
- omnibase_infra/runtime/handler_bootstrap_source.py +507 -0
- omnibase_infra/runtime/handler_contract_config_loader.py +603 -0
- omnibase_infra/runtime/handler_contract_source.py +750 -0
- omnibase_infra/runtime/handler_identity.py +81 -0
- omnibase_infra/runtime/handler_plugin_loader.py +2046 -0
- omnibase_infra/runtime/handler_registry.py +329 -0
- omnibase_infra/runtime/handler_source_resolver.py +367 -0
- omnibase_infra/runtime/invocation_security_enforcer.py +427 -0
- omnibase_infra/runtime/kafka_contract_source.py +984 -0
- omnibase_infra/runtime/kernel.py +40 -0
- omnibase_infra/runtime/mixin_policy_validation.py +522 -0
- omnibase_infra/runtime/mixin_semver_cache.py +402 -0
- omnibase_infra/runtime/mixins/__init__.py +24 -0
- omnibase_infra/runtime/mixins/mixin_projector_notification_publishing.py +566 -0
- omnibase_infra/runtime/mixins/mixin_projector_sql_operations.py +778 -0
- omnibase_infra/runtime/models/__init__.py +229 -0
- omnibase_infra/runtime/models/model_batch_lifecycle_result.py +217 -0
- omnibase_infra/runtime/models/model_binding_config.py +168 -0
- omnibase_infra/runtime/models/model_binding_config_cache_stats.py +135 -0
- omnibase_infra/runtime/models/model_binding_config_resolver_config.py +329 -0
- omnibase_infra/runtime/models/model_cached_secret.py +138 -0
- omnibase_infra/runtime/models/model_compute_key.py +138 -0
- omnibase_infra/runtime/models/model_compute_registration.py +97 -0
- omnibase_infra/runtime/models/model_config_cache_entry.py +61 -0
- omnibase_infra/runtime/models/model_config_ref.py +331 -0
- omnibase_infra/runtime/models/model_config_ref_parse_result.py +125 -0
- omnibase_infra/runtime/models/model_contract_load_result.py +224 -0
- omnibase_infra/runtime/models/model_domain_plugin_config.py +92 -0
- omnibase_infra/runtime/models/model_domain_plugin_result.py +270 -0
- omnibase_infra/runtime/models/model_duplicate_response.py +54 -0
- omnibase_infra/runtime/models/model_enabled_protocols_config.py +61 -0
- omnibase_infra/runtime/models/model_event_bus_config.py +54 -0
- omnibase_infra/runtime/models/model_failed_component.py +55 -0
- omnibase_infra/runtime/models/model_health_check_response.py +168 -0
- omnibase_infra/runtime/models/model_health_check_result.py +229 -0
- omnibase_infra/runtime/models/model_lifecycle_result.py +245 -0
- omnibase_infra/runtime/models/model_logging_config.py +42 -0
- omnibase_infra/runtime/models/model_optional_correlation_id.py +167 -0
- omnibase_infra/runtime/models/model_optional_string.py +94 -0
- omnibase_infra/runtime/models/model_optional_uuid.py +110 -0
- omnibase_infra/runtime/models/model_policy_context.py +100 -0
- omnibase_infra/runtime/models/model_policy_key.py +138 -0
- omnibase_infra/runtime/models/model_policy_registration.py +139 -0
- omnibase_infra/runtime/models/model_policy_result.py +103 -0
- omnibase_infra/runtime/models/model_policy_type_filter.py +157 -0
- omnibase_infra/runtime/models/model_projector_notification_config.py +171 -0
- omnibase_infra/runtime/models/model_projector_plugin_loader_config.py +47 -0
- omnibase_infra/runtime/models/model_protocol_registration_config.py +65 -0
- omnibase_infra/runtime/models/model_retry_policy.py +105 -0
- omnibase_infra/runtime/models/model_runtime_config.py +150 -0
- omnibase_infra/runtime/models/model_runtime_contract_config.py +268 -0
- omnibase_infra/runtime/models/model_runtime_scheduler_config.py +625 -0
- omnibase_infra/runtime/models/model_runtime_scheduler_metrics.py +233 -0
- omnibase_infra/runtime/models/model_runtime_tick.py +193 -0
- omnibase_infra/runtime/models/model_secret_cache_stats.py +82 -0
- omnibase_infra/runtime/models/model_secret_mapping.py +63 -0
- omnibase_infra/runtime/models/model_secret_resolver_config.py +107 -0
- omnibase_infra/runtime/models/model_secret_resolver_metrics.py +111 -0
- omnibase_infra/runtime/models/model_secret_source_info.py +72 -0
- omnibase_infra/runtime/models/model_secret_source_spec.py +66 -0
- omnibase_infra/runtime/models/model_security_config.py +109 -0
- omnibase_infra/runtime/models/model_shutdown_batch_result.py +75 -0
- omnibase_infra/runtime/models/model_shutdown_config.py +94 -0
- omnibase_infra/runtime/models/model_transition_notification_outbox_config.py +112 -0
- omnibase_infra/runtime/models/model_transition_notification_outbox_metrics.py +140 -0
- omnibase_infra/runtime/models/model_transition_notification_publisher_metrics.py +357 -0
- omnibase_infra/runtime/projector_plugin_loader.py +1462 -0
- omnibase_infra/runtime/projector_schema_manager.py +565 -0
- omnibase_infra/runtime/projector_shell.py +1330 -0
- omnibase_infra/runtime/protocol_contract_descriptor.py +92 -0
- omnibase_infra/runtime/protocol_contract_source.py +92 -0
- omnibase_infra/runtime/protocol_domain_plugin.py +474 -0
- omnibase_infra/runtime/protocol_handler_discovery.py +221 -0
- omnibase_infra/runtime/protocol_handler_plugin_loader.py +327 -0
- omnibase_infra/runtime/protocol_lifecycle_executor.py +435 -0
- omnibase_infra/runtime/protocol_policy.py +366 -0
- omnibase_infra/runtime/protocols/__init__.py +37 -0
- omnibase_infra/runtime/protocols/protocol_runtime_scheduler.py +468 -0
- omnibase_infra/runtime/publisher_topic_scoped.py +294 -0
- omnibase_infra/runtime/registry/__init__.py +93 -0
- omnibase_infra/runtime/registry/mixin_message_type_query.py +326 -0
- omnibase_infra/runtime/registry/mixin_message_type_registration.py +354 -0
- omnibase_infra/runtime/registry/registry_event_bus_binding.py +268 -0
- omnibase_infra/runtime/registry/registry_message_type.py +542 -0
- omnibase_infra/runtime/registry/registry_protocol_binding.py +445 -0
- omnibase_infra/runtime/registry_compute.py +1143 -0
- omnibase_infra/runtime/registry_contract_source.py +693 -0
- omnibase_infra/runtime/registry_dispatcher.py +678 -0
- omnibase_infra/runtime/registry_policy.py +1185 -0
- omnibase_infra/runtime/runtime_contract_config_loader.py +406 -0
- omnibase_infra/runtime/runtime_scheduler.py +1070 -0
- omnibase_infra/runtime/secret_resolver.py +2112 -0
- omnibase_infra/runtime/security_metadata_validator.py +776 -0
- omnibase_infra/runtime/service_kernel.py +1651 -0
- omnibase_infra/runtime/service_message_dispatch_engine.py +2350 -0
- omnibase_infra/runtime/service_runtime_host_process.py +3493 -0
- omnibase_infra/runtime/transition_notification_outbox.py +1190 -0
- omnibase_infra/runtime/transition_notification_publisher.py +765 -0
- omnibase_infra/runtime/util_container_wiring.py +1124 -0
- omnibase_infra/runtime/util_validation.py +314 -0
- omnibase_infra/runtime/util_version.py +98 -0
- omnibase_infra/runtime/util_wiring.py +723 -0
- omnibase_infra/schemas/schema_registration_projection.sql +320 -0
- omnibase_infra/schemas/schema_transition_notification_outbox.sql +245 -0
- omnibase_infra/services/__init__.py +89 -0
- omnibase_infra/services/corpus_capture.py +684 -0
- omnibase_infra/services/mcp/__init__.py +31 -0
- omnibase_infra/services/mcp/mcp_server_lifecycle.py +449 -0
- omnibase_infra/services/mcp/service_mcp_tool_discovery.py +411 -0
- omnibase_infra/services/mcp/service_mcp_tool_registry.py +329 -0
- omnibase_infra/services/mcp/service_mcp_tool_sync.py +565 -0
- omnibase_infra/services/registry_api/__init__.py +40 -0
- omnibase_infra/services/registry_api/main.py +261 -0
- omnibase_infra/services/registry_api/models/__init__.py +66 -0
- omnibase_infra/services/registry_api/models/model_capability_widget_mapping.py +38 -0
- omnibase_infra/services/registry_api/models/model_pagination_info.py +48 -0
- omnibase_infra/services/registry_api/models/model_registry_discovery_response.py +73 -0
- omnibase_infra/services/registry_api/models/model_registry_health_response.py +49 -0
- omnibase_infra/services/registry_api/models/model_registry_instance_view.py +88 -0
- omnibase_infra/services/registry_api/models/model_registry_node_view.py +88 -0
- omnibase_infra/services/registry_api/models/model_registry_summary.py +60 -0
- omnibase_infra/services/registry_api/models/model_response_list_instances.py +43 -0
- omnibase_infra/services/registry_api/models/model_response_list_nodes.py +51 -0
- omnibase_infra/services/registry_api/models/model_warning.py +49 -0
- omnibase_infra/services/registry_api/models/model_widget_defaults.py +28 -0
- omnibase_infra/services/registry_api/models/model_widget_mapping.py +51 -0
- omnibase_infra/services/registry_api/routes.py +371 -0
- omnibase_infra/services/registry_api/service.py +837 -0
- omnibase_infra/services/service_capability_query.py +945 -0
- omnibase_infra/services/service_health.py +898 -0
- omnibase_infra/services/service_node_selector.py +530 -0
- omnibase_infra/services/service_timeout_emitter.py +699 -0
- omnibase_infra/services/service_timeout_scanner.py +394 -0
- omnibase_infra/services/session/__init__.py +56 -0
- omnibase_infra/services/session/config_consumer.py +137 -0
- omnibase_infra/services/session/config_store.py +139 -0
- omnibase_infra/services/session/consumer.py +1007 -0
- omnibase_infra/services/session/protocol_session_aggregator.py +117 -0
- omnibase_infra/services/session/store.py +997 -0
- omnibase_infra/services/snapshot/__init__.py +31 -0
- omnibase_infra/services/snapshot/service_snapshot.py +647 -0
- omnibase_infra/services/snapshot/store_inmemory.py +637 -0
- omnibase_infra/services/snapshot/store_postgres.py +1279 -0
- omnibase_infra/shared/__init__.py +8 -0
- omnibase_infra/testing/__init__.py +10 -0
- omnibase_infra/testing/utils.py +23 -0
- omnibase_infra/topics/__init__.py +45 -0
- omnibase_infra/topics/platform_topic_suffixes.py +140 -0
- omnibase_infra/topics/util_topic_composition.py +95 -0
- omnibase_infra/types/__init__.py +48 -0
- omnibase_infra/types/type_cache_info.py +49 -0
- omnibase_infra/types/type_dsn.py +173 -0
- omnibase_infra/types/type_infra_aliases.py +60 -0
- omnibase_infra/types/typed_dict/__init__.py +29 -0
- omnibase_infra/types/typed_dict/typed_dict_envelope_build_params.py +115 -0
- omnibase_infra/types/typed_dict/typed_dict_introspection_cache.py +128 -0
- omnibase_infra/types/typed_dict/typed_dict_performance_metrics_cache.py +140 -0
- omnibase_infra/types/typed_dict_capabilities.py +64 -0
- omnibase_infra/utils/__init__.py +117 -0
- omnibase_infra/utils/correlation.py +208 -0
- omnibase_infra/utils/util_atomic_file.py +261 -0
- omnibase_infra/utils/util_consumer_group.py +232 -0
- omnibase_infra/utils/util_datetime.py +372 -0
- omnibase_infra/utils/util_db_transaction.py +239 -0
- omnibase_infra/utils/util_dsn_validation.py +333 -0
- omnibase_infra/utils/util_env_parsing.py +264 -0
- omnibase_infra/utils/util_error_sanitization.py +457 -0
- omnibase_infra/utils/util_pydantic_validators.py +477 -0
- omnibase_infra/utils/util_retry_optimistic.py +281 -0
- omnibase_infra/utils/util_semver.py +233 -0
- omnibase_infra/validation/__init__.py +307 -0
- omnibase_infra/validation/contracts/security.validation.yaml +114 -0
- omnibase_infra/validation/enums/__init__.py +11 -0
- omnibase_infra/validation/enums/enum_contract_violation_severity.py +13 -0
- omnibase_infra/validation/infra_validators.py +1514 -0
- omnibase_infra/validation/linter_contract.py +907 -0
- omnibase_infra/validation/mixin_any_type_classification.py +120 -0
- omnibase_infra/validation/mixin_any_type_exemption.py +580 -0
- omnibase_infra/validation/mixin_any_type_reporting.py +106 -0
- omnibase_infra/validation/mixin_execution_shape_violation_checks.py +596 -0
- omnibase_infra/validation/mixin_node_archetype_detection.py +254 -0
- omnibase_infra/validation/models/__init__.py +15 -0
- omnibase_infra/validation/models/model_contract_lint_result.py +101 -0
- omnibase_infra/validation/models/model_contract_violation.py +41 -0
- omnibase_infra/validation/service_validation_aggregator.py +395 -0
- omnibase_infra/validation/validation_exemptions.yaml +2033 -0
- omnibase_infra/validation/validator_any_type.py +715 -0
- omnibase_infra/validation/validator_chain_propagation.py +839 -0
- omnibase_infra/validation/validator_execution_shape.py +465 -0
- omnibase_infra/validation/validator_localhandler.py +261 -0
- omnibase_infra/validation/validator_registration_security.py +410 -0
- omnibase_infra/validation/validator_routing_coverage.py +1020 -0
- omnibase_infra/validation/validator_runtime_shape.py +915 -0
- omnibase_infra/validation/validator_security.py +513 -0
- omnibase_infra/validation/validator_topic_category.py +1152 -0
- omnibase_infra-0.2.6.dist-info/METADATA +197 -0
- omnibase_infra-0.2.6.dist-info/RECORD +833 -0
- omnibase_infra-0.2.6.dist-info/WHEEL +4 -0
- omnibase_infra-0.2.6.dist-info/entry_points.txt +5 -0
- omnibase_infra-0.2.6.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,1020 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Routing Coverage Validator for ONEX Message Types.
|
|
4
|
+
|
|
5
|
+
This module provides validation functionality to ensure all message types
|
|
6
|
+
(Events, Commands, Intents, Projections) defined in the codebase are properly
|
|
7
|
+
registered in the routing configuration. It supports startup fail-fast validation
|
|
8
|
+
and CI gate integration.
|
|
9
|
+
|
|
10
|
+
The validator performs two types of discovery:
|
|
11
|
+
1. **Message Type Discovery**: Scans source code for classes following ONEX
|
|
12
|
+
message type naming conventions (Event, Command, Intent, Projection suffixes).
|
|
13
|
+
2. **Route Registration Discovery**: Inspects the runtime registry or performs
|
|
14
|
+
static analysis to find registered message routes.
|
|
15
|
+
|
|
16
|
+
Usage:
|
|
17
|
+
# At application startup
|
|
18
|
+
from omnibase_infra.validation import validate_routing_coverage_on_startup
|
|
19
|
+
|
|
20
|
+
validate_routing_coverage_on_startup(
|
|
21
|
+
source_directory=Path("src/omnibase_infra"),
|
|
22
|
+
fail_on_unmapped=True,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
# In CI pipelines
|
|
26
|
+
from omnibase_infra.validation import check_routing_coverage_ci
|
|
27
|
+
|
|
28
|
+
passed, violations = check_routing_coverage_ci(Path("src/omnibase_infra"))
|
|
29
|
+
if not passed:
|
|
30
|
+
for v in violations:
|
|
31
|
+
print(v.format_for_ci())
|
|
32
|
+
sys.exit(1)
|
|
33
|
+
|
|
34
|
+
Integration with ONEX Architecture:
|
|
35
|
+
- Supports ONEX 4-node architecture message categories
|
|
36
|
+
- Integrates with RegistryProtocolBinding for runtime route inspection
|
|
37
|
+
- Returns ModelExecutionShapeViolationResult for consistency with other validators
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
from __future__ import annotations
|
|
41
|
+
|
|
42
|
+
import ast
|
|
43
|
+
import logging
|
|
44
|
+
import re
|
|
45
|
+
import threading
|
|
46
|
+
from pathlib import Path
|
|
47
|
+
from typing import TYPE_CHECKING
|
|
48
|
+
|
|
49
|
+
from omnibase_infra.enums import (
|
|
50
|
+
EnumExecutionShapeViolation,
|
|
51
|
+
EnumMessageCategory,
|
|
52
|
+
EnumNodeOutputType,
|
|
53
|
+
EnumValidationSeverity,
|
|
54
|
+
)
|
|
55
|
+
from omnibase_infra.errors import RuntimeHostError
|
|
56
|
+
from omnibase_infra.models.validation.model_category_match_result import (
|
|
57
|
+
ModelCategoryMatchResult,
|
|
58
|
+
)
|
|
59
|
+
from omnibase_infra.models.validation.model_coverage_metrics import (
|
|
60
|
+
ModelCoverageMetrics,
|
|
61
|
+
)
|
|
62
|
+
from omnibase_infra.models.validation.model_execution_shape_violation import (
|
|
63
|
+
ModelExecutionShapeViolationResult,
|
|
64
|
+
)
|
|
65
|
+
from omnibase_infra.types import MessageOutputCategory
|
|
66
|
+
from omnibase_infra.validation.infra_validators import should_skip_path
|
|
67
|
+
|
|
68
|
+
if TYPE_CHECKING:
|
|
69
|
+
from omnibase_infra.runtime.handler_registry import RegistryProtocolBinding
|
|
70
|
+
|
|
71
|
+
logger = logging.getLogger(__name__)
|
|
72
|
+
|
|
73
|
+
# =============================================================================
|
|
74
|
+
# Custom Exception
|
|
75
|
+
# =============================================================================
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class RoutingCoverageError(RuntimeHostError):
|
|
79
|
+
"""Raised when message types are not registered in routing.
|
|
80
|
+
|
|
81
|
+
This exception is thrown during application startup if fail-fast mode
|
|
82
|
+
is enabled and there are unmapped message types. It provides a clear
|
|
83
|
+
list of all types that need routing registration.
|
|
84
|
+
|
|
85
|
+
Attributes:
|
|
86
|
+
unmapped_types: Set of message type class names that lack routing.
|
|
87
|
+
coverage_percent: Percentage of types that are properly registered.
|
|
88
|
+
|
|
89
|
+
Example:
|
|
90
|
+
>>> raise RoutingCoverageError(
|
|
91
|
+
... unmapped_types={"OrderCreatedEvent", "PaymentCommand"},
|
|
92
|
+
... total_types=10,
|
|
93
|
+
... registered_types=8,
|
|
94
|
+
... )
|
|
95
|
+
RoutingCoverageError: 2 unmapped message types (80.0% coverage):
|
|
96
|
+
OrderCreatedEvent, PaymentCommand
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
def __init__(
|
|
100
|
+
self,
|
|
101
|
+
unmapped_types: set[str],
|
|
102
|
+
total_types: int = 0,
|
|
103
|
+
registered_types: int = 0,
|
|
104
|
+
) -> None:
|
|
105
|
+
"""Initialize RoutingCoverageError.
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
unmapped_types: Set of message type class names without routing.
|
|
109
|
+
total_types: Total number of message types discovered.
|
|
110
|
+
registered_types: Number of types with registered routes.
|
|
111
|
+
"""
|
|
112
|
+
self.unmapped_types = unmapped_types
|
|
113
|
+
self.total_types = total_types
|
|
114
|
+
self.registered_types = registered_types
|
|
115
|
+
|
|
116
|
+
coverage_percent = (
|
|
117
|
+
(registered_types / total_types * 100) if total_types > 0 else 0.0
|
|
118
|
+
)
|
|
119
|
+
self.coverage_percent = coverage_percent
|
|
120
|
+
|
|
121
|
+
types_list = ", ".join(sorted(unmapped_types))
|
|
122
|
+
message = (
|
|
123
|
+
f"{len(unmapped_types)} unmapped message types "
|
|
124
|
+
f"({coverage_percent:.1f}% coverage): {types_list}"
|
|
125
|
+
)
|
|
126
|
+
super().__init__(message=message)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
# =============================================================================
|
|
130
|
+
# Message Category Detection
|
|
131
|
+
# =============================================================================
|
|
132
|
+
|
|
133
|
+
# Suffix patterns for message type detection
|
|
134
|
+
# Note: PROJECTION uses EnumNodeOutputType as it's a node output, not a message category
|
|
135
|
+
_MESSAGE_SUFFIX_PATTERNS: dict[str, MessageOutputCategory] = {
|
|
136
|
+
"Event": EnumMessageCategory.EVENT,
|
|
137
|
+
"Command": EnumMessageCategory.COMMAND,
|
|
138
|
+
"Intent": EnumMessageCategory.INTENT,
|
|
139
|
+
"Projection": EnumNodeOutputType.PROJECTION,
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
# Decorator patterns that indicate a message type
|
|
143
|
+
_MESSAGE_DECORATOR_PATTERNS: frozenset[str] = frozenset(
|
|
144
|
+
{
|
|
145
|
+
"message_type",
|
|
146
|
+
"event_type",
|
|
147
|
+
"command_type",
|
|
148
|
+
"intent_type",
|
|
149
|
+
"projection_type",
|
|
150
|
+
}
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
# Base class patterns indicating message inheritance
|
|
154
|
+
_MESSAGE_BASE_PATTERNS: frozenset[str] = frozenset(
|
|
155
|
+
{
|
|
156
|
+
"BaseEvent",
|
|
157
|
+
"BaseCommand",
|
|
158
|
+
"BaseIntent",
|
|
159
|
+
"BaseProjection",
|
|
160
|
+
"ModelEvent",
|
|
161
|
+
"ModelCommand",
|
|
162
|
+
"ModelIntent",
|
|
163
|
+
"ModelProjection",
|
|
164
|
+
"EventBase",
|
|
165
|
+
"CommandBase",
|
|
166
|
+
"IntentBase",
|
|
167
|
+
"ProjectionBase",
|
|
168
|
+
}
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def _get_category_from_suffix(
|
|
173
|
+
class_name: str,
|
|
174
|
+
) -> MessageOutputCategory | None:
|
|
175
|
+
"""Determine message category or node output type from class name suffix.
|
|
176
|
+
|
|
177
|
+
Args:
|
|
178
|
+
class_name: The class name to analyze.
|
|
179
|
+
|
|
180
|
+
Returns:
|
|
181
|
+
EnumMessageCategory or EnumNodeOutputType if suffix matches, None otherwise.
|
|
182
|
+
"""
|
|
183
|
+
for suffix, category in _MESSAGE_SUFFIX_PATTERNS.items():
|
|
184
|
+
if class_name.endswith(suffix):
|
|
185
|
+
return category
|
|
186
|
+
return None
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def _get_category_from_base(
|
|
190
|
+
base_name: str,
|
|
191
|
+
) -> MessageOutputCategory | None:
|
|
192
|
+
"""Determine message category or node output type from base class name.
|
|
193
|
+
|
|
194
|
+
Args:
|
|
195
|
+
base_name: The base class name to analyze.
|
|
196
|
+
|
|
197
|
+
Returns:
|
|
198
|
+
EnumMessageCategory or EnumNodeOutputType if base matches, None otherwise.
|
|
199
|
+
"""
|
|
200
|
+
base_lower = base_name.lower()
|
|
201
|
+
if "event" in base_lower:
|
|
202
|
+
return EnumMessageCategory.EVENT
|
|
203
|
+
if "command" in base_lower:
|
|
204
|
+
return EnumMessageCategory.COMMAND
|
|
205
|
+
if "intent" in base_lower:
|
|
206
|
+
return EnumMessageCategory.INTENT
|
|
207
|
+
if "projection" in base_lower:
|
|
208
|
+
return EnumNodeOutputType.PROJECTION
|
|
209
|
+
return None
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def _has_message_decorator(
|
|
213
|
+
node: ast.ClassDef,
|
|
214
|
+
) -> ModelCategoryMatchResult:
|
|
215
|
+
"""Check if class has a message type decorator.
|
|
216
|
+
|
|
217
|
+
Args:
|
|
218
|
+
node: AST ClassDef node to analyze.
|
|
219
|
+
|
|
220
|
+
Returns:
|
|
221
|
+
ModelCategoryMatchResult indicating whether a decorator was found
|
|
222
|
+
and, if so, which category it represents.
|
|
223
|
+
|
|
224
|
+
Example:
|
|
225
|
+
>>> # For a class with @event_type decorator
|
|
226
|
+
>>> result = _has_message_decorator(class_node)
|
|
227
|
+
>>> result.matched
|
|
228
|
+
True
|
|
229
|
+
>>> result.category
|
|
230
|
+
<EnumMessageCategory.EVENT: 'event'>
|
|
231
|
+
|
|
232
|
+
.. versionchanged:: 0.6.1
|
|
233
|
+
Changed return type from tuple[bool, MessageOutputCategory | None]
|
|
234
|
+
to ModelCategoryMatchResult (OMN-1007).
|
|
235
|
+
"""
|
|
236
|
+
for decorator in node.decorator_list:
|
|
237
|
+
decorator_name = ""
|
|
238
|
+
if isinstance(decorator, ast.Name):
|
|
239
|
+
decorator_name = decorator.id
|
|
240
|
+
elif isinstance(decorator, ast.Call):
|
|
241
|
+
if isinstance(decorator.func, ast.Name):
|
|
242
|
+
decorator_name = decorator.func.id
|
|
243
|
+
elif isinstance(decorator.func, ast.Attribute):
|
|
244
|
+
decorator_name = decorator.func.attr
|
|
245
|
+
|
|
246
|
+
if decorator_name in _MESSAGE_DECORATOR_PATTERNS:
|
|
247
|
+
# Try to infer category from decorator name
|
|
248
|
+
if "event" in decorator_name.lower():
|
|
249
|
+
return ModelCategoryMatchResult.matched_with_category(
|
|
250
|
+
EnumMessageCategory.EVENT
|
|
251
|
+
)
|
|
252
|
+
if "command" in decorator_name.lower():
|
|
253
|
+
return ModelCategoryMatchResult.matched_with_category(
|
|
254
|
+
EnumMessageCategory.COMMAND
|
|
255
|
+
)
|
|
256
|
+
if "intent" in decorator_name.lower():
|
|
257
|
+
return ModelCategoryMatchResult.matched_with_category(
|
|
258
|
+
EnumMessageCategory.INTENT
|
|
259
|
+
)
|
|
260
|
+
if "projection" in decorator_name.lower():
|
|
261
|
+
return ModelCategoryMatchResult.matched_with_category(
|
|
262
|
+
EnumNodeOutputType.PROJECTION
|
|
263
|
+
)
|
|
264
|
+
# Generic message_type decorator
|
|
265
|
+
return ModelCategoryMatchResult.matched_without_category()
|
|
266
|
+
|
|
267
|
+
return ModelCategoryMatchResult.not_matched()
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def _get_base_classes(node: ast.ClassDef) -> list[str]:
|
|
271
|
+
"""Extract base class names from ClassDef node.
|
|
272
|
+
|
|
273
|
+
Args:
|
|
274
|
+
node: AST ClassDef node to analyze.
|
|
275
|
+
|
|
276
|
+
Returns:
|
|
277
|
+
List of base class names as strings.
|
|
278
|
+
"""
|
|
279
|
+
bases: list[str] = []
|
|
280
|
+
for base in node.bases:
|
|
281
|
+
if isinstance(base, ast.Name):
|
|
282
|
+
bases.append(base.id)
|
|
283
|
+
elif isinstance(base, ast.Attribute):
|
|
284
|
+
bases.append(base.attr)
|
|
285
|
+
return bases
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
# =============================================================================
|
|
289
|
+
# Discovery Functions
|
|
290
|
+
# =============================================================================
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
def discover_message_types(
|
|
294
|
+
source_directory: Path,
|
|
295
|
+
exclude_patterns: list[str] | None = None,
|
|
296
|
+
) -> dict[str, MessageOutputCategory]:
|
|
297
|
+
"""Discover all message types defined in source code.
|
|
298
|
+
|
|
299
|
+
Scans Python files in the source directory for classes that match
|
|
300
|
+
ONEX message type patterns:
|
|
301
|
+
- Classes ending in 'Event', 'Command', 'Intent', 'Projection'
|
|
302
|
+
- Classes with @message_type decorator (or variants)
|
|
303
|
+
- Classes inheriting from base message types
|
|
304
|
+
|
|
305
|
+
Args:
|
|
306
|
+
source_directory: Root directory to scan for message types.
|
|
307
|
+
exclude_patterns: Optional list of glob patterns to exclude.
|
|
308
|
+
|
|
309
|
+
Returns:
|
|
310
|
+
Dictionary mapping message class names to their categories
|
|
311
|
+
(EnumMessageCategory for EVENT/COMMAND/INTENT, EnumNodeOutputType for PROJECTION).
|
|
312
|
+
Returns empty dict if source_directory is invalid.
|
|
313
|
+
|
|
314
|
+
Example:
|
|
315
|
+
>>> types = discover_message_types(Path("src/omnibase_infra"))
|
|
316
|
+
>>> print(types)
|
|
317
|
+
{
|
|
318
|
+
'ModelNodeHeartbeatEvent': EnumMessageCategory.EVENT,
|
|
319
|
+
'ModelNodeIntrospectionEvent': EnumMessageCategory.EVENT,
|
|
320
|
+
...
|
|
321
|
+
}
|
|
322
|
+
"""
|
|
323
|
+
# Defensive type check for source_directory
|
|
324
|
+
if not isinstance(source_directory, Path):
|
|
325
|
+
try:
|
|
326
|
+
source_directory = Path(source_directory)
|
|
327
|
+
except (TypeError, ValueError):
|
|
328
|
+
return {}
|
|
329
|
+
|
|
330
|
+
if exclude_patterns is None:
|
|
331
|
+
exclude_patterns = [
|
|
332
|
+
"**/test_*.py",
|
|
333
|
+
"**/*_test.py",
|
|
334
|
+
"**/tests/**",
|
|
335
|
+
"**/__pycache__/**",
|
|
336
|
+
]
|
|
337
|
+
# Defensive type check for exclude_patterns
|
|
338
|
+
elif not isinstance(exclude_patterns, list):
|
|
339
|
+
exclude_patterns = []
|
|
340
|
+
|
|
341
|
+
discovered_types: dict[str, MessageOutputCategory] = {}
|
|
342
|
+
|
|
343
|
+
# Collect all Python files
|
|
344
|
+
python_files: list[Path] = []
|
|
345
|
+
for pattern in ["**/*.py"]:
|
|
346
|
+
python_files.extend(source_directory.glob(pattern))
|
|
347
|
+
|
|
348
|
+
# Filter out excluded files
|
|
349
|
+
filtered_files: list[Path] = []
|
|
350
|
+
for file_path in python_files:
|
|
351
|
+
excluded = False
|
|
352
|
+
for exclude in exclude_patterns:
|
|
353
|
+
# Skip non-string exclude patterns
|
|
354
|
+
if not isinstance(exclude, str):
|
|
355
|
+
continue
|
|
356
|
+
if file_path.match(exclude):
|
|
357
|
+
excluded = True
|
|
358
|
+
break
|
|
359
|
+
if not excluded:
|
|
360
|
+
filtered_files.append(file_path)
|
|
361
|
+
|
|
362
|
+
# Parse each file and discover message types
|
|
363
|
+
for file_path in filtered_files:
|
|
364
|
+
try:
|
|
365
|
+
file_content = file_path.read_text(encoding="utf-8")
|
|
366
|
+
tree = ast.parse(file_content, filename=str(file_path))
|
|
367
|
+
except SyntaxError as e:
|
|
368
|
+
# Log and skip files with syntax errors
|
|
369
|
+
logger.debug(
|
|
370
|
+
"Skipping file with syntax error during message type discovery: %s "
|
|
371
|
+
"(line %s: %s)",
|
|
372
|
+
file_path,
|
|
373
|
+
e.lineno,
|
|
374
|
+
e.msg,
|
|
375
|
+
)
|
|
376
|
+
continue
|
|
377
|
+
except UnicodeDecodeError as e:
|
|
378
|
+
# Log and skip files with encoding errors
|
|
379
|
+
logger.debug(
|
|
380
|
+
"Skipping file with encoding error during message type discovery: %s "
|
|
381
|
+
"(%s)",
|
|
382
|
+
file_path,
|
|
383
|
+
e.reason,
|
|
384
|
+
)
|
|
385
|
+
continue
|
|
386
|
+
|
|
387
|
+
for node in ast.walk(tree):
|
|
388
|
+
if not isinstance(node, ast.ClassDef):
|
|
389
|
+
continue
|
|
390
|
+
|
|
391
|
+
class_name = node.name
|
|
392
|
+
category: MessageOutputCategory | None = None
|
|
393
|
+
|
|
394
|
+
# Strategy 1: Check suffix pattern (most common)
|
|
395
|
+
category = _get_category_from_suffix(class_name)
|
|
396
|
+
|
|
397
|
+
# Strategy 2: Check for message type decorators
|
|
398
|
+
if category is None:
|
|
399
|
+
match_result = _has_message_decorator(node)
|
|
400
|
+
if match_result.matched:
|
|
401
|
+
category = match_result.category
|
|
402
|
+
|
|
403
|
+
# Strategy 3: Check base class inheritance
|
|
404
|
+
if category is None:
|
|
405
|
+
bases = _get_base_classes(node)
|
|
406
|
+
for base_name in bases:
|
|
407
|
+
if base_name in _MESSAGE_BASE_PATTERNS:
|
|
408
|
+
category = _get_category_from_base(base_name)
|
|
409
|
+
if category is not None:
|
|
410
|
+
break
|
|
411
|
+
|
|
412
|
+
# If we found a category, record it
|
|
413
|
+
if category is not None:
|
|
414
|
+
discovered_types[class_name] = category
|
|
415
|
+
|
|
416
|
+
return discovered_types
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
def discover_registered_routes(
|
|
420
|
+
registry: RegistryProtocolBinding | None = None,
|
|
421
|
+
source_directory: Path | None = None,
|
|
422
|
+
) -> set[str]:
|
|
423
|
+
"""Discover routing registrations from registry or source code.
|
|
424
|
+
|
|
425
|
+
This function supports two discovery strategies that return DIFFERENT
|
|
426
|
+
types of identifiers. Understanding this distinction is critical for
|
|
427
|
+
correct usage.
|
|
428
|
+
|
|
429
|
+
**Strategy 1: Runtime Registry Inspection** (returns HANDLER CATEGORIES)
|
|
430
|
+
When `registry` is provided, inspects the RegistryProtocolBinding
|
|
431
|
+
to find registered protocol handlers.
|
|
432
|
+
|
|
433
|
+
Returns: Handler category strings (e.g., "http", "db", "kafka")
|
|
434
|
+
representing the types of protocol handlers registered in the system.
|
|
435
|
+
|
|
436
|
+
Use case: Infrastructure health checks - verifying handler infrastructure
|
|
437
|
+
is configured. NOT suitable for message-level routing coverage validation.
|
|
438
|
+
|
|
439
|
+
Example return: {"http", "kafka", "db", "grpc"}
|
|
440
|
+
|
|
441
|
+
**Strategy 2: Static Source Analysis** (returns MESSAGE TYPE NAMES)
|
|
442
|
+
When `source_directory` is provided, scans source files for message
|
|
443
|
+
registration patterns using regex-based static analysis.
|
|
444
|
+
|
|
445
|
+
Returns: Message type class names (e.g., "OrderCreatedEvent",
|
|
446
|
+
"CreateUserCommand") found in registration patterns like
|
|
447
|
+
@route(MessageType) or registry.register(MessageType, handler).
|
|
448
|
+
|
|
449
|
+
Use case: Routing coverage validation - discovering which specific
|
|
450
|
+
message types have handler registrations. This is the PREFERRED
|
|
451
|
+
approach for coverage validation.
|
|
452
|
+
|
|
453
|
+
Example return: {"OrderCreatedEvent", "UserRegisteredEvent", "PaymentCommand"}
|
|
454
|
+
|
|
455
|
+
**Critical Distinction**:
|
|
456
|
+
- Registry strategy: Returns protocol/transport categories (http, kafka)
|
|
457
|
+
- Source analysis: Returns message type class names (OrderCreatedEvent)
|
|
458
|
+
|
|
459
|
+
These are fundamentally different identifier spaces and should NOT
|
|
460
|
+
be mixed or compared. For routing coverage validation, always use
|
|
461
|
+
source_directory alone.
|
|
462
|
+
|
|
463
|
+
Args:
|
|
464
|
+
registry: Optional runtime registry instance to inspect. When used,
|
|
465
|
+
returns handler categories (protocol types like "http", "kafka").
|
|
466
|
+
Useful for infrastructure health checks, not coverage validation.
|
|
467
|
+
source_directory: Optional source directory for static analysis.
|
|
468
|
+
Returns message type class names found in registration patterns.
|
|
469
|
+
Preferred for routing coverage validation.
|
|
470
|
+
|
|
471
|
+
Returns:
|
|
472
|
+
Set of discovered route identifiers. The semantics depend on which
|
|
473
|
+
parameters were provided:
|
|
474
|
+
- Registry only: Handler categories (http, db, kafka)
|
|
475
|
+
- Source directory only: Message type class names (OrderEvent, etc.)
|
|
476
|
+
- Both: Combined set (not recommended - produces mixed identifier types)
|
|
477
|
+
|
|
478
|
+
Example:
|
|
479
|
+
>>> # Runtime inspection - returns handler categories (infrastructure check)
|
|
480
|
+
>>> routes = discover_registered_routes(registry=get_handler_registry())
|
|
481
|
+
>>> # Returns: {"http", "kafka", "db"}
|
|
482
|
+
>>> # Use case: Verify handler infrastructure is configured
|
|
483
|
+
|
|
484
|
+
>>> # Static analysis - returns message type names (coverage validation)
|
|
485
|
+
>>> routes = discover_registered_routes(
|
|
486
|
+
... source_directory=Path("src/omnibase_infra")
|
|
487
|
+
... )
|
|
488
|
+
>>> # Returns: {"OrderCreatedEvent", "UserRegisteredEvent", ...}
|
|
489
|
+
>>> # Use case: Validate message routing coverage
|
|
490
|
+
|
|
491
|
+
>>> # For coverage validation, compare with discover_message_types():
|
|
492
|
+
>>> message_types = discover_message_types(Path("src/omnibase_infra"))
|
|
493
|
+
>>> registered = discover_registered_routes(source_directory=Path("src"))
|
|
494
|
+
>>> unmapped = set(message_types.keys()) - registered
|
|
495
|
+
"""
|
|
496
|
+
registered_types: set[str] = set()
|
|
497
|
+
|
|
498
|
+
# Strategy 1: Inspect runtime registry
|
|
499
|
+
if registry is not None:
|
|
500
|
+
# Get all registered protocol types
|
|
501
|
+
protocol_types = registry.list_protocols()
|
|
502
|
+
# Note: Protocol types are handler categories (http, db, kafka),
|
|
503
|
+
# not individual message types. For full message routing coverage,
|
|
504
|
+
# we need to inspect message-to-handler bindings separately.
|
|
505
|
+
# This is a placeholder for future integration with message routing.
|
|
506
|
+
registered_types.update(protocol_types)
|
|
507
|
+
|
|
508
|
+
# Strategy 2: Static analysis of registration calls
|
|
509
|
+
if source_directory is not None:
|
|
510
|
+
# Defensive type check - convert to Path if needed
|
|
511
|
+
if not isinstance(source_directory, Path):
|
|
512
|
+
try:
|
|
513
|
+
source_directory = Path(source_directory)
|
|
514
|
+
except (TypeError, ValueError):
|
|
515
|
+
pass
|
|
516
|
+
else:
|
|
517
|
+
registered_types.update(_discover_routes_static(source_directory))
|
|
518
|
+
else:
|
|
519
|
+
registered_types.update(_discover_routes_static(source_directory))
|
|
520
|
+
|
|
521
|
+
return registered_types
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
def _discover_routes_static(source_directory: Path) -> set[str]:
|
|
525
|
+
"""Discover registered routes through regex-based static analysis.
|
|
526
|
+
|
|
527
|
+
Searches for patterns like:
|
|
528
|
+
- registry.register(MessageType, handler)
|
|
529
|
+
- @route(MessageType)
|
|
530
|
+
- handler_map[MessageType] = ...
|
|
531
|
+
- bind(MessageType, ...)
|
|
532
|
+
- subscribe(topic, MessageType)
|
|
533
|
+
|
|
534
|
+
Note:
|
|
535
|
+
This function uses regex patterns, not AST parsing, for discovery.
|
|
536
|
+
This approach is faster but has limitations:
|
|
537
|
+
|
|
538
|
+
**May produce false positives:**
|
|
539
|
+
- Code in comments or docstrings matching the patterns
|
|
540
|
+
- String literals that happen to match (e.g., error messages)
|
|
541
|
+
- Test fixtures or mocks that aren't real registrations
|
|
542
|
+
|
|
543
|
+
**May miss registrations:**
|
|
544
|
+
- Dynamically constructed registration calls
|
|
545
|
+
- Non-standard registration patterns
|
|
546
|
+
- Registrations via factory functions or metaclasses
|
|
547
|
+
- Registrations in configuration files (YAML, JSON)
|
|
548
|
+
|
|
549
|
+
For precise discovery, consider AST-based analysis or runtime
|
|
550
|
+
registry inspection.
|
|
551
|
+
|
|
552
|
+
Args:
|
|
553
|
+
source_directory: Root directory to scan.
|
|
554
|
+
|
|
555
|
+
Returns:
|
|
556
|
+
Set of message type names found in registration patterns.
|
|
557
|
+
Returns empty set if source_directory is invalid.
|
|
558
|
+
"""
|
|
559
|
+
registered_types: set[str] = set()
|
|
560
|
+
|
|
561
|
+
# Defensive type check for source_directory
|
|
562
|
+
if not isinstance(source_directory, Path):
|
|
563
|
+
try:
|
|
564
|
+
source_directory = Path(source_directory)
|
|
565
|
+
except (TypeError, ValueError):
|
|
566
|
+
return registered_types
|
|
567
|
+
|
|
568
|
+
# Registration patterns to search for.
|
|
569
|
+
# Each pattern captures the message type name as group 1.
|
|
570
|
+
#
|
|
571
|
+
# PATTERN ORDERING: Patterns are ordered by specificity/reliability:
|
|
572
|
+
# 1. Decorator patterns - most explicit routing declarations
|
|
573
|
+
# 2. Method call patterns - programmatic registration
|
|
574
|
+
# 3. Dictionary patterns - mapping-based registration
|
|
575
|
+
#
|
|
576
|
+
# Note: Order doesn't affect matching (all patterns run independently),
|
|
577
|
+
# but documents the relative reliability of each pattern type.
|
|
578
|
+
registration_patterns = [
|
|
579
|
+
# Decorator patterns (most explicit routing declarations)
|
|
580
|
+
# Matches: @route(OrderEvent), @handle("OrderEvent"), @handler(OrderEvent)
|
|
581
|
+
# False positive risk: Low - decorators are typically for routing
|
|
582
|
+
r"@(?:route|handle|handler)\s*\(\s*['\"]?(\w+)['\"]?\s*\)",
|
|
583
|
+
# Method call patterns (programmatic registration)
|
|
584
|
+
# Matches: registry.register(OrderEvent, handler)
|
|
585
|
+
# False positive risk: Medium - .register() is a common method name
|
|
586
|
+
r"\.register\s*\(\s*['\"]?(\w+)['\"]?\s*,",
|
|
587
|
+
# Matches: event_bus.bind(OrderEvent, handler)
|
|
588
|
+
# False positive risk: Medium - .bind() could be used for other purposes
|
|
589
|
+
r"\.bind\s*\(\s*['\"]?(\w+)['\"]?\s*,",
|
|
590
|
+
# Matches: consumer.subscribe(topic, OrderEvent)
|
|
591
|
+
# False positive risk: Medium - second argument detection is heuristic
|
|
592
|
+
r"\.subscribe\s*\([^,]+,\s*['\"]?(\w+)['\"]?\s*\)",
|
|
593
|
+
# Dictionary patterns (mapping-based registration)
|
|
594
|
+
# Matches: handler_map[OrderEvent] = ...
|
|
595
|
+
# False positive risk: Low - specific to handler_map convention
|
|
596
|
+
r"handler_map\s*\[\s*['\"]?(\w+)['\"]?\s*\]",
|
|
597
|
+
]
|
|
598
|
+
|
|
599
|
+
compiled_patterns = [re.compile(p) for p in registration_patterns]
|
|
600
|
+
|
|
601
|
+
# Scan all Python files, excluding test files to reduce false positives
|
|
602
|
+
for file_path in source_directory.glob("**/*.py"):
|
|
603
|
+
# Skip files in excluded directories (archive, archived, examples, __pycache__)
|
|
604
|
+
# Uses exact path component matching to avoid false positives from substring
|
|
605
|
+
# matching (e.g., "my__pycache__dir" should NOT be skipped)
|
|
606
|
+
if should_skip_path(file_path):
|
|
607
|
+
continue
|
|
608
|
+
# Skip test files - they often contain mock registrations that
|
|
609
|
+
# would produce false positives (e.g., `registry.register(MockEvent, ...)`)
|
|
610
|
+
if file_path.name.startswith("test_") or file_path.name.endswith("_test.py"):
|
|
611
|
+
continue
|
|
612
|
+
if file_path.name == "conftest.py":
|
|
613
|
+
continue
|
|
614
|
+
|
|
615
|
+
try:
|
|
616
|
+
content = file_path.read_text(encoding="utf-8")
|
|
617
|
+
for pattern in compiled_patterns:
|
|
618
|
+
matches = pattern.findall(content)
|
|
619
|
+
registered_types.update(matches)
|
|
620
|
+
except UnicodeDecodeError as e:
|
|
621
|
+
logger.debug(
|
|
622
|
+
"Skipping file with encoding error during route discovery: %s (%s)",
|
|
623
|
+
file_path,
|
|
624
|
+
e.reason,
|
|
625
|
+
)
|
|
626
|
+
continue
|
|
627
|
+
except OSError as e:
|
|
628
|
+
logger.debug(
|
|
629
|
+
"Skipping file with OS error during route discovery: %s (%s)",
|
|
630
|
+
file_path,
|
|
631
|
+
e.strerror,
|
|
632
|
+
)
|
|
633
|
+
continue
|
|
634
|
+
|
|
635
|
+
return registered_types
|
|
636
|
+
|
|
637
|
+
|
|
638
|
+
# =============================================================================
|
|
639
|
+
# Routing Coverage Validator
|
|
640
|
+
# =============================================================================
|
|
641
|
+
|
|
642
|
+
|
|
643
|
+
class RoutingCoverageValidator:
|
|
644
|
+
"""Validator for ensuring all message types have registered routes.
|
|
645
|
+
|
|
646
|
+
This validator checks that every message type discovered in the source code
|
|
647
|
+
has a corresponding route registration. It supports both runtime inspection
|
|
648
|
+
and static analysis modes.
|
|
649
|
+
|
|
650
|
+
Attributes:
|
|
651
|
+
source_directory: Root directory to scan for message types.
|
|
652
|
+
registry: Optional runtime registry for route inspection.
|
|
653
|
+
|
|
654
|
+
Thread Safety:
|
|
655
|
+
This validator uses lazy initialization with double-checked locking.
|
|
656
|
+
The first call to validate_coverage() or get_unmapped_types() triggers
|
|
657
|
+
discovery, which is protected by a threading.Lock. Subsequent calls
|
|
658
|
+
use cached results without locking overhead.
|
|
659
|
+
|
|
660
|
+
Multiple threads can safely call validation methods concurrently.
|
|
661
|
+
The cached discovery results are immutable after initialization.
|
|
662
|
+
|
|
663
|
+
Performance:
|
|
664
|
+
**Lazy Initialization**: Discovery is deferred until first validation
|
|
665
|
+
call. This allows creating validators early without blocking on I/O.
|
|
666
|
+
|
|
667
|
+
**Caching**: After first discovery, results are cached. Repeated calls
|
|
668
|
+
to validate_coverage() reuse cached data without re-scanning.
|
|
669
|
+
|
|
670
|
+
**Refresh**: If source files change, call refresh() to clear cache
|
|
671
|
+
and re-discover on next validation call.
|
|
672
|
+
|
|
673
|
+
**When to create new instances vs reuse**:
|
|
674
|
+
- Reuse: Within a single application run for consistent results
|
|
675
|
+
- New instance: After source code changes, or for different directories
|
|
676
|
+
- CI pipelines: Typically create fresh instance per run
|
|
677
|
+
|
|
678
|
+
For startup validation, use validate_routing_coverage_on_startup()
|
|
679
|
+
which creates a fresh validator and performs immediate validation.
|
|
680
|
+
|
|
681
|
+
Example:
|
|
682
|
+
>>> validator = RoutingCoverageValidator(Path("src/omnibase_infra"))
|
|
683
|
+
>>> violations = validator.validate_coverage()
|
|
684
|
+
>>> if violations:
|
|
685
|
+
... for v in violations:
|
|
686
|
+
... print(v.format_for_ci())
|
|
687
|
+
|
|
688
|
+
>>> # Get coverage statistics
|
|
689
|
+
>>> report = validator.get_coverage_report()
|
|
690
|
+
>>> print(f"Coverage: {report.coverage_percent:.1f}%")
|
|
691
|
+
|
|
692
|
+
>>> # After source changes, refresh the cache
|
|
693
|
+
>>> validator.refresh()
|
|
694
|
+
>>> violations = validator.validate_coverage() # Re-discovers
|
|
695
|
+
"""
|
|
696
|
+
|
|
697
|
+
def __init__(
|
|
698
|
+
self,
|
|
699
|
+
source_directory: Path,
|
|
700
|
+
registry: RegistryProtocolBinding | None = None,
|
|
701
|
+
) -> None:
|
|
702
|
+
"""Initialize the routing coverage validator.
|
|
703
|
+
|
|
704
|
+
Args:
|
|
705
|
+
source_directory: Root directory to scan for message types.
|
|
706
|
+
registry: Optional runtime registry for route inspection.
|
|
707
|
+
"""
|
|
708
|
+
self.source_directory = source_directory
|
|
709
|
+
self.registry = registry
|
|
710
|
+
self._lock = threading.Lock()
|
|
711
|
+
# Explicit initialization flag - more robust than checking data fields
|
|
712
|
+
# See _ensure_discovery() docstring for thread safety rationale
|
|
713
|
+
self._initialized = False
|
|
714
|
+
self._discovered_types: dict[str, MessageOutputCategory] | None = None
|
|
715
|
+
self._registered_routes: set[str] | None = None
|
|
716
|
+
|
|
717
|
+
def _ensure_discovery(self) -> None:
|
|
718
|
+
"""Ensure discovery has been performed (lazy initialization).
|
|
719
|
+
|
|
720
|
+
Thread Safety:
|
|
721
|
+
Uses double-checked locking with an explicit _initialized flag.
|
|
722
|
+
|
|
723
|
+
Why a separate flag instead of checking data fields?
|
|
724
|
+
- Eliminates ordering dependency between field assignments
|
|
725
|
+
- Future refactoring can't accidentally break the invariant
|
|
726
|
+
- The flag is only set True AFTER all fields are fully populated
|
|
727
|
+
- Any thread seeing _initialized=True is guaranteed to see
|
|
728
|
+
both _discovered_types and _registered_routes populated
|
|
729
|
+
|
|
730
|
+
The pattern:
|
|
731
|
+
1. Check _initialized without lock (fast path for already-initialized)
|
|
732
|
+
2. Acquire lock and re-check (prevents duplicate initialization)
|
|
733
|
+
3. Set all data fields first
|
|
734
|
+
4. Set _initialized=True last (makes state visible atomically)
|
|
735
|
+
"""
|
|
736
|
+
if not self._initialized:
|
|
737
|
+
with self._lock:
|
|
738
|
+
if not self._initialized:
|
|
739
|
+
self._discovered_types = discover_message_types(
|
|
740
|
+
self.source_directory
|
|
741
|
+
)
|
|
742
|
+
self._registered_routes = discover_registered_routes(
|
|
743
|
+
registry=self.registry,
|
|
744
|
+
source_directory=self.source_directory,
|
|
745
|
+
)
|
|
746
|
+
# CRITICAL: Set _initialized LAST to ensure all fields
|
|
747
|
+
# are visible to other threads before they skip the lock
|
|
748
|
+
self._initialized = True
|
|
749
|
+
|
|
750
|
+
def validate_coverage(self) -> list[ModelExecutionShapeViolationResult]:
|
|
751
|
+
"""Validate all message types are registered.
|
|
752
|
+
|
|
753
|
+
Returns:
|
|
754
|
+
List of violations for unmapped types. Empty if all types are mapped.
|
|
755
|
+
|
|
756
|
+
Example:
|
|
757
|
+
>>> validator = RoutingCoverageValidator(Path("src"))
|
|
758
|
+
>>> violations = validator.validate_coverage()
|
|
759
|
+
>>> for v in violations:
|
|
760
|
+
... print(f"{v.file_path}:{v.line_number}: {v.message}")
|
|
761
|
+
"""
|
|
762
|
+
self._ensure_discovery()
|
|
763
|
+
assert self._discovered_types is not None
|
|
764
|
+
assert self._registered_routes is not None
|
|
765
|
+
|
|
766
|
+
violations: list[ModelExecutionShapeViolationResult] = []
|
|
767
|
+
unmapped = self.get_unmapped_types()
|
|
768
|
+
|
|
769
|
+
for type_name in sorted(unmapped):
|
|
770
|
+
category = self._discovered_types.get(type_name)
|
|
771
|
+
category_name = category.value if category else "unknown"
|
|
772
|
+
|
|
773
|
+
# Routing coverage is a configuration issue, not specific to any node archetype.
|
|
774
|
+
# node_archetype is None because this violation is about missing routing
|
|
775
|
+
# registration, not about a specific handler's behavior.
|
|
776
|
+
# Use UNMAPPED_MESSAGE_ROUTE for semantic correctness - this is a routing
|
|
777
|
+
# configuration issue, not a topic/category mismatch.
|
|
778
|
+
violation = ModelExecutionShapeViolationResult(
|
|
779
|
+
violation_type=EnumExecutionShapeViolation.UNMAPPED_MESSAGE_ROUTE,
|
|
780
|
+
node_archetype=None, # Routing coverage is not archetype-specific
|
|
781
|
+
file_path=str(self.source_directory),
|
|
782
|
+
line_number=1,
|
|
783
|
+
message=(
|
|
784
|
+
f"Message type '{type_name}' ({category_name}) is not registered "
|
|
785
|
+
f"in routing configuration"
|
|
786
|
+
),
|
|
787
|
+
severity=EnumValidationSeverity.ERROR,
|
|
788
|
+
)
|
|
789
|
+
violations.append(violation)
|
|
790
|
+
|
|
791
|
+
return violations
|
|
792
|
+
|
|
793
|
+
def get_unmapped_types(self) -> set[str]:
|
|
794
|
+
"""Get message types that are not registered.
|
|
795
|
+
|
|
796
|
+
Returns:
|
|
797
|
+
Set of message type class names without routing registration.
|
|
798
|
+
"""
|
|
799
|
+
self._ensure_discovery()
|
|
800
|
+
assert self._discovered_types is not None
|
|
801
|
+
assert self._registered_routes is not None
|
|
802
|
+
|
|
803
|
+
discovered_names = set(self._discovered_types.keys())
|
|
804
|
+
return discovered_names - self._registered_routes
|
|
805
|
+
|
|
806
|
+
def get_coverage_report(self) -> ModelCoverageMetrics:
|
|
807
|
+
"""Get coverage statistics.
|
|
808
|
+
|
|
809
|
+
Returns:
|
|
810
|
+
ModelCoverageMetrics containing:
|
|
811
|
+
- total_types: Total number of discovered message types
|
|
812
|
+
- registered_types: Number of types with registered routes
|
|
813
|
+
- unmapped_types: List of type names without routes
|
|
814
|
+
- coverage_percent: Percentage of types with routes
|
|
815
|
+
"""
|
|
816
|
+
self._ensure_discovery()
|
|
817
|
+
assert self._discovered_types is not None
|
|
818
|
+
assert self._registered_routes is not None
|
|
819
|
+
|
|
820
|
+
return ModelCoverageMetrics.from_discovery(
|
|
821
|
+
discovered_types=self._discovered_types,
|
|
822
|
+
registered_routes=self._registered_routes,
|
|
823
|
+
)
|
|
824
|
+
|
|
825
|
+
def fail_fast_on_unmapped(self) -> None:
|
|
826
|
+
"""Raise exception if any message types are unmapped.
|
|
827
|
+
|
|
828
|
+
This method is intended for use during application startup to ensure
|
|
829
|
+
all message types have routing configured before the application
|
|
830
|
+
accepts requests.
|
|
831
|
+
|
|
832
|
+
Raises:
|
|
833
|
+
RoutingCoverageError: If any message types are unmapped.
|
|
834
|
+
|
|
835
|
+
Example:
|
|
836
|
+
>>> validator = RoutingCoverageValidator(Path("src"))
|
|
837
|
+
>>> try:
|
|
838
|
+
... validator.fail_fast_on_unmapped()
|
|
839
|
+
... except RoutingCoverageError as e:
|
|
840
|
+
... print(f"Missing routes for: {e.unmapped_types}")
|
|
841
|
+
... sys.exit(1)
|
|
842
|
+
"""
|
|
843
|
+
self._ensure_discovery()
|
|
844
|
+
assert self._discovered_types is not None
|
|
845
|
+
|
|
846
|
+
unmapped = self.get_unmapped_types()
|
|
847
|
+
if unmapped:
|
|
848
|
+
total = len(self._discovered_types)
|
|
849
|
+
registered = total - len(unmapped)
|
|
850
|
+
raise RoutingCoverageError(
|
|
851
|
+
unmapped_types=unmapped,
|
|
852
|
+
total_types=total,
|
|
853
|
+
registered_types=registered,
|
|
854
|
+
)
|
|
855
|
+
|
|
856
|
+
def refresh(self) -> None:
|
|
857
|
+
"""Clear cached discovery results and re-scan.
|
|
858
|
+
|
|
859
|
+
Call this method if source files have changed and you need
|
|
860
|
+
to re-discover message types and routes.
|
|
861
|
+
|
|
862
|
+
Thread Safety:
|
|
863
|
+
Clears _initialized FIRST to ensure any concurrent readers
|
|
864
|
+
see the invalidated state and wait for the lock.
|
|
865
|
+
"""
|
|
866
|
+
with self._lock:
|
|
867
|
+
# CRITICAL: Clear _initialized FIRST to invalidate
|
|
868
|
+
# Any thread checking this will then acquire the lock
|
|
869
|
+
self._initialized = False
|
|
870
|
+
self._discovered_types = None
|
|
871
|
+
self._registered_routes = None
|
|
872
|
+
|
|
873
|
+
|
|
874
|
+
# =============================================================================
|
|
875
|
+
# Integration Functions
|
|
876
|
+
# =============================================================================
|
|
877
|
+
|
|
878
|
+
|
|
879
|
+
def validate_routing_coverage_on_startup(
|
|
880
|
+
source_directory: Path,
|
|
881
|
+
fail_on_unmapped: bool = True,
|
|
882
|
+
registry: RegistryProtocolBinding | None = None,
|
|
883
|
+
) -> bool:
|
|
884
|
+
"""Validate routing coverage at application startup.
|
|
885
|
+
|
|
886
|
+
This function is designed to be called during application initialization
|
|
887
|
+
to ensure all message types have routing configured. If fail_on_unmapped
|
|
888
|
+
is True, the application will fail fast with a clear error message.
|
|
889
|
+
|
|
890
|
+
Args:
|
|
891
|
+
source_directory: Root directory to scan for message types.
|
|
892
|
+
fail_on_unmapped: If True, raise exception on unmapped types.
|
|
893
|
+
registry: Optional runtime registry for route inspection.
|
|
894
|
+
|
|
895
|
+
Returns:
|
|
896
|
+
True if all types are mapped, False otherwise.
|
|
897
|
+
|
|
898
|
+
Raises:
|
|
899
|
+
RoutingCoverageError: If fail_on_unmapped and types are unmapped.
|
|
900
|
+
|
|
901
|
+
Example:
|
|
902
|
+
>>> # In your application startup code
|
|
903
|
+
>>> from omnibase_infra.validation import validate_routing_coverage_on_startup
|
|
904
|
+
>>>
|
|
905
|
+
>>> def main():
|
|
906
|
+
... # Validate routing before accepting requests
|
|
907
|
+
... validate_routing_coverage_on_startup(
|
|
908
|
+
... source_directory=Path("src/myapp"),
|
|
909
|
+
... fail_on_unmapped=True,
|
|
910
|
+
... )
|
|
911
|
+
...
|
|
912
|
+
... # Continue with application startup
|
|
913
|
+
... app.run()
|
|
914
|
+
"""
|
|
915
|
+
validator = RoutingCoverageValidator(
|
|
916
|
+
source_directory=source_directory,
|
|
917
|
+
registry=registry,
|
|
918
|
+
)
|
|
919
|
+
|
|
920
|
+
if fail_on_unmapped:
|
|
921
|
+
validator.fail_fast_on_unmapped()
|
|
922
|
+
return True
|
|
923
|
+
|
|
924
|
+
unmapped = validator.get_unmapped_types()
|
|
925
|
+
return len(unmapped) == 0
|
|
926
|
+
|
|
927
|
+
|
|
928
|
+
def check_routing_coverage_ci(
|
|
929
|
+
source_directory: Path,
|
|
930
|
+
registry: RegistryProtocolBinding | None = None,
|
|
931
|
+
) -> tuple[bool, list[ModelExecutionShapeViolationResult]]:
|
|
932
|
+
"""CI gate for routing coverage.
|
|
933
|
+
|
|
934
|
+
This function is designed for CI/CD pipeline integration. It returns
|
|
935
|
+
both a pass/fail status and a list of violations that can be formatted
|
|
936
|
+
for CI output (e.g., GitHub Actions annotations).
|
|
937
|
+
|
|
938
|
+
Args:
|
|
939
|
+
source_directory: Root directory to scan for message types.
|
|
940
|
+
registry: Optional runtime registry for route inspection.
|
|
941
|
+
|
|
942
|
+
Returns:
|
|
943
|
+
Tuple of (passed, violations) where:
|
|
944
|
+
- passed: True if all types have routes
|
|
945
|
+
- violations: List of ModelExecutionShapeViolationResult for CI output
|
|
946
|
+
|
|
947
|
+
Example:
|
|
948
|
+
>>> # In your CI script
|
|
949
|
+
>>> from omnibase_infra.validation import check_routing_coverage_ci
|
|
950
|
+
>>>
|
|
951
|
+
>>> passed, violations = check_routing_coverage_ci(Path("src"))
|
|
952
|
+
>>>
|
|
953
|
+
>>> # Output in GitHub Actions format
|
|
954
|
+
>>> for v in violations:
|
|
955
|
+
... print(v.format_for_ci())
|
|
956
|
+
>>>
|
|
957
|
+
>>> sys.exit(0 if passed else 1)
|
|
958
|
+
"""
|
|
959
|
+
validator = RoutingCoverageValidator(
|
|
960
|
+
source_directory=source_directory,
|
|
961
|
+
registry=registry,
|
|
962
|
+
)
|
|
963
|
+
|
|
964
|
+
violations = validator.validate_coverage()
|
|
965
|
+
passed = len(violations) == 0
|
|
966
|
+
|
|
967
|
+
return passed, violations
|
|
968
|
+
|
|
969
|
+
|
|
970
|
+
# =============================================================================
|
|
971
|
+
# Design Note: Why No Module-Level Singleton
|
|
972
|
+
# =============================================================================
|
|
973
|
+
#
|
|
974
|
+
# Unlike other validators (ExecutionShapeValidator, RuntimeShapeValidator,
|
|
975
|
+
# TopicCategoryValidator), the RoutingCoverageValidator is NOT cached as a
|
|
976
|
+
# module-level singleton. This is an intentional design decision:
|
|
977
|
+
#
|
|
978
|
+
# 1. **Parameterized Construction**: Each RoutingCoverageValidator requires a
|
|
979
|
+
# source_directory parameter. Different callers may validate different
|
|
980
|
+
# directories (e.g., "src/handlers" vs "src/events").
|
|
981
|
+
#
|
|
982
|
+
# 2. **Stateful Discovery**: The validator caches discovered message types
|
|
983
|
+
# and routes internally. This state is tied to the specific source_directory.
|
|
984
|
+
# A singleton would only work for one directory.
|
|
985
|
+
#
|
|
986
|
+
# 3. **Built-in Caching**: The validator already implements lazy initialization
|
|
987
|
+
# with thread-safe locking (_ensure_discovery). Callers who need repeated
|
|
988
|
+
# validation of the same directory should keep a reference to their validator
|
|
989
|
+
# instance rather than relying on a module-level singleton.
|
|
990
|
+
#
|
|
991
|
+
# 4. **Refresh Capability**: The refresh() method allows re-scanning after
|
|
992
|
+
# source file changes. This per-instance state management wouldn't work
|
|
993
|
+
# well with a shared singleton.
|
|
994
|
+
#
|
|
995
|
+
# Performance Recommendation for Callers:
|
|
996
|
+
# # For repeated validation of the same directory, reuse the instance:
|
|
997
|
+
# validator = RoutingCoverageValidator(Path("src/handlers"))
|
|
998
|
+
# violations = validator.validate_coverage() # Discovery happens here
|
|
999
|
+
# report = validator.get_coverage_report() # Uses cached discovery
|
|
1000
|
+
#
|
|
1001
|
+
# # For one-time CI validation, the integration functions are sufficient:
|
|
1002
|
+
# passed, violations = check_routing_coverage_ci(Path("src/handlers"))
|
|
1003
|
+
|
|
1004
|
+
# =============================================================================
|
|
1005
|
+
# Module Exports
|
|
1006
|
+
# =============================================================================
|
|
1007
|
+
|
|
1008
|
+
|
|
1009
|
+
__all__: list[str] = [
|
|
1010
|
+
# Exception
|
|
1011
|
+
"RoutingCoverageError",
|
|
1012
|
+
# Validator class
|
|
1013
|
+
"RoutingCoverageValidator",
|
|
1014
|
+
"check_routing_coverage_ci",
|
|
1015
|
+
# Discovery functions
|
|
1016
|
+
"discover_message_types",
|
|
1017
|
+
"discover_registered_routes",
|
|
1018
|
+
# Integration functions
|
|
1019
|
+
"validate_routing_coverage_on_startup",
|
|
1020
|
+
]
|