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,1143 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Compute Registry - SINGLE SOURCE OF TRUTH for compute plugin registration.
|
|
4
|
+
|
|
5
|
+
This module provides the RegistryCompute class for registering and resolving
|
|
6
|
+
deterministic compute plugins in the ONEX infrastructure layer.
|
|
7
|
+
|
|
8
|
+
Compute plugins:
|
|
9
|
+
- Perform deterministic, in-process computation with NO external I/O
|
|
10
|
+
- Examples: JSON normalization, ranking/scoring, policy evaluation, diffing, AST transforms
|
|
11
|
+
- MUST be synchronous by default (async requires explicit deterministic_async=True flag)
|
|
12
|
+
|
|
13
|
+
Design Principles:
|
|
14
|
+
- Single source of truth: All compute plugin registrations go through this registry
|
|
15
|
+
- Sync enforcement: Async plugins must be explicitly flagged
|
|
16
|
+
- Type-safe: Full typing for plugin registrations (no Any types)
|
|
17
|
+
- Thread-safe: Registration operations protected by lock
|
|
18
|
+
- Testable: Easy to mock and test plugin configurations
|
|
19
|
+
|
|
20
|
+
CRITICAL: Compute plugins are PURE computation logic only.
|
|
21
|
+
|
|
22
|
+
Compute plugins MUST NOT:
|
|
23
|
+
- Perform I/O operations (file, network, database)
|
|
24
|
+
- Have side effects (state mutation outside return values)
|
|
25
|
+
- Make external service calls
|
|
26
|
+
- Log at runtime
|
|
27
|
+
- Depend on mutable global state
|
|
28
|
+
- Access current time (unless explicitly provided as input)
|
|
29
|
+
- Use random number generation (unless deterministic with provided seed)
|
|
30
|
+
|
|
31
|
+
Example Usage:
|
|
32
|
+
```python
|
|
33
|
+
from omnibase_core.container import ModelONEXContainer
|
|
34
|
+
from omnibase_infra.runtime.registry_compute import RegistryCompute
|
|
35
|
+
from omnibase_infra.runtime.models import ModelComputeRegistration
|
|
36
|
+
|
|
37
|
+
# Container-based DI (preferred)
|
|
38
|
+
container = ModelONEXContainer()
|
|
39
|
+
await wire_infrastructure_services(container)
|
|
40
|
+
registry = await container.service_registry.resolve_service(RegistryCompute)
|
|
41
|
+
|
|
42
|
+
# Register a synchronous plugin using the model (preferred)
|
|
43
|
+
registration = ModelComputeRegistration(
|
|
44
|
+
plugin_id="json_normalizer",
|
|
45
|
+
plugin_class=JsonNormalizerPlugin,
|
|
46
|
+
version="1.0.0",
|
|
47
|
+
description="Normalizes JSON for deterministic comparison",
|
|
48
|
+
)
|
|
49
|
+
registry.register(registration)
|
|
50
|
+
|
|
51
|
+
# Register using convenience method
|
|
52
|
+
registry.register_plugin(
|
|
53
|
+
plugin_id="async_transformer",
|
|
54
|
+
plugin_class=AsyncTransformerPlugin,
|
|
55
|
+
version="1.0.0",
|
|
56
|
+
deterministic_async=True, # MUST be explicit for async plugins
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
# Retrieve a plugin
|
|
60
|
+
plugin_cls = registry.get("json_normalizer")
|
|
61
|
+
plugin = plugin_cls()
|
|
62
|
+
result = plugin.execute(input_data, context)
|
|
63
|
+
|
|
64
|
+
# List all plugins
|
|
65
|
+
plugins = registry.list_keys() # [(plugin_id, version), ...]
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Integration Points:
|
|
69
|
+
- RuntimeHostProcess uses this registry to discover and instantiate compute plugins
|
|
70
|
+
- Plugins are loaded based on contract definitions
|
|
71
|
+
- Supports hot-reload patterns for development
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
from __future__ import annotations
|
|
75
|
+
|
|
76
|
+
import asyncio
|
|
77
|
+
import functools
|
|
78
|
+
import inspect
|
|
79
|
+
import logging
|
|
80
|
+
import os
|
|
81
|
+
import threading
|
|
82
|
+
import time
|
|
83
|
+
import warnings
|
|
84
|
+
from collections.abc import Callable
|
|
85
|
+
from typing import TYPE_CHECKING
|
|
86
|
+
|
|
87
|
+
from omnibase_infra.errors import (
|
|
88
|
+
ComputeRegistryError,
|
|
89
|
+
ModelInfraErrorContext,
|
|
90
|
+
ProtocolConfigurationError,
|
|
91
|
+
)
|
|
92
|
+
from omnibase_infra.runtime.models import ModelComputeRegistration
|
|
93
|
+
from omnibase_infra.runtime.models.model_compute_key import ModelComputeKey
|
|
94
|
+
|
|
95
|
+
if TYPE_CHECKING:
|
|
96
|
+
from omnibase_infra.protocols import ProtocolPluginCompute, ProtocolRegistryMetrics
|
|
97
|
+
|
|
98
|
+
# Module-level logger for metrics and registry operations
|
|
99
|
+
logger = logging.getLogger(__name__)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
# =============================================================================
|
|
103
|
+
# Metrics Timer Utility
|
|
104
|
+
# =============================================================================
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class _MetricsTimer:
|
|
108
|
+
"""Context manager for timing operations.
|
|
109
|
+
|
|
110
|
+
Provides high-precision timing using time.perf_counter() for accurate
|
|
111
|
+
latency measurements in the registry metrics system.
|
|
112
|
+
|
|
113
|
+
Attributes:
|
|
114
|
+
elapsed_ms: Time elapsed in milliseconds after exiting the context.
|
|
115
|
+
|
|
116
|
+
Example:
|
|
117
|
+
>>> timer = _MetricsTimer()
|
|
118
|
+
>>> with timer:
|
|
119
|
+
... # perform operation
|
|
120
|
+
... result = expensive_operation()
|
|
121
|
+
>>> print(f"Operation took {timer.elapsed_ms:.2f}ms")
|
|
122
|
+
"""
|
|
123
|
+
|
|
124
|
+
def __init__(self) -> None:
|
|
125
|
+
"""Initialize timer with zero elapsed time."""
|
|
126
|
+
self.elapsed_ms: float = 0.0
|
|
127
|
+
self._start: float = 0.0
|
|
128
|
+
|
|
129
|
+
def __enter__(self) -> _MetricsTimer:
|
|
130
|
+
"""Start timing on context entry."""
|
|
131
|
+
self._start = time.perf_counter()
|
|
132
|
+
return self
|
|
133
|
+
|
|
134
|
+
def __exit__(self, *args: object) -> None:
|
|
135
|
+
"""Calculate elapsed time on context exit."""
|
|
136
|
+
self.elapsed_ms = (time.perf_counter() - self._start) * 1000
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
# =============================================================================
|
|
140
|
+
# Compute Registry
|
|
141
|
+
# =============================================================================
|
|
142
|
+
|
|
143
|
+
# Semver sorting sentinel value (chr(127) = DEL character, ASCII 127)
|
|
144
|
+
# WHY chr(127): In semantic versioning, releases sort AFTER prereleases:
|
|
145
|
+
# - "1.0.0-alpha" < "1.0.0" (prerelease comes before release)
|
|
146
|
+
# - "1.0.0-beta" < "1.0.0"
|
|
147
|
+
#
|
|
148
|
+
# For string comparison to work correctly:
|
|
149
|
+
# - Prerelease strings (e.g., "alpha", "beta") are compared lexicographically
|
|
150
|
+
# - Empty prerelease (release version) needs to sort AFTER any prerelease string
|
|
151
|
+
# - chr(127) is the highest printable ASCII value (DEL character)
|
|
152
|
+
# - Any prerelease string ("alpha", "rc", "beta") < chr(127)
|
|
153
|
+
# - Therefore: ("1.0.0-alpha") < ("1.0.0") because "alpha" < chr(127)
|
|
154
|
+
_SEMVER_SORT_SENTINEL = chr(127)
|
|
155
|
+
|
|
156
|
+
# Environment variable for configuring the semver LRU cache size
|
|
157
|
+
# Set ONEX_COMPUTE_REGISTRY_CACHE_SIZE to tune cache size for large deployments
|
|
158
|
+
ENV_COMPUTE_REGISTRY_CACHE_SIZE = "ONEX_COMPUTE_REGISTRY_CACHE_SIZE"
|
|
159
|
+
|
|
160
|
+
# Default cache size when environment variable is not set
|
|
161
|
+
_DEFAULT_SEMVER_CACHE_SIZE = 128
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def _get_compute_registry_cache_size() -> int:
|
|
165
|
+
"""Get compute registry cache size from environment.
|
|
166
|
+
|
|
167
|
+
Reads the ONEX_COMPUTE_REGISTRY_CACHE_SIZE environment variable.
|
|
168
|
+
If not set, returns the default cache size.
|
|
169
|
+
|
|
170
|
+
Range validation: Cache size must be between 1 and 10000.
|
|
171
|
+
- Below 1: Uses default (logged as warning)
|
|
172
|
+
- Above 10000: Uses default (logged as warning)
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
Cache size as an integer.
|
|
176
|
+
|
|
177
|
+
Raises:
|
|
178
|
+
ProtocolConfigurationError: If the environment variable contains
|
|
179
|
+
a non-integer value.
|
|
180
|
+
"""
|
|
181
|
+
from omnibase_infra.enums import EnumInfraTransportType
|
|
182
|
+
from omnibase_infra.utils.util_env_parsing import parse_env_int
|
|
183
|
+
|
|
184
|
+
if os.environ.get(ENV_COMPUTE_REGISTRY_CACHE_SIZE) is not None:
|
|
185
|
+
return parse_env_int(
|
|
186
|
+
ENV_COMPUTE_REGISTRY_CACHE_SIZE,
|
|
187
|
+
_DEFAULT_SEMVER_CACHE_SIZE,
|
|
188
|
+
min_value=1,
|
|
189
|
+
max_value=10000,
|
|
190
|
+
transport_type=EnumInfraTransportType.HTTP,
|
|
191
|
+
service_name="compute_registry",
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
return _DEFAULT_SEMVER_CACHE_SIZE
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
class RegistryCompute:
|
|
198
|
+
"""SINGLE SOURCE OF TRUTH for compute plugin registration in omnibase_infra.
|
|
199
|
+
|
|
200
|
+
Thread-safe registry for compute plugins. Manages deterministic computation plugins
|
|
201
|
+
that perform pure data transformations without side effects.
|
|
202
|
+
|
|
203
|
+
The registry maintains a mapping from ModelComputeKey instances to plugin classes
|
|
204
|
+
that implement the ProtocolPluginCompute protocol. ModelComputeKey provides strong
|
|
205
|
+
typing and replaces the legacy tuple[str, str] pattern.
|
|
206
|
+
|
|
207
|
+
Container Integration:
|
|
208
|
+
RegistryCompute is designed to be managed by ModelONEXContainer from omnibase_core.
|
|
209
|
+
Use container_wiring.wire_infrastructure_services() to register RegistryCompute
|
|
210
|
+
in the container, then resolve it via:
|
|
211
|
+
|
|
212
|
+
```python
|
|
213
|
+
from omnibase_core.container import ModelONEXContainer
|
|
214
|
+
from omnibase_infra.runtime.registry_compute import RegistryCompute
|
|
215
|
+
|
|
216
|
+
# Resolve from container (preferred)
|
|
217
|
+
registry = await container.service_registry.resolve_service(RegistryCompute)
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Thread Safety:
|
|
221
|
+
All registration operations are protected by a threading.Lock to ensure
|
|
222
|
+
thread-safe access in concurrent environments.
|
|
223
|
+
|
|
224
|
+
Sync Enforcement:
|
|
225
|
+
By default, plugins must be synchronous. If a plugin has async methods
|
|
226
|
+
(execute or any public method), registration will fail unless
|
|
227
|
+
deterministic_async=True is explicitly specified.
|
|
228
|
+
|
|
229
|
+
Scale and Performance Characteristics:
|
|
230
|
+
|
|
231
|
+
Expected Registry Scale:
|
|
232
|
+
- Typical ONEX system: 10-30 unique compute plugins across 2-5 versions each
|
|
233
|
+
- Medium deployment: 30-50 plugins across 3-8 versions each
|
|
234
|
+
- Large deployment: 50-100 plugins across 5-10 versions each
|
|
235
|
+
- Stress tested: 500+ total registrations (100 plugins x 5 versions)
|
|
236
|
+
|
|
237
|
+
Performance Characteristics:
|
|
238
|
+
|
|
239
|
+
Primary Operations:
|
|
240
|
+
- register(): O(1) - Direct dictionary insert with secondary index update
|
|
241
|
+
- get(plugin_id): O(1) best case, O(k) average
|
|
242
|
+
where k = number of matching versions
|
|
243
|
+
- Uses secondary index (_plugin_id_index) for O(1) plugin_id lookup
|
|
244
|
+
- Fast path (single version): O(1) direct lookup
|
|
245
|
+
- Multi-version: O(k) to find max version via comparison
|
|
246
|
+
- Cached semver parsing: LRU cache (128 entries) avoids re-parsing
|
|
247
|
+
|
|
248
|
+
- is_registered(): O(k) where k = versions for plugin_id
|
|
249
|
+
- list_keys(): O(n*log n) where n = total registrations (full scan + sort)
|
|
250
|
+
- list_versions(): O(k) where k = versions for plugin_id
|
|
251
|
+
- unregister(): O(k) where k = versions for plugin_id
|
|
252
|
+
|
|
253
|
+
Benchmark Targets (match RegistryPolicy):
|
|
254
|
+
- 1000 sequential get() calls: < 100ms (< 0.1ms per lookup)
|
|
255
|
+
- 1000 concurrent get() calls (10 threads): < 500ms
|
|
256
|
+
- 100 failed lookups (missing plugin_id): < 500ms (early exit optimization)
|
|
257
|
+
|
|
258
|
+
Lock Contention:
|
|
259
|
+
- Read operations (get, is_registered): Hold lock during lookup only
|
|
260
|
+
- Write operations (register, unregister): Hold lock for full operation
|
|
261
|
+
- Critical sections minimized to reduce contention
|
|
262
|
+
- Expected concurrent throughput: > 2000 reads/sec under 10-thread load
|
|
263
|
+
|
|
264
|
+
Memory Footprint:
|
|
265
|
+
|
|
266
|
+
Per Plugin Registration:
|
|
267
|
+
- ModelComputeKey: ~160 bytes (2 strings: plugin_id, version)
|
|
268
|
+
- Plugin class reference: 8 bytes (Python object pointer)
|
|
269
|
+
- Secondary index entry: ~50 bytes (list entry + key reference)
|
|
270
|
+
- Total per registration: ~220 bytes
|
|
271
|
+
|
|
272
|
+
Estimated Registry Memory:
|
|
273
|
+
- 50 registrations: ~11 KB
|
|
274
|
+
- 100 registrations: ~22 KB
|
|
275
|
+
- 500 registrations: ~110 KB
|
|
276
|
+
|
|
277
|
+
Cache Overhead:
|
|
278
|
+
- Semver LRU cache: Configurable via ONEX_COMPUTE_REGISTRY_CACHE_SIZE env var
|
|
279
|
+
(default: 128 entries x ~100 bytes = ~12.8 KB)
|
|
280
|
+
- Total with cache: Registry memory + cache overhead
|
|
281
|
+
|
|
282
|
+
Environment Variables:
|
|
283
|
+
ONEX_COMPUTE_REGISTRY_CACHE_SIZE: Configure the semver LRU cache size for large
|
|
284
|
+
deployments. Set to a higher value (e.g., 256, 512) if you have many
|
|
285
|
+
unique version strings. Default: 128.
|
|
286
|
+
|
|
287
|
+
Attributes:
|
|
288
|
+
_registry: Internal dictionary mapping ModelComputeKey instances to plugin classes
|
|
289
|
+
_lock: Threading lock for thread-safe registration operations
|
|
290
|
+
_plugin_id_index: Secondary index for O(1) plugin_id lookup
|
|
291
|
+
SEMVER_CACHE_SIZE: Class variable for LRU cache size, read from
|
|
292
|
+
ONEX_COMPUTE_REGISTRY_CACHE_SIZE environment variable (default: 128)
|
|
293
|
+
|
|
294
|
+
Example:
|
|
295
|
+
>>> from omnibase_infra.runtime.models import ModelComputeRegistration
|
|
296
|
+
>>> from omnibase_infra.runtime.models.model_compute_key import ModelComputeKey
|
|
297
|
+
>>> registry = RegistryCompute()
|
|
298
|
+
>>> registration = ModelComputeRegistration(
|
|
299
|
+
... plugin_id="json_normalizer",
|
|
300
|
+
... plugin_class=JsonNormalizerPlugin,
|
|
301
|
+
... )
|
|
302
|
+
>>> registry.register(registration)
|
|
303
|
+
>>> plugin_cls = registry.get("json_normalizer")
|
|
304
|
+
>>> print(registry.list_keys())
|
|
305
|
+
[('json_normalizer', '1.0.0')]
|
|
306
|
+
"""
|
|
307
|
+
|
|
308
|
+
# ==========================================================================
|
|
309
|
+
# Class-level semver cache configuration
|
|
310
|
+
# ==========================================================================
|
|
311
|
+
|
|
312
|
+
# Semver cache size - configurable via ONEX_COMPUTE_REGISTRY_CACHE_SIZE env var
|
|
313
|
+
# Read at class definition time; can be overridden via class attribute before first parse
|
|
314
|
+
SEMVER_CACHE_SIZE: int = _get_compute_registry_cache_size()
|
|
315
|
+
|
|
316
|
+
# Cached semver parser function (lazily initialized)
|
|
317
|
+
_semver_cache: Callable[[str], tuple[int, int, int, str]] | None = None
|
|
318
|
+
|
|
319
|
+
# Lock for thread-safe cache initialization
|
|
320
|
+
_semver_cache_lock: threading.Lock = threading.Lock()
|
|
321
|
+
|
|
322
|
+
def __init__(
|
|
323
|
+
self, metrics_collector: ProtocolRegistryMetrics | None = None
|
|
324
|
+
) -> None:
|
|
325
|
+
"""Initialize an empty compute registry with thread lock.
|
|
326
|
+
|
|
327
|
+
Args:
|
|
328
|
+
metrics_collector: Optional metrics collector for production monitoring.
|
|
329
|
+
If provided, registry operations will record latency, cache hits/misses,
|
|
330
|
+
registry size changes, and errors to the collector.
|
|
331
|
+
See ProtocolRegistryMetrics for the expected interface.
|
|
332
|
+
"""
|
|
333
|
+
# Key: ModelComputeKey -> plugin_class (strong typing replaces tuple pattern)
|
|
334
|
+
self._registry: dict[ModelComputeKey, type[ProtocolPluginCompute]] = {}
|
|
335
|
+
self._lock: threading.Lock = threading.Lock()
|
|
336
|
+
|
|
337
|
+
# Performance optimization: Secondary indexes for O(1) lookups
|
|
338
|
+
# Maps plugin_id -> list of ModelComputeKey instances
|
|
339
|
+
self._plugin_id_index: dict[str, list[ModelComputeKey]] = {}
|
|
340
|
+
|
|
341
|
+
# Optional metrics collector for production monitoring
|
|
342
|
+
self._metrics: ProtocolRegistryMetrics | None = metrics_collector
|
|
343
|
+
|
|
344
|
+
def set_metrics_collector(self, collector: ProtocolRegistryMetrics | None) -> None:
|
|
345
|
+
"""Set the metrics collector for production monitoring.
|
|
346
|
+
|
|
347
|
+
This method allows setting or changing the metrics collector after
|
|
348
|
+
initialization. Pass None to disable metrics collection.
|
|
349
|
+
|
|
350
|
+
Args:
|
|
351
|
+
collector: Metrics collector implementing ProtocolRegistryMetrics,
|
|
352
|
+
or None to disable metrics collection.
|
|
353
|
+
|
|
354
|
+
Example:
|
|
355
|
+
>>> from omnibase_infra.runtime.registry_compute import RegistryCompute
|
|
356
|
+
>>> registry = RegistryCompute()
|
|
357
|
+
>>> # Later, enable metrics
|
|
358
|
+
>>> registry.set_metrics_collector(my_metrics)
|
|
359
|
+
>>> # Or disable
|
|
360
|
+
>>> registry.set_metrics_collector(None)
|
|
361
|
+
"""
|
|
362
|
+
self._metrics = collector
|
|
363
|
+
|
|
364
|
+
def _validate_sync_enforcement(
|
|
365
|
+
self,
|
|
366
|
+
plugin_id: str,
|
|
367
|
+
plugin_class: type,
|
|
368
|
+
deterministic_async: bool,
|
|
369
|
+
) -> None:
|
|
370
|
+
"""Validate that plugin is synchronous unless explicitly flagged.
|
|
371
|
+
|
|
372
|
+
CRITICAL: This validation inspects ALL public methods, not just execute().
|
|
373
|
+
This ensures that compute plugins with any async methods are flagged properly.
|
|
374
|
+
|
|
375
|
+
This validation enforces the synchronous-by-default plugin execution model.
|
|
376
|
+
Compute plugins are expected to be pure computation logic without I/O or async
|
|
377
|
+
operations. If a plugin needs async methods (e.g., for deterministic async
|
|
378
|
+
computation), it must be explicitly flagged with deterministic_async=True
|
|
379
|
+
during registration.
|
|
380
|
+
|
|
381
|
+
Validation Process:
|
|
382
|
+
1. Check if execute() method exists and is async
|
|
383
|
+
2. Iterate through ALL public methods (not prefixed with _)
|
|
384
|
+
3. Check if any method is a coroutine function
|
|
385
|
+
4. If async methods found and deterministic_async=False, raise error
|
|
386
|
+
5. If async methods found and deterministic_async=True, allow registration
|
|
387
|
+
|
|
388
|
+
Args:
|
|
389
|
+
plugin_id: Unique identifier for the plugin being validated
|
|
390
|
+
plugin_class: The plugin class to validate for async methods
|
|
391
|
+
deterministic_async: If True, allows async interface; if False, enforces sync
|
|
392
|
+
|
|
393
|
+
Raises:
|
|
394
|
+
ComputeRegistryError: If plugin has async methods and deterministic_async=False.
|
|
395
|
+
Error includes the plugin_id and the name of the async
|
|
396
|
+
method that caused validation failure.
|
|
397
|
+
|
|
398
|
+
Example:
|
|
399
|
+
>>> # This will fail - async plugin without explicit flag
|
|
400
|
+
>>> class AsyncPlugin:
|
|
401
|
+
... async def execute(self, input_data, context):
|
|
402
|
+
... return {"result": True}
|
|
403
|
+
>>> registry._validate_sync_enforcement("async_plugin", AsyncPlugin, False)
|
|
404
|
+
ComputeRegistryError: Plugin 'async_plugin' has async execute() but
|
|
405
|
+
deterministic_async=True not specified.
|
|
406
|
+
|
|
407
|
+
>>> # This will succeed - async explicitly flagged
|
|
408
|
+
>>> registry._validate_sync_enforcement("async_plugin", AsyncPlugin, True)
|
|
409
|
+
"""
|
|
410
|
+
# First check execute() method specifically for clear error message
|
|
411
|
+
if hasattr(plugin_class, "execute"):
|
|
412
|
+
if asyncio.iscoroutinefunction(plugin_class.execute):
|
|
413
|
+
if not deterministic_async:
|
|
414
|
+
raise ComputeRegistryError(
|
|
415
|
+
f"Plugin {plugin_id!r} has async execute() but "
|
|
416
|
+
f"deterministic_async=True not specified. "
|
|
417
|
+
f"Compute plugins must be synchronous by default.",
|
|
418
|
+
plugin_id=plugin_id,
|
|
419
|
+
context=ModelInfraErrorContext.with_correlation(
|
|
420
|
+
operation="validate_sync_enforcement",
|
|
421
|
+
),
|
|
422
|
+
async_method="execute",
|
|
423
|
+
)
|
|
424
|
+
|
|
425
|
+
# Check ALL public methods for async (comprehensive validation)
|
|
426
|
+
for name, method in inspect.getmembers(
|
|
427
|
+
plugin_class, predicate=inspect.isfunction
|
|
428
|
+
):
|
|
429
|
+
# Skip private methods (prefixed with _)
|
|
430
|
+
if name.startswith("_"):
|
|
431
|
+
continue
|
|
432
|
+
|
|
433
|
+
# Check if method is async
|
|
434
|
+
if asyncio.iscoroutinefunction(method):
|
|
435
|
+
if not deterministic_async:
|
|
436
|
+
raise ComputeRegistryError(
|
|
437
|
+
f"Plugin {plugin_id!r} has async method {name}() but "
|
|
438
|
+
f"deterministic_async=True not specified. "
|
|
439
|
+
f"Compute plugins must be synchronous by default.",
|
|
440
|
+
plugin_id=plugin_id,
|
|
441
|
+
context=ModelInfraErrorContext.with_correlation(
|
|
442
|
+
operation="validate_sync_enforcement",
|
|
443
|
+
),
|
|
444
|
+
async_method=name,
|
|
445
|
+
)
|
|
446
|
+
|
|
447
|
+
def register(self, registration: ModelComputeRegistration) -> None:
|
|
448
|
+
"""Register a compute plugin using a registration model.
|
|
449
|
+
|
|
450
|
+
Associates a (plugin_id, version) tuple with a plugin class.
|
|
451
|
+
If the combination is already registered, the existing registration is
|
|
452
|
+
overwritten.
|
|
453
|
+
|
|
454
|
+
Args:
|
|
455
|
+
registration: ModelComputeRegistration containing all registration parameters:
|
|
456
|
+
- plugin_id: Unique identifier for the plugin
|
|
457
|
+
- plugin_class: The plugin class to register (must implement ProtocolPluginCompute)
|
|
458
|
+
- version: Semantic version string (default: "1.0.0")
|
|
459
|
+
- description: Human-readable description
|
|
460
|
+
- deterministic_async: If True, allows async interface
|
|
461
|
+
|
|
462
|
+
Raises:
|
|
463
|
+
ComputeRegistryError: If plugin has async methods and
|
|
464
|
+
deterministic_async=False, or if plugin_class
|
|
465
|
+
does not implement ProtocolPluginCompute
|
|
466
|
+
ProtocolConfigurationError: If version format is invalid
|
|
467
|
+
|
|
468
|
+
Example:
|
|
469
|
+
>>> from omnibase_infra.runtime.models import ModelComputeRegistration
|
|
470
|
+
>>> registry = RegistryCompute()
|
|
471
|
+
>>> registration = ModelComputeRegistration(
|
|
472
|
+
... plugin_id="json_normalizer",
|
|
473
|
+
... plugin_class=JsonNormalizerPlugin,
|
|
474
|
+
... version="1.0.0",
|
|
475
|
+
... )
|
|
476
|
+
>>> registry.register(registration)
|
|
477
|
+
"""
|
|
478
|
+
# Extract fields from model
|
|
479
|
+
plugin_id = registration.plugin_id
|
|
480
|
+
plugin_class = registration.plugin_class
|
|
481
|
+
version = registration.version
|
|
482
|
+
deterministic_async = registration.deterministic_async
|
|
483
|
+
|
|
484
|
+
# Runtime type validation: Ensure plugin_class implements ProtocolPluginCompute protocol
|
|
485
|
+
# Check if execute() method exists and is callable
|
|
486
|
+
execute_attr = getattr(plugin_class, "execute", None)
|
|
487
|
+
|
|
488
|
+
if execute_attr is None:
|
|
489
|
+
raise ComputeRegistryError(
|
|
490
|
+
f"Plugin class {plugin_class.__name__!r} does not implement "
|
|
491
|
+
f"ProtocolPluginCompute protocol: missing 'execute()' method",
|
|
492
|
+
plugin_id=plugin_id,
|
|
493
|
+
context=ModelInfraErrorContext.with_correlation(
|
|
494
|
+
operation="register",
|
|
495
|
+
),
|
|
496
|
+
plugin_class=plugin_class.__name__,
|
|
497
|
+
)
|
|
498
|
+
|
|
499
|
+
if not callable(execute_attr):
|
|
500
|
+
raise ComputeRegistryError(
|
|
501
|
+
f"Plugin class {plugin_class.__name__!r} does not implement "
|
|
502
|
+
f"ProtocolPluginCompute protocol: 'execute' attribute is not callable",
|
|
503
|
+
plugin_id=plugin_id,
|
|
504
|
+
context=ModelInfraErrorContext.with_correlation(
|
|
505
|
+
operation="register",
|
|
506
|
+
),
|
|
507
|
+
plugin_class=plugin_class.__name__,
|
|
508
|
+
)
|
|
509
|
+
|
|
510
|
+
# Validate sync enforcement
|
|
511
|
+
self._validate_sync_enforcement(plugin_id, plugin_class, deterministic_async)
|
|
512
|
+
|
|
513
|
+
# Validate version format (ensures semantic versioning compliance)
|
|
514
|
+
# This calls _parse_semver which will raise ProtocolConfigurationError if invalid
|
|
515
|
+
self._parse_semver(version)
|
|
516
|
+
|
|
517
|
+
# Register the plugin using ModelComputeKey
|
|
518
|
+
key = ModelComputeKey(plugin_id=plugin_id, version=version)
|
|
519
|
+
with self._lock:
|
|
520
|
+
self._registry[key] = plugin_class
|
|
521
|
+
# Update secondary index for performance optimization
|
|
522
|
+
if plugin_id not in self._plugin_id_index:
|
|
523
|
+
self._plugin_id_index[plugin_id] = []
|
|
524
|
+
if key not in self._plugin_id_index[plugin_id]:
|
|
525
|
+
self._plugin_id_index[plugin_id].append(key)
|
|
526
|
+
registry_size = len(self._registry)
|
|
527
|
+
|
|
528
|
+
# Record registry size if metrics collector is set
|
|
529
|
+
if self._metrics is not None:
|
|
530
|
+
try:
|
|
531
|
+
self._metrics.record_registry_size(registry_size)
|
|
532
|
+
except Exception:
|
|
533
|
+
# Metrics recording should never break registry operations
|
|
534
|
+
# WARNING level for development visibility (change to DEBUG for production)
|
|
535
|
+
logger.warning(
|
|
536
|
+
"Metrics error suppressed during register()",
|
|
537
|
+
exc_info=True,
|
|
538
|
+
extra={"plugin_id": plugin_id, "version": version},
|
|
539
|
+
)
|
|
540
|
+
|
|
541
|
+
def register_plugin(
|
|
542
|
+
self,
|
|
543
|
+
plugin_id: str,
|
|
544
|
+
plugin_class: type,
|
|
545
|
+
version: str = "1.0.0",
|
|
546
|
+
deterministic_async: bool = False,
|
|
547
|
+
description: str = "",
|
|
548
|
+
) -> None:
|
|
549
|
+
"""Convenience method to register a plugin with individual parameters.
|
|
550
|
+
|
|
551
|
+
Wraps parameters in ModelComputeRegistration and calls register().
|
|
552
|
+
|
|
553
|
+
Args:
|
|
554
|
+
plugin_id: Unique identifier for the plugin (e.g., 'json_normalizer')
|
|
555
|
+
plugin_class: The plugin class to register. Must implement ProtocolPluginCompute.
|
|
556
|
+
version: Semantic version string (default: "1.0.0")
|
|
557
|
+
deterministic_async: If True, allows async interface. MUST be explicitly
|
|
558
|
+
flagged for plugins with async methods.
|
|
559
|
+
description: Human-readable description of the plugin
|
|
560
|
+
|
|
561
|
+
Raises:
|
|
562
|
+
ComputeRegistryError: If plugin has async methods and
|
|
563
|
+
deterministic_async=False
|
|
564
|
+
ProtocolConfigurationError: If version format is invalid
|
|
565
|
+
|
|
566
|
+
Example:
|
|
567
|
+
>>> registry = RegistryCompute()
|
|
568
|
+
>>> registry.register_plugin(
|
|
569
|
+
... plugin_id="json_normalizer",
|
|
570
|
+
... plugin_class=JsonNormalizerPlugin,
|
|
571
|
+
... version="1.0.0",
|
|
572
|
+
... )
|
|
573
|
+
"""
|
|
574
|
+
registration = ModelComputeRegistration(
|
|
575
|
+
plugin_id=plugin_id,
|
|
576
|
+
plugin_class=plugin_class,
|
|
577
|
+
version=version,
|
|
578
|
+
description=description,
|
|
579
|
+
deterministic_async=deterministic_async,
|
|
580
|
+
)
|
|
581
|
+
self.register(registration)
|
|
582
|
+
|
|
583
|
+
def get(
|
|
584
|
+
self,
|
|
585
|
+
plugin_id: str,
|
|
586
|
+
version: str | None = None,
|
|
587
|
+
) -> type[ProtocolPluginCompute]:
|
|
588
|
+
"""Get compute plugin by ID and optional version.
|
|
589
|
+
|
|
590
|
+
Resolves the plugin class registered for the given plugin configuration.
|
|
591
|
+
If version is not specified, returns the latest version (semver sorted).
|
|
592
|
+
|
|
593
|
+
Performance Characteristics:
|
|
594
|
+
- Best case: O(1) - Direct lookup with single version
|
|
595
|
+
- Average case: O(k) where k = number of matching versions
|
|
596
|
+
- Uses secondary index for O(1) plugin_id lookup instead of O(n) scan
|
|
597
|
+
- Defers expensive error message generation until actually needed
|
|
598
|
+
|
|
599
|
+
Args:
|
|
600
|
+
plugin_id: Plugin identifier.
|
|
601
|
+
version: Optional version filter. If None, returns latest version.
|
|
602
|
+
|
|
603
|
+
Returns:
|
|
604
|
+
Plugin class registered for the configuration.
|
|
605
|
+
|
|
606
|
+
Raises:
|
|
607
|
+
ComputeRegistryError: If no matching plugin is found.
|
|
608
|
+
|
|
609
|
+
Example:
|
|
610
|
+
>>> registry = RegistryCompute()
|
|
611
|
+
>>> registry.register_plugin("normalizer", NormalizerPlugin)
|
|
612
|
+
>>> plugin_cls = registry.get("normalizer")
|
|
613
|
+
>>> plugin_cls = registry.get("normalizer", version="1.0.0")
|
|
614
|
+
"""
|
|
615
|
+
timer = _MetricsTimer()
|
|
616
|
+
try:
|
|
617
|
+
with timer:
|
|
618
|
+
with self._lock:
|
|
619
|
+
# Performance optimization: Use secondary index for O(1) lookup
|
|
620
|
+
# This avoids iterating through all registry entries (O(n) -> O(1))
|
|
621
|
+
candidate_keys = self._plugin_id_index.get(plugin_id, [])
|
|
622
|
+
|
|
623
|
+
# Early exit if plugin_id not found - avoid building matches list
|
|
624
|
+
if not candidate_keys:
|
|
625
|
+
# Record error before raising
|
|
626
|
+
if self._metrics is not None:
|
|
627
|
+
try:
|
|
628
|
+
self._metrics.record_error("not_found", plugin_id)
|
|
629
|
+
except Exception:
|
|
630
|
+
# Metrics recording should never break registry operations
|
|
631
|
+
# WARNING level for development visibility (change to DEBUG for production)
|
|
632
|
+
logger.warning(
|
|
633
|
+
"Metrics error suppressed during get() not_found",
|
|
634
|
+
exc_info=True,
|
|
635
|
+
extra={"plugin_id": plugin_id},
|
|
636
|
+
)
|
|
637
|
+
# Get unique, sorted list of registered plugin IDs for error context
|
|
638
|
+
# Uses secondary index for O(m) where m=unique plugins vs O(n) scan
|
|
639
|
+
registered: list[str] = sorted(self._plugin_id_index.keys())
|
|
640
|
+
raise ComputeRegistryError(
|
|
641
|
+
f"No compute plugin registered with id={plugin_id!r}. "
|
|
642
|
+
f"Registered plugins: {registered}",
|
|
643
|
+
plugin_id=plugin_id,
|
|
644
|
+
registered_plugins=registered,
|
|
645
|
+
context=ModelInfraErrorContext.with_correlation(
|
|
646
|
+
operation="get",
|
|
647
|
+
),
|
|
648
|
+
version=version,
|
|
649
|
+
)
|
|
650
|
+
|
|
651
|
+
# If version specified, do exact match
|
|
652
|
+
if version is not None:
|
|
653
|
+
for key in candidate_keys:
|
|
654
|
+
if key.version == version:
|
|
655
|
+
return self._registry[key]
|
|
656
|
+
# Record error before raising
|
|
657
|
+
if self._metrics is not None:
|
|
658
|
+
try:
|
|
659
|
+
self._metrics.record_error(
|
|
660
|
+
"version_not_found", plugin_id
|
|
661
|
+
)
|
|
662
|
+
except Exception:
|
|
663
|
+
# Metrics recording should never break registry operations
|
|
664
|
+
# WARNING level for development visibility (change to DEBUG for production)
|
|
665
|
+
logger.warning(
|
|
666
|
+
"Metrics error suppressed during get() version_not_found",
|
|
667
|
+
exc_info=True,
|
|
668
|
+
extra={"plugin_id": plugin_id, "version": version},
|
|
669
|
+
)
|
|
670
|
+
# Version not found - get versions from candidate_keys
|
|
671
|
+
available_versions = sorted(
|
|
672
|
+
[key.version for key in candidate_keys],
|
|
673
|
+
key=self._parse_semver,
|
|
674
|
+
)
|
|
675
|
+
raise ComputeRegistryError(
|
|
676
|
+
f"Compute plugin {plugin_id!r} version {version!r} "
|
|
677
|
+
f"not found. Available versions: {available_versions}",
|
|
678
|
+
plugin_id=plugin_id,
|
|
679
|
+
context=ModelInfraErrorContext.with_correlation(
|
|
680
|
+
operation="get",
|
|
681
|
+
),
|
|
682
|
+
version=version,
|
|
683
|
+
)
|
|
684
|
+
|
|
685
|
+
# Return latest version (no version filter)
|
|
686
|
+
# Fast path optimization: avoid sorting if only one version
|
|
687
|
+
if len(candidate_keys) == 1:
|
|
688
|
+
return self._registry[candidate_keys[0]]
|
|
689
|
+
|
|
690
|
+
# Multiple versions - find latest using semver comparison
|
|
691
|
+
latest_key = max(
|
|
692
|
+
candidate_keys,
|
|
693
|
+
key=lambda k: self._parse_semver(k.version),
|
|
694
|
+
)
|
|
695
|
+
return self._registry[latest_key]
|
|
696
|
+
finally:
|
|
697
|
+
# Record latency if metrics collector is set
|
|
698
|
+
if self._metrics is not None:
|
|
699
|
+
try:
|
|
700
|
+
self._metrics.record_get_latency(
|
|
701
|
+
plugin_id, version, timer.elapsed_ms
|
|
702
|
+
)
|
|
703
|
+
except Exception:
|
|
704
|
+
# Metrics recording should never break registry operations
|
|
705
|
+
# WARNING level for development visibility (change to DEBUG for production)
|
|
706
|
+
logger.warning(
|
|
707
|
+
"Metrics error suppressed during get() latency recording",
|
|
708
|
+
exc_info=True,
|
|
709
|
+
extra={"plugin_id": plugin_id, "version": version},
|
|
710
|
+
)
|
|
711
|
+
|
|
712
|
+
def list_keys(self) -> list[tuple[str, str]]:
|
|
713
|
+
"""List registered plugin keys as (plugin_id, version) tuples.
|
|
714
|
+
|
|
715
|
+
Returns:
|
|
716
|
+
List of (plugin_id, version) tuples, sorted by plugin_id then semver.
|
|
717
|
+
|
|
718
|
+
Example:
|
|
719
|
+
>>> registry = RegistryCompute()
|
|
720
|
+
>>> registry.register_plugin("normalizer", NormalizerV1, version="1.0.0")
|
|
721
|
+
>>> registry.register_plugin("normalizer", NormalizerV2, version="2.0.0")
|
|
722
|
+
>>> print(registry.list_keys())
|
|
723
|
+
[('normalizer', '1.0.0'), ('normalizer', '2.0.0')]
|
|
724
|
+
"""
|
|
725
|
+
with self._lock:
|
|
726
|
+
return sorted(
|
|
727
|
+
[k.to_tuple() for k in self._registry],
|
|
728
|
+
key=lambda x: (x[0], self._parse_semver(x[1])),
|
|
729
|
+
)
|
|
730
|
+
|
|
731
|
+
def list_versions(self, plugin_id: str) -> list[str]:
|
|
732
|
+
"""List registered versions for a plugin ID.
|
|
733
|
+
|
|
734
|
+
Args:
|
|
735
|
+
plugin_id: The plugin ID to list versions for.
|
|
736
|
+
|
|
737
|
+
Returns:
|
|
738
|
+
List of version strings registered for the plugin ID, sorted by semver.
|
|
739
|
+
|
|
740
|
+
Example:
|
|
741
|
+
>>> registry = RegistryCompute()
|
|
742
|
+
>>> registry.register_plugin("normalizer", NormalizerV1, version="1.0.0")
|
|
743
|
+
>>> registry.register_plugin("normalizer", NormalizerV2, version="2.0.0")
|
|
744
|
+
>>> print(registry.list_versions("normalizer"))
|
|
745
|
+
['1.0.0', '2.0.0']
|
|
746
|
+
"""
|
|
747
|
+
with self._lock:
|
|
748
|
+
# Performance optimization: Use secondary index
|
|
749
|
+
candidate_keys = self._plugin_id_index.get(plugin_id, [])
|
|
750
|
+
versions = sorted(
|
|
751
|
+
[key.version for key in candidate_keys],
|
|
752
|
+
key=self._parse_semver,
|
|
753
|
+
)
|
|
754
|
+
return versions
|
|
755
|
+
|
|
756
|
+
def is_registered(
|
|
757
|
+
self,
|
|
758
|
+
plugin_id: str,
|
|
759
|
+
version: str | None = None,
|
|
760
|
+
) -> bool:
|
|
761
|
+
"""Check if a plugin is registered.
|
|
762
|
+
|
|
763
|
+
Args:
|
|
764
|
+
plugin_id: Plugin identifier.
|
|
765
|
+
version: Optional version filter.
|
|
766
|
+
|
|
767
|
+
Returns:
|
|
768
|
+
True if a matching plugin is registered, False otherwise.
|
|
769
|
+
|
|
770
|
+
Example:
|
|
771
|
+
>>> registry = RegistryCompute()
|
|
772
|
+
>>> registry.register_plugin("normalizer", NormalizerPlugin)
|
|
773
|
+
>>> registry.is_registered("normalizer")
|
|
774
|
+
True
|
|
775
|
+
>>> registry.is_registered("unknown")
|
|
776
|
+
False
|
|
777
|
+
"""
|
|
778
|
+
with self._lock:
|
|
779
|
+
# Performance optimization: Use secondary index
|
|
780
|
+
candidate_keys = self._plugin_id_index.get(plugin_id, [])
|
|
781
|
+
if not candidate_keys:
|
|
782
|
+
return False
|
|
783
|
+
if version is None:
|
|
784
|
+
return True
|
|
785
|
+
return any(key.version == version for key in candidate_keys)
|
|
786
|
+
|
|
787
|
+
def unregister(
|
|
788
|
+
self,
|
|
789
|
+
plugin_id: str,
|
|
790
|
+
version: str | None = None,
|
|
791
|
+
) -> int:
|
|
792
|
+
"""Unregister compute plugin(s).
|
|
793
|
+
|
|
794
|
+
Removes plugin registrations matching the given criteria.
|
|
795
|
+
This is useful for testing and hot-reload scenarios.
|
|
796
|
+
|
|
797
|
+
Args:
|
|
798
|
+
plugin_id: Plugin identifier to unregister.
|
|
799
|
+
version: Optional version filter. If None, removes all versions.
|
|
800
|
+
|
|
801
|
+
Returns:
|
|
802
|
+
Number of plugins unregistered.
|
|
803
|
+
|
|
804
|
+
Example:
|
|
805
|
+
>>> registry = RegistryCompute()
|
|
806
|
+
>>> registry.register_plugin("normalizer", NormalizerV1, version="1.0.0")
|
|
807
|
+
>>> registry.register_plugin("normalizer", NormalizerV2, version="2.0.0")
|
|
808
|
+
>>> registry.unregister("normalizer") # Removes all versions
|
|
809
|
+
2
|
|
810
|
+
>>> registry.unregister("normalizer", version="1.0.0") # Remove specific version
|
|
811
|
+
1
|
|
812
|
+
"""
|
|
813
|
+
# Thread safety: Lock held during full unregister operation (write operation)
|
|
814
|
+
with self._lock:
|
|
815
|
+
# Performance optimization: Use secondary index
|
|
816
|
+
candidate_keys = self._plugin_id_index.get(plugin_id, [])
|
|
817
|
+
keys_to_remove: list[ModelComputeKey] = []
|
|
818
|
+
|
|
819
|
+
for key in candidate_keys:
|
|
820
|
+
if version is None or key.version == version:
|
|
821
|
+
keys_to_remove.append(key)
|
|
822
|
+
|
|
823
|
+
for key in keys_to_remove:
|
|
824
|
+
del self._registry[key]
|
|
825
|
+
# Update secondary index
|
|
826
|
+
self._plugin_id_index[plugin_id].remove(key)
|
|
827
|
+
|
|
828
|
+
# Clean up empty index entries
|
|
829
|
+
if (
|
|
830
|
+
plugin_id in self._plugin_id_index
|
|
831
|
+
and not self._plugin_id_index[plugin_id]
|
|
832
|
+
):
|
|
833
|
+
del self._plugin_id_index[plugin_id]
|
|
834
|
+
|
|
835
|
+
registry_size = len(self._registry)
|
|
836
|
+
removed_count = len(keys_to_remove)
|
|
837
|
+
|
|
838
|
+
# Record registry size if metrics collector is set and we removed something
|
|
839
|
+
if removed_count > 0 and self._metrics is not None:
|
|
840
|
+
try:
|
|
841
|
+
self._metrics.record_registry_size(registry_size)
|
|
842
|
+
except Exception:
|
|
843
|
+
# Metrics recording should never break registry operations
|
|
844
|
+
# WARNING level for development visibility (change to DEBUG for production)
|
|
845
|
+
logger.warning(
|
|
846
|
+
"Metrics error suppressed during unregister()",
|
|
847
|
+
exc_info=True,
|
|
848
|
+
extra={"plugin_id": plugin_id, "version": version},
|
|
849
|
+
)
|
|
850
|
+
|
|
851
|
+
return removed_count
|
|
852
|
+
|
|
853
|
+
def clear(self) -> None:
|
|
854
|
+
"""Clear all plugin registrations.
|
|
855
|
+
|
|
856
|
+
Removes all registered plugins from the registry.
|
|
857
|
+
|
|
858
|
+
Warning:
|
|
859
|
+
This method is intended for **testing purposes only**.
|
|
860
|
+
Calling it in production code will emit a warning.
|
|
861
|
+
It breaks the immutability guarantee after startup.
|
|
862
|
+
|
|
863
|
+
Example:
|
|
864
|
+
>>> registry = RegistryCompute()
|
|
865
|
+
>>> registry.register_plugin("normalizer", NormalizerPlugin)
|
|
866
|
+
>>> registry.clear()
|
|
867
|
+
>>> registry.list_keys()
|
|
868
|
+
[]
|
|
869
|
+
"""
|
|
870
|
+
warnings.warn(
|
|
871
|
+
"RegistryCompute.clear() is intended for testing only. "
|
|
872
|
+
"Do not use in production code.",
|
|
873
|
+
UserWarning,
|
|
874
|
+
stacklevel=2,
|
|
875
|
+
)
|
|
876
|
+
with self._lock:
|
|
877
|
+
self._registry.clear()
|
|
878
|
+
self._plugin_id_index.clear()
|
|
879
|
+
|
|
880
|
+
def __len__(self) -> int:
|
|
881
|
+
"""Return the number of registered plugins.
|
|
882
|
+
|
|
883
|
+
Returns:
|
|
884
|
+
Number of registered plugin (plugin_id, version) combinations.
|
|
885
|
+
|
|
886
|
+
Example:
|
|
887
|
+
>>> registry = RegistryCompute()
|
|
888
|
+
>>> len(registry)
|
|
889
|
+
0
|
|
890
|
+
>>> registry.register_plugin("normalizer", NormalizerPlugin)
|
|
891
|
+
>>> len(registry)
|
|
892
|
+
1
|
|
893
|
+
"""
|
|
894
|
+
with self._lock:
|
|
895
|
+
return len(self._registry)
|
|
896
|
+
|
|
897
|
+
def __contains__(self, key: ModelComputeKey | str) -> bool:
|
|
898
|
+
"""Check if plugin is registered using 'in' operator.
|
|
899
|
+
|
|
900
|
+
Args:
|
|
901
|
+
key: Either a ModelComputeKey instance or a plugin_id string.
|
|
902
|
+
|
|
903
|
+
Returns:
|
|
904
|
+
True if plugin is registered, False otherwise.
|
|
905
|
+
|
|
906
|
+
Example:
|
|
907
|
+
>>> registry = RegistryCompute()
|
|
908
|
+
>>> registry.register_plugin("normalizer", NormalizerPlugin)
|
|
909
|
+
>>> "normalizer" in registry
|
|
910
|
+
True
|
|
911
|
+
>>> ModelComputeKey(plugin_id="normalizer", version="1.0.0") in registry
|
|
912
|
+
True
|
|
913
|
+
>>> "unknown" in registry
|
|
914
|
+
False
|
|
915
|
+
"""
|
|
916
|
+
if isinstance(key, str):
|
|
917
|
+
return self.is_registered(key)
|
|
918
|
+
return self.is_registered(key.plugin_id, key.version)
|
|
919
|
+
|
|
920
|
+
# ==========================================================================
|
|
921
|
+
# Semver Cache Configuration Methods
|
|
922
|
+
# ==========================================================================
|
|
923
|
+
|
|
924
|
+
@classmethod
|
|
925
|
+
def _get_semver_parser(cls) -> Callable[[str], tuple[int, int, int, str]]:
|
|
926
|
+
"""Get or create the semver parser with configured cache size.
|
|
927
|
+
|
|
928
|
+
This method implements lazy initialization of the LRU-cached semver parser.
|
|
929
|
+
The cache size is determined by SEMVER_CACHE_SIZE at initialization time.
|
|
930
|
+
|
|
931
|
+
Thread Safety:
|
|
932
|
+
Uses double-checked locking pattern for thread-safe lazy initialization.
|
|
933
|
+
The fast path stores the cache reference in a local variable to prevent
|
|
934
|
+
TOCTOU (time-of-check-time-of-use) race conditions where another thread
|
|
935
|
+
could call _reset_semver_cache() between the None check and the return.
|
|
936
|
+
|
|
937
|
+
Returns:
|
|
938
|
+
Cached semver parsing function.
|
|
939
|
+
|
|
940
|
+
Performance:
|
|
941
|
+
- First call: Creates LRU-cached function (one-time cost)
|
|
942
|
+
- Subsequent calls: Returns cached function reference (O(1))
|
|
943
|
+
"""
|
|
944
|
+
# Fast path: cache already initialized
|
|
945
|
+
# CRITICAL: Store in local variable to prevent TOCTOU race condition.
|
|
946
|
+
# Without this, another thread could call _reset_semver_cache() between
|
|
947
|
+
# the None check and the return, causing this method to return None.
|
|
948
|
+
cache = cls._semver_cache
|
|
949
|
+
if cache is not None:
|
|
950
|
+
return cache
|
|
951
|
+
|
|
952
|
+
# Slow path: initialize with lock
|
|
953
|
+
with cls._semver_cache_lock:
|
|
954
|
+
# Double-check after acquiring lock
|
|
955
|
+
if cls._semver_cache is not None:
|
|
956
|
+
return cls._semver_cache
|
|
957
|
+
|
|
958
|
+
# Create LRU-cached parser with configured size
|
|
959
|
+
@functools.lru_cache(maxsize=cls.SEMVER_CACHE_SIZE)
|
|
960
|
+
def _parse_semver_impl(version: str) -> tuple[int, int, int, str]:
|
|
961
|
+
"""Parse semantic version string into comparable tuple.
|
|
962
|
+
|
|
963
|
+
Implementation moved here to support configurable cache size.
|
|
964
|
+
See _parse_semver docstring for full documentation.
|
|
965
|
+
"""
|
|
966
|
+
# Validate non-empty version string
|
|
967
|
+
if not version or not version.strip():
|
|
968
|
+
raise ProtocolConfigurationError(
|
|
969
|
+
"Invalid semantic version format: empty version string",
|
|
970
|
+
context=ModelInfraErrorContext.with_correlation(
|
|
971
|
+
operation="parse_semver",
|
|
972
|
+
),
|
|
973
|
+
version=version,
|
|
974
|
+
)
|
|
975
|
+
|
|
976
|
+
# Trim whitespace BEFORE any split operations
|
|
977
|
+
version = version.strip()
|
|
978
|
+
|
|
979
|
+
# Split off prerelease suffix (e.g., "1.0.0-alpha" -> "1.0.0", "alpha")
|
|
980
|
+
if "-" in version:
|
|
981
|
+
version_part, prerelease = version.split("-", 1)
|
|
982
|
+
# Validate prerelease is non-empty when dash is present
|
|
983
|
+
if not prerelease:
|
|
984
|
+
raise ProtocolConfigurationError(
|
|
985
|
+
f"Invalid semantic version format: '{version}'. "
|
|
986
|
+
f"Prerelease suffix cannot be empty when '-' is specified.",
|
|
987
|
+
context=ModelInfraErrorContext.with_correlation(
|
|
988
|
+
operation="parse_semver",
|
|
989
|
+
),
|
|
990
|
+
version=version,
|
|
991
|
+
)
|
|
992
|
+
else:
|
|
993
|
+
version_part, prerelease = version, ""
|
|
994
|
+
|
|
995
|
+
# Parse major.minor.patch
|
|
996
|
+
parts = version_part.split(".")
|
|
997
|
+
|
|
998
|
+
# Validate version format (max 3 parts, no empty parts)
|
|
999
|
+
# Note: len(parts) >= 1 is guaranteed since split(".") always returns
|
|
1000
|
+
# at least one element, so we only need to check the upper bound
|
|
1001
|
+
if len(parts) > 3 or any(not p.strip() for p in parts):
|
|
1002
|
+
raise ProtocolConfigurationError(
|
|
1003
|
+
f"Invalid semantic version format: '{version}'",
|
|
1004
|
+
context=ModelInfraErrorContext.with_correlation(
|
|
1005
|
+
operation="parse_semver",
|
|
1006
|
+
),
|
|
1007
|
+
version=version,
|
|
1008
|
+
)
|
|
1009
|
+
|
|
1010
|
+
try:
|
|
1011
|
+
major = int(parts[0])
|
|
1012
|
+
minor = int(parts[1]) if len(parts) > 1 else 0
|
|
1013
|
+
patch = int(parts[2]) if len(parts) > 2 else 0
|
|
1014
|
+
except (ValueError, IndexError) as e:
|
|
1015
|
+
raise ProtocolConfigurationError(
|
|
1016
|
+
f"Invalid semantic version format: '{version}'",
|
|
1017
|
+
context=ModelInfraErrorContext.with_correlation(
|
|
1018
|
+
operation="parse_semver",
|
|
1019
|
+
),
|
|
1020
|
+
version=version,
|
|
1021
|
+
) from e
|
|
1022
|
+
|
|
1023
|
+
# Validate non-negative integers
|
|
1024
|
+
if major < 0 or minor < 0 or patch < 0:
|
|
1025
|
+
raise ProtocolConfigurationError(
|
|
1026
|
+
f"Invalid semantic version: negative component in '{version}'",
|
|
1027
|
+
context=ModelInfraErrorContext.with_correlation(
|
|
1028
|
+
operation="parse_semver",
|
|
1029
|
+
),
|
|
1030
|
+
version=version,
|
|
1031
|
+
)
|
|
1032
|
+
|
|
1033
|
+
# Empty prerelease uses sentinel (chr(127)) to sort AFTER any prerelease string
|
|
1034
|
+
# This ensures "1.0.0" > "1.0.0-alpha" in version comparisons
|
|
1035
|
+
sort_prerelease = prerelease if prerelease else _SEMVER_SORT_SENTINEL
|
|
1036
|
+
|
|
1037
|
+
return (major, minor, patch, sort_prerelease)
|
|
1038
|
+
|
|
1039
|
+
cls._semver_cache = _parse_semver_impl
|
|
1040
|
+
return cls._semver_cache
|
|
1041
|
+
|
|
1042
|
+
@classmethod
|
|
1043
|
+
def _parse_semver(cls, version: str) -> tuple[int, int, int, str]:
|
|
1044
|
+
"""Parse semantic version string into comparable tuple with INTEGER components.
|
|
1045
|
+
|
|
1046
|
+
This method implements SEMANTIC VERSION SORTING, not lexicographic sorting.
|
|
1047
|
+
This is critical for correct "latest version" selection.
|
|
1048
|
+
|
|
1049
|
+
Why This Matters:
|
|
1050
|
+
Lexicographic sorting (string comparison):
|
|
1051
|
+
"1.10.0" < "1.9.0" WRONG (because '1' < '9' in strings)
|
|
1052
|
+
"10.0.0" < "2.0.0" WRONG (because '1' < '2' in strings)
|
|
1053
|
+
|
|
1054
|
+
Semantic version sorting (integer comparison):
|
|
1055
|
+
1.10.0 > 1.9.0 CORRECT (because 10 > 9 as integers)
|
|
1056
|
+
10.0.0 > 2.0.0 CORRECT (because 10 > 2 as integers)
|
|
1057
|
+
|
|
1058
|
+
Implementation:
|
|
1059
|
+
- Parses version components as INTEGERS (not strings)
|
|
1060
|
+
- Returns tuple (major: int, minor: int, patch: int, prerelease: str)
|
|
1061
|
+
- Python's tuple comparison then works correctly: (1, 10, 0) > (1, 9, 0)
|
|
1062
|
+
- Prerelease versions sort before release: "1.0.0-alpha" < "1.0.0"
|
|
1063
|
+
|
|
1064
|
+
Supported Formats:
|
|
1065
|
+
- Full: "1.2.3", "1.2.3-beta"
|
|
1066
|
+
- Partial: "1" -> (1, 0, 0), "1.2" -> (1, 2, 0)
|
|
1067
|
+
- Prerelease: "1.0.0-alpha", "2.1.0-rc.1"
|
|
1068
|
+
|
|
1069
|
+
Performance:
|
|
1070
|
+
This method uses an LRU cache with configurable size (default: 128)
|
|
1071
|
+
to avoid re-parsing the same version strings repeatedly.
|
|
1072
|
+
|
|
1073
|
+
Args:
|
|
1074
|
+
version: Semantic version string (e.g., "1.2.3" or "1.0.0-beta")
|
|
1075
|
+
|
|
1076
|
+
Returns:
|
|
1077
|
+
Tuple of (major, minor, patch, prerelease) for comparison.
|
|
1078
|
+
Components are INTEGERS (not strings) for correct semantic sorting.
|
|
1079
|
+
|
|
1080
|
+
Raises:
|
|
1081
|
+
ProtocolConfigurationError: If version format is invalid
|
|
1082
|
+
"""
|
|
1083
|
+
parser = cls._get_semver_parser()
|
|
1084
|
+
return parser(version)
|
|
1085
|
+
|
|
1086
|
+
@classmethod
|
|
1087
|
+
def _reset_semver_cache(cls) -> None:
|
|
1088
|
+
"""Reset semver cache. For testing only.
|
|
1089
|
+
|
|
1090
|
+
Clears the cached semver parser, allowing reconfiguration of cache size.
|
|
1091
|
+
This should only be used in test fixtures to ensure test isolation.
|
|
1092
|
+
|
|
1093
|
+
Thread Safety:
|
|
1094
|
+
This method is thread-safe and uses the class-level lock. The reset
|
|
1095
|
+
operation is atomic - either the cache is fully reset or not at all.
|
|
1096
|
+
|
|
1097
|
+
In-flight Operations:
|
|
1098
|
+
If other threads have already obtained a reference to the cache
|
|
1099
|
+
via _get_semver_parser(), they will continue using the old cache
|
|
1100
|
+
until they complete. This is safe because the old cache remains
|
|
1101
|
+
a valid callable until garbage collected. New operations after
|
|
1102
|
+
reset will get the new cache instance when created.
|
|
1103
|
+
|
|
1104
|
+
Memory Reclamation:
|
|
1105
|
+
The old cache's internal LRU entries are explicitly cleared via
|
|
1106
|
+
cache_clear() before the reference is released. This ensures
|
|
1107
|
+
prompt memory reclamation rather than waiting for garbage
|
|
1108
|
+
collection.
|
|
1109
|
+
|
|
1110
|
+
Concurrent Reset:
|
|
1111
|
+
Multiple concurrent reset calls are safe. Each reset will clear
|
|
1112
|
+
the current cache (if any) and set the reference to None. The
|
|
1113
|
+
lock ensures only one reset executes at a time.
|
|
1114
|
+
|
|
1115
|
+
Example:
|
|
1116
|
+
>>> # In test fixture
|
|
1117
|
+
>>> RegistryCompute._reset_semver_cache()
|
|
1118
|
+
>>> RegistryCompute.SEMVER_CACHE_SIZE = 64
|
|
1119
|
+
>>> # Now cache will be initialized with size 64 on next use
|
|
1120
|
+
"""
|
|
1121
|
+
with cls._semver_cache_lock:
|
|
1122
|
+
old_cache = cls._semver_cache
|
|
1123
|
+
if old_cache is not None:
|
|
1124
|
+
# Clear internal LRU cache entries before releasing reference.
|
|
1125
|
+
# This ensures prompt memory reclamation rather than waiting
|
|
1126
|
+
# for garbage collection of the orphaned function object.
|
|
1127
|
+
# NOTE: cache_clear() is added by @lru_cache decorator but not
|
|
1128
|
+
# reflected in Callable type annotation. This is a known mypy
|
|
1129
|
+
# limitation with lru_cache wrappers.
|
|
1130
|
+
old_cache.cache_clear() # type: ignore[attr-defined] # NOTE: lru_cache dynamic method
|
|
1131
|
+
cls._semver_cache = None
|
|
1132
|
+
|
|
1133
|
+
|
|
1134
|
+
# =============================================================================
|
|
1135
|
+
# Module Exports
|
|
1136
|
+
# =============================================================================
|
|
1137
|
+
|
|
1138
|
+
__all__: list[str] = [
|
|
1139
|
+
"ENV_COMPUTE_REGISTRY_CACHE_SIZE", # Environment variable constant
|
|
1140
|
+
"ModelComputeKey", # Re-export for convenience
|
|
1141
|
+
"ModelComputeRegistration", # Re-export for convenience
|
|
1142
|
+
"RegistryCompute", # Registry class
|
|
1143
|
+
]
|