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,784 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Pure function reducer for contract registry projection.
|
|
4
|
+
|
|
5
|
+
This reducer implements the pure function pattern for contract registry workflows:
|
|
6
|
+
reduce(state, event, metadata) -> ModelReducerOutput[state + intents]
|
|
7
|
+
|
|
8
|
+
The reducer handles four event types:
|
|
9
|
+
1. contract-registered: Upsert contract record, extract topics
|
|
10
|
+
2. contract-deregistered: Mark contract as inactive
|
|
11
|
+
3. node-heartbeat: Update last_seen_at timestamp
|
|
12
|
+
4. runtime-tick: Compute staleness, mark stale contracts inactive
|
|
13
|
+
|
|
14
|
+
Architecture:
|
|
15
|
+
- Pure function: reduce(state, event) -> new_state + intents
|
|
16
|
+
- No internal state - state passed in and returned
|
|
17
|
+
- No I/O - emits intents for Effect layer (PostgreSQL writes)
|
|
18
|
+
- Deterministic - same inputs produce same outputs
|
|
19
|
+
|
|
20
|
+
Circuit Breaker Considerations:
|
|
21
|
+
This reducer does NOT require a circuit breaker because:
|
|
22
|
+
|
|
23
|
+
1. **Pure Function Pattern**: Reducers are pure functions - they perform
|
|
24
|
+
NO I/O operations. All external interactions are delegated to the
|
|
25
|
+
Effect layer via emitted intents.
|
|
26
|
+
|
|
27
|
+
2. **No Transient Failures**: Without I/O, there are no transient failures
|
|
28
|
+
to recover from. Circuit breakers are designed for I/O resilience.
|
|
29
|
+
|
|
30
|
+
3. **Deterministic Behavior**: Given the same state and event, the reducer
|
|
31
|
+
always produces the same output. There's no "retry" semantic.
|
|
32
|
+
|
|
33
|
+
4. **Effect Layer Responsibility**: Circuit breakers should be implemented
|
|
34
|
+
in the Effect layer nodes (PostgresAdapter) that actually perform the
|
|
35
|
+
external I/O operations.
|
|
36
|
+
|
|
37
|
+
Staleness Strategy:
|
|
38
|
+
Staleness is computed on runtime-tick events (not on every heartbeat).
|
|
39
|
+
This design:
|
|
40
|
+
- Reduces PostgreSQL write amplification (batch staleness updates)
|
|
41
|
+
- Centralizes TTL logic in one place (the tick handler)
|
|
42
|
+
- Makes heartbeat handling cheap (just update last_seen_at)
|
|
43
|
+
|
|
44
|
+
Heartbeats opportunistically update last_seen_at. The staleness check
|
|
45
|
+
on runtime-tick marks contracts as stale if last_seen_at > threshold.
|
|
46
|
+
|
|
47
|
+
Intent Emission:
|
|
48
|
+
The reducer emits ModelIntent objects for Effect layer execution:
|
|
49
|
+
- postgres.upsert_contract: Upsert contract record
|
|
50
|
+
- postgres.update_topic: Update topic routing entry
|
|
51
|
+
- postgres.mark_stale: Mark contracts as stale (batch operation)
|
|
52
|
+
- postgres.update_heartbeat: Update last_seen_at timestamp
|
|
53
|
+
- postgres.deactivate_contract: Mark contract as inactive
|
|
54
|
+
|
|
55
|
+
The payload contains the serialized typed intent for Effect layer execution.
|
|
56
|
+
|
|
57
|
+
Related:
|
|
58
|
+
- OMN-1653: Contract registry reducer implementation
|
|
59
|
+
- RegistrationReducer: Reference implementation for pure reducer pattern
|
|
60
|
+
- DESIGN_CONTRACT_REGISTRY.md: Architecture design
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
from __future__ import annotations
|
|
64
|
+
|
|
65
|
+
import logging
|
|
66
|
+
import os
|
|
67
|
+
import time
|
|
68
|
+
from datetime import UTC, datetime, timedelta
|
|
69
|
+
from typing import assert_never
|
|
70
|
+
from uuid import UUID, uuid4
|
|
71
|
+
|
|
72
|
+
import yaml
|
|
73
|
+
|
|
74
|
+
from omnibase_core.enums import EnumReductionType, EnumStreamingMode
|
|
75
|
+
|
|
76
|
+
# =============================================================================
|
|
77
|
+
# Event Models from omnibase_core 0.9.8
|
|
78
|
+
# =============================================================================
|
|
79
|
+
from omnibase_core.models.events import (
|
|
80
|
+
ModelContractDeregisteredEvent,
|
|
81
|
+
ModelContractRegisteredEvent,
|
|
82
|
+
ModelNodeHeartbeatEvent,
|
|
83
|
+
)
|
|
84
|
+
from omnibase_core.models.primitives.model_semver import ModelSemVer
|
|
85
|
+
from omnibase_core.models.reducer.model_intent import ModelIntent
|
|
86
|
+
from omnibase_core.nodes import ModelReducerOutput
|
|
87
|
+
from omnibase_core.types import JsonType
|
|
88
|
+
from omnibase_infra.nodes.contract_registry_reducer.models.model_contract_registry_state import (
|
|
89
|
+
ModelContractRegistryState,
|
|
90
|
+
)
|
|
91
|
+
from omnibase_infra.nodes.contract_registry_reducer.models.model_payload_cleanup_topic_references import (
|
|
92
|
+
ModelPayloadCleanupTopicReferences,
|
|
93
|
+
)
|
|
94
|
+
from omnibase_infra.nodes.contract_registry_reducer.models.model_payload_deactivate_contract import (
|
|
95
|
+
ModelPayloadDeactivateContract,
|
|
96
|
+
)
|
|
97
|
+
from omnibase_infra.nodes.contract_registry_reducer.models.model_payload_mark_stale import (
|
|
98
|
+
ModelPayloadMarkStale,
|
|
99
|
+
)
|
|
100
|
+
from omnibase_infra.nodes.contract_registry_reducer.models.model_payload_update_heartbeat import (
|
|
101
|
+
ModelPayloadUpdateHeartbeat,
|
|
102
|
+
)
|
|
103
|
+
from omnibase_infra.nodes.contract_registry_reducer.models.model_payload_update_topic import (
|
|
104
|
+
ModelPayloadUpdateTopic,
|
|
105
|
+
)
|
|
106
|
+
from omnibase_infra.nodes.contract_registry_reducer.models.model_payload_upsert_contract import (
|
|
107
|
+
ModelPayloadUpsertContract,
|
|
108
|
+
)
|
|
109
|
+
from omnibase_infra.runtime.models.model_runtime_tick import ModelRuntimeTick
|
|
110
|
+
|
|
111
|
+
# Union type for all events this reducer handles
|
|
112
|
+
ContractRegistryEvent = (
|
|
113
|
+
ModelContractRegisteredEvent
|
|
114
|
+
| ModelContractDeregisteredEvent
|
|
115
|
+
| ModelNodeHeartbeatEvent
|
|
116
|
+
| ModelRuntimeTick
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
# =============================================================================
|
|
120
|
+
# Performance Threshold Constants (in milliseconds)
|
|
121
|
+
# =============================================================================
|
|
122
|
+
|
|
123
|
+
# Target processing time for reduce() method (<300ms per event)
|
|
124
|
+
# ONEX_EXCLUDE: io_audit - Module-level config loaded at import, reduce() remains pure
|
|
125
|
+
PERF_THRESHOLD_REDUCE_MS: float = float(
|
|
126
|
+
os.getenv("ONEX_PERF_THRESHOLD_CONTRACT_REDUCE_MS", "300.0")
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
# Target processing time for intent building (<50ms per intent)
|
|
130
|
+
# ONEX_EXCLUDE: io_audit - Module-level config loaded at import, reduce() remains pure
|
|
131
|
+
PERF_THRESHOLD_INTENT_BUILD_MS: float = float(
|
|
132
|
+
os.getenv("ONEX_PERF_THRESHOLD_CONTRACT_INTENT_BUILD_MS", "50.0")
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
# Target processing time for staleness computation (<100ms)
|
|
136
|
+
# ONEX_EXCLUDE: io_audit - Module-level config loaded at import, reduce() remains pure
|
|
137
|
+
PERF_THRESHOLD_STALENESS_CHECK_MS: float = float(
|
|
138
|
+
os.getenv("ONEX_PERF_THRESHOLD_STALENESS_CHECK_MS", "100.0")
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
# Staleness threshold (contracts without heartbeat for this duration are stale)
|
|
142
|
+
# ONEX_EXCLUDE: io_audit - Module-level config loaded at import, reduce() remains pure
|
|
143
|
+
STALENESS_THRESHOLD_SECONDS: int = int(
|
|
144
|
+
os.getenv("ONEX_CONTRACT_STALENESS_THRESHOLD_SECONDS", "300")
|
|
145
|
+
)
|
|
146
|
+
STALENESS_THRESHOLD: timedelta = timedelta(seconds=STALENESS_THRESHOLD_SECONDS)
|
|
147
|
+
|
|
148
|
+
# Logger for performance warnings
|
|
149
|
+
_logger = logging.getLogger(__name__)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class ContractRegistryReducer:
|
|
153
|
+
"""Pure reducer for contract registry projection.
|
|
154
|
+
|
|
155
|
+
Follows ProtocolReducer pattern:
|
|
156
|
+
- reduce(state, event, metadata) -> ModelReducerOutput
|
|
157
|
+
- Pure function, no side effects
|
|
158
|
+
- Emits intents for PostgreSQL operations
|
|
159
|
+
|
|
160
|
+
This is a stateless class - all state is passed in and returned via
|
|
161
|
+
ModelContractRegistryState. The class exists to group related pure functions.
|
|
162
|
+
|
|
163
|
+
Event Handling:
|
|
164
|
+
This reducer handles four event types:
|
|
165
|
+
|
|
166
|
+
1. reduce_contract_registered(): Processes contract registration events.
|
|
167
|
+
- Upserts contract record to PostgreSQL
|
|
168
|
+
- Extracts topics from contract_yaml and updates topic routing
|
|
169
|
+
|
|
170
|
+
2. reduce_contract_deregistered(): Processes deregistration events.
|
|
171
|
+
- Marks contract as inactive in PostgreSQL
|
|
172
|
+
- Preserves contract data for auditing
|
|
173
|
+
|
|
174
|
+
3. reduce_heartbeat(): Processes heartbeat events.
|
|
175
|
+
- Updates last_seen_at timestamp
|
|
176
|
+
- Does NOT compute staleness (deferred to runtime-tick)
|
|
177
|
+
|
|
178
|
+
4. reduce_runtime_tick(): Processes periodic tick events.
|
|
179
|
+
- Computes staleness across all contracts
|
|
180
|
+
- Marks contracts as stale if last_seen_at > threshold
|
|
181
|
+
|
|
182
|
+
Example:
|
|
183
|
+
>>> from uuid import uuid4
|
|
184
|
+
>>> reducer = ContractRegistryReducer()
|
|
185
|
+
>>> state = ModelContractRegistryState() # Initial state
|
|
186
|
+
>>> # Simulate contract registration (event model stubbed)
|
|
187
|
+
>>> # output = reducer.reduce(state, event, metadata)
|
|
188
|
+
>>> # print(output.result.contracts_processed) # 1
|
|
189
|
+
"""
|
|
190
|
+
|
|
191
|
+
def reduce(
|
|
192
|
+
self,
|
|
193
|
+
state: ModelContractRegistryState,
|
|
194
|
+
event: ContractRegistryEvent,
|
|
195
|
+
event_metadata: dict[str, JsonType],
|
|
196
|
+
) -> ModelReducerOutput[ModelContractRegistryState]:
|
|
197
|
+
"""Pure reduce function: state + event -> new_state + intents.
|
|
198
|
+
|
|
199
|
+
Routes to the appropriate handler based on event type. All handlers
|
|
200
|
+
follow the same pure function pattern - no I/O, emit intents.
|
|
201
|
+
|
|
202
|
+
Args:
|
|
203
|
+
state: Current contract registry state (immutable).
|
|
204
|
+
event: Contract event to process (registration, deregistration,
|
|
205
|
+
heartbeat, or runtime-tick).
|
|
206
|
+
event_metadata: Kafka metadata containing topic, partition, offset.
|
|
207
|
+
|
|
208
|
+
Returns:
|
|
209
|
+
ModelReducerOutput containing new_state and intents tuple.
|
|
210
|
+
"""
|
|
211
|
+
# Extract Kafka metadata for idempotency
|
|
212
|
+
topic = str(event_metadata.get("topic", ""))
|
|
213
|
+
partition_raw = event_metadata.get("partition")
|
|
214
|
+
offset_raw = event_metadata.get("offset")
|
|
215
|
+
partition = int(partition_raw) if isinstance(partition_raw, (int, str)) else 0
|
|
216
|
+
offset = int(offset_raw) if isinstance(offset_raw, (int, str)) else 0
|
|
217
|
+
|
|
218
|
+
# Warn if metadata is incomplete (could cause idempotency issues)
|
|
219
|
+
if not topic or partition_raw is None or offset_raw is None:
|
|
220
|
+
_logger.warning(
|
|
221
|
+
"Event metadata incomplete - idempotency may be compromised",
|
|
222
|
+
extra={
|
|
223
|
+
"topic": topic,
|
|
224
|
+
"partition": partition,
|
|
225
|
+
"offset": offset,
|
|
226
|
+
"event_type": type(event).__name__,
|
|
227
|
+
},
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
# Idempotency guard - skip if we've already processed this event
|
|
231
|
+
if state.is_duplicate_event(topic, partition, offset):
|
|
232
|
+
return self._build_output(
|
|
233
|
+
state=state,
|
|
234
|
+
intents=(),
|
|
235
|
+
processing_time_ms=0.0,
|
|
236
|
+
items_processed=0,
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
# NOTE: isinstance dispatch is intentional here for omnibase_core event models.
|
|
240
|
+
# These are external typed models from omnibase_core where we cannot add protocol
|
|
241
|
+
# discriminators without modifying the external package. For internal events,
|
|
242
|
+
# prefer protocol-based dispatch. This pattern is acceptable for typed event
|
|
243
|
+
# model routing where the union type is exhaustive and statically checked.
|
|
244
|
+
# See: CLAUDE.md (Protocol Resolution - external type exceptions)
|
|
245
|
+
if isinstance(event, ModelContractRegisteredEvent):
|
|
246
|
+
return self._on_contract_registered(state, event, topic, partition, offset)
|
|
247
|
+
elif isinstance(event, ModelContractDeregisteredEvent):
|
|
248
|
+
return self._on_contract_deregistered(
|
|
249
|
+
state, event, topic, partition, offset
|
|
250
|
+
)
|
|
251
|
+
elif isinstance(event, ModelNodeHeartbeatEvent):
|
|
252
|
+
return self._on_heartbeat(state, event, topic, partition, offset)
|
|
253
|
+
elif isinstance(event, ModelRuntimeTick):
|
|
254
|
+
return self._on_runtime_tick(state, event, topic, partition, offset)
|
|
255
|
+
else:
|
|
256
|
+
# Exhaustiveness check - type checker will catch missing cases
|
|
257
|
+
assert_never(event)
|
|
258
|
+
|
|
259
|
+
def _on_contract_registered(
|
|
260
|
+
self,
|
|
261
|
+
state: ModelContractRegistryState,
|
|
262
|
+
event: ModelContractRegisteredEvent,
|
|
263
|
+
topic: str,
|
|
264
|
+
partition: int,
|
|
265
|
+
offset: int,
|
|
266
|
+
) -> ModelReducerOutput[ModelContractRegistryState]:
|
|
267
|
+
"""Handle contract registration - upsert contract and extract topics.
|
|
268
|
+
|
|
269
|
+
This handler:
|
|
270
|
+
1. Validates the event has required fields (contract_id, node_id)
|
|
271
|
+
2. Builds a postgres.upsert_contract intent
|
|
272
|
+
3. Extracts topics from contract_yaml and builds postgres.update_topic intents
|
|
273
|
+
4. Returns new state with event marked as processed
|
|
274
|
+
|
|
275
|
+
Args:
|
|
276
|
+
state: Current state.
|
|
277
|
+
event: Contract registered event.
|
|
278
|
+
topic: Kafka topic.
|
|
279
|
+
partition: Kafka partition.
|
|
280
|
+
offset: Kafka offset.
|
|
281
|
+
|
|
282
|
+
Returns:
|
|
283
|
+
ModelReducerOutput with new state and PostgreSQL intents.
|
|
284
|
+
"""
|
|
285
|
+
start_time = time.perf_counter()
|
|
286
|
+
|
|
287
|
+
# Extract fields from typed event
|
|
288
|
+
event_id = event.event_id
|
|
289
|
+
correlation_id = self._resolve_correlation_id(event_id, event.correlation_id)
|
|
290
|
+
|
|
291
|
+
# Derive contract identity from node_name + version (natural key)
|
|
292
|
+
contract_id = self._derive_contract_id(event.node_name, event.node_version)
|
|
293
|
+
|
|
294
|
+
intents: list[ModelIntent] = []
|
|
295
|
+
|
|
296
|
+
# Intent 1: Upsert contract record
|
|
297
|
+
upsert_intent = self._build_upsert_contract_intent(event, correlation_id)
|
|
298
|
+
intents.append(upsert_intent)
|
|
299
|
+
|
|
300
|
+
# Intent 2+: Extract and update topics from contract_yaml
|
|
301
|
+
topic_intents = self._build_topic_update_intents(event, correlation_id)
|
|
302
|
+
intents.extend(topic_intents)
|
|
303
|
+
|
|
304
|
+
# Update state
|
|
305
|
+
new_state = state.with_event_processed(
|
|
306
|
+
event_id=event_id,
|
|
307
|
+
topic=topic,
|
|
308
|
+
partition=partition,
|
|
309
|
+
offset=offset,
|
|
310
|
+
).with_contract_registered()
|
|
311
|
+
|
|
312
|
+
processing_time_ms = (time.perf_counter() - start_time) * 1000
|
|
313
|
+
if processing_time_ms > PERF_THRESHOLD_REDUCE_MS:
|
|
314
|
+
_logger.warning(
|
|
315
|
+
"Contract registration processing exceeded threshold",
|
|
316
|
+
extra={
|
|
317
|
+
"processing_time_ms": processing_time_ms,
|
|
318
|
+
"threshold_ms": PERF_THRESHOLD_REDUCE_MS,
|
|
319
|
+
"contract_id": contract_id,
|
|
320
|
+
"node_name": event.node_name,
|
|
321
|
+
"correlation_id": str(correlation_id),
|
|
322
|
+
},
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
return self._build_output(
|
|
326
|
+
state=new_state,
|
|
327
|
+
intents=tuple(intents),
|
|
328
|
+
processing_time_ms=processing_time_ms,
|
|
329
|
+
items_processed=1,
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
def _on_contract_deregistered(
|
|
333
|
+
self,
|
|
334
|
+
state: ModelContractRegistryState,
|
|
335
|
+
event: ModelContractDeregisteredEvent,
|
|
336
|
+
topic: str,
|
|
337
|
+
partition: int,
|
|
338
|
+
offset: int,
|
|
339
|
+
) -> ModelReducerOutput[ModelContractRegistryState]:
|
|
340
|
+
"""Handle deregistration - mark contract inactive.
|
|
341
|
+
|
|
342
|
+
This handler:
|
|
343
|
+
1. Validates the event has required fields (contract_id)
|
|
344
|
+
2. Builds a postgres.deactivate_contract intent
|
|
345
|
+
3. Returns new state with event marked as processed
|
|
346
|
+
|
|
347
|
+
Args:
|
|
348
|
+
state: Current state.
|
|
349
|
+
event: Contract deregistered event.
|
|
350
|
+
topic: Kafka topic.
|
|
351
|
+
partition: Kafka partition.
|
|
352
|
+
offset: Kafka offset.
|
|
353
|
+
|
|
354
|
+
Returns:
|
|
355
|
+
ModelReducerOutput with new state and deactivation intent.
|
|
356
|
+
"""
|
|
357
|
+
start_time = time.perf_counter()
|
|
358
|
+
|
|
359
|
+
# Extract fields from typed event
|
|
360
|
+
event_id = event.event_id
|
|
361
|
+
correlation_id = self._resolve_correlation_id(event_id, event.correlation_id)
|
|
362
|
+
|
|
363
|
+
# Derive contract identity from node_name + version
|
|
364
|
+
contract_id = self._derive_contract_id(event.node_name, event.node_version)
|
|
365
|
+
|
|
366
|
+
# Intent 1: Deactivate contract record
|
|
367
|
+
deactivate_payload = ModelPayloadDeactivateContract(
|
|
368
|
+
correlation_id=correlation_id,
|
|
369
|
+
contract_id=contract_id,
|
|
370
|
+
node_name=event.node_name,
|
|
371
|
+
reason=event.reason.value,
|
|
372
|
+
deactivated_at=event.timestamp,
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
deactivate_intent = ModelIntent(
|
|
376
|
+
intent_type="extension",
|
|
377
|
+
target=f"postgres://contracts/{contract_id}",
|
|
378
|
+
payload=deactivate_payload,
|
|
379
|
+
)
|
|
380
|
+
|
|
381
|
+
# Intent 2: Cleanup topic references (remove contract_id from topics.contract_ids)
|
|
382
|
+
cleanup_payload = ModelPayloadCleanupTopicReferences(
|
|
383
|
+
correlation_id=correlation_id,
|
|
384
|
+
contract_id=contract_id,
|
|
385
|
+
node_name=event.node_name,
|
|
386
|
+
cleaned_at=event.timestamp,
|
|
387
|
+
)
|
|
388
|
+
|
|
389
|
+
cleanup_intent = ModelIntent(
|
|
390
|
+
intent_type="extension",
|
|
391
|
+
target=f"postgres://topics/cleanup/{contract_id}",
|
|
392
|
+
payload=cleanup_payload,
|
|
393
|
+
)
|
|
394
|
+
|
|
395
|
+
new_state = state.with_event_processed(
|
|
396
|
+
event_id=event_id,
|
|
397
|
+
topic=topic,
|
|
398
|
+
partition=partition,
|
|
399
|
+
offset=offset,
|
|
400
|
+
).with_deregistration_processed()
|
|
401
|
+
|
|
402
|
+
processing_time_ms = (time.perf_counter() - start_time) * 1000
|
|
403
|
+
|
|
404
|
+
return self._build_output(
|
|
405
|
+
state=new_state,
|
|
406
|
+
intents=(deactivate_intent, cleanup_intent),
|
|
407
|
+
processing_time_ms=processing_time_ms,
|
|
408
|
+
items_processed=1,
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
def _on_heartbeat(
|
|
412
|
+
self,
|
|
413
|
+
state: ModelContractRegistryState,
|
|
414
|
+
event: ModelNodeHeartbeatEvent,
|
|
415
|
+
topic: str,
|
|
416
|
+
partition: int,
|
|
417
|
+
offset: int,
|
|
418
|
+
) -> ModelReducerOutput[ModelContractRegistryState]:
|
|
419
|
+
"""Handle heartbeat - update last_seen_at.
|
|
420
|
+
|
|
421
|
+
Heartbeats opportunistically update last_seen_at. Staleness computation
|
|
422
|
+
is deferred to runtime-tick events to reduce write amplification.
|
|
423
|
+
|
|
424
|
+
Args:
|
|
425
|
+
state: Current state.
|
|
426
|
+
event: Node heartbeat event.
|
|
427
|
+
topic: Kafka topic.
|
|
428
|
+
partition: Kafka partition.
|
|
429
|
+
offset: Kafka offset.
|
|
430
|
+
|
|
431
|
+
Returns:
|
|
432
|
+
ModelReducerOutput with new state and heartbeat update intent.
|
|
433
|
+
"""
|
|
434
|
+
start_time = time.perf_counter()
|
|
435
|
+
|
|
436
|
+
# Extract fields from typed event
|
|
437
|
+
event_id = event.event_id
|
|
438
|
+
correlation_id = self._resolve_correlation_id(event_id, event.correlation_id)
|
|
439
|
+
|
|
440
|
+
# Derive contract identity from node_name + version
|
|
441
|
+
contract_id = self._derive_contract_id(event.node_name, event.node_version)
|
|
442
|
+
|
|
443
|
+
payload = ModelPayloadUpdateHeartbeat(
|
|
444
|
+
correlation_id=correlation_id,
|
|
445
|
+
contract_id=contract_id,
|
|
446
|
+
node_name=event.node_name,
|
|
447
|
+
source_node_id=str(event.source_node_id) if event.source_node_id else None,
|
|
448
|
+
last_seen_at=event.timestamp,
|
|
449
|
+
uptime_seconds=event.uptime_seconds,
|
|
450
|
+
sequence_number=event.sequence_number,
|
|
451
|
+
)
|
|
452
|
+
|
|
453
|
+
intent = ModelIntent(
|
|
454
|
+
intent_type="extension",
|
|
455
|
+
target=f"postgres://contracts/{contract_id}/heartbeat",
|
|
456
|
+
payload=payload,
|
|
457
|
+
)
|
|
458
|
+
|
|
459
|
+
new_state = state.with_event_processed(
|
|
460
|
+
event_id=event_id,
|
|
461
|
+
topic=topic,
|
|
462
|
+
partition=partition,
|
|
463
|
+
offset=offset,
|
|
464
|
+
).with_heartbeat_processed()
|
|
465
|
+
|
|
466
|
+
processing_time_ms = (time.perf_counter() - start_time) * 1000
|
|
467
|
+
|
|
468
|
+
return self._build_output(
|
|
469
|
+
state=new_state,
|
|
470
|
+
intents=(intent,),
|
|
471
|
+
processing_time_ms=processing_time_ms,
|
|
472
|
+
items_processed=1,
|
|
473
|
+
)
|
|
474
|
+
|
|
475
|
+
def _on_runtime_tick(
|
|
476
|
+
self,
|
|
477
|
+
state: ModelContractRegistryState,
|
|
478
|
+
event: ModelRuntimeTick,
|
|
479
|
+
topic: str,
|
|
480
|
+
partition: int,
|
|
481
|
+
offset: int,
|
|
482
|
+
) -> ModelReducerOutput[ModelContractRegistryState]:
|
|
483
|
+
"""Handle runtime tick - compute staleness.
|
|
484
|
+
|
|
485
|
+
This handler is called periodically (via runtime-tick events) to:
|
|
486
|
+
1. Compute the staleness cutoff time
|
|
487
|
+
2. Emit a batch intent to mark stale contracts as inactive
|
|
488
|
+
3. Update state with staleness check timestamp
|
|
489
|
+
|
|
490
|
+
The actual staleness computation happens in PostgreSQL (via the Effect layer)
|
|
491
|
+
which can efficiently update all contracts with last_seen_at < cutoff.
|
|
492
|
+
|
|
493
|
+
Args:
|
|
494
|
+
state: Current state.
|
|
495
|
+
event: Runtime tick event with authoritative timestamp.
|
|
496
|
+
topic: Kafka topic.
|
|
497
|
+
partition: Kafka partition.
|
|
498
|
+
offset: Kafka offset.
|
|
499
|
+
|
|
500
|
+
Returns:
|
|
501
|
+
ModelReducerOutput with new state and staleness batch intent.
|
|
502
|
+
"""
|
|
503
|
+
start_time = time.perf_counter()
|
|
504
|
+
|
|
505
|
+
# Use the tick's authoritative time (not datetime.now())
|
|
506
|
+
now = event.now
|
|
507
|
+
stale_cutoff = now - STALENESS_THRESHOLD
|
|
508
|
+
|
|
509
|
+
payload = ModelPayloadMarkStale(
|
|
510
|
+
correlation_id=event.correlation_id,
|
|
511
|
+
stale_cutoff=stale_cutoff,
|
|
512
|
+
checked_at=now,
|
|
513
|
+
)
|
|
514
|
+
|
|
515
|
+
intent = ModelIntent(
|
|
516
|
+
intent_type="extension",
|
|
517
|
+
target="postgres://contracts/stale",
|
|
518
|
+
payload=payload,
|
|
519
|
+
)
|
|
520
|
+
|
|
521
|
+
new_state = state.with_event_processed(
|
|
522
|
+
event_id=event.tick_id,
|
|
523
|
+
topic=topic,
|
|
524
|
+
partition=partition,
|
|
525
|
+
offset=offset,
|
|
526
|
+
).with_staleness_check(now)
|
|
527
|
+
|
|
528
|
+
processing_time_ms = (time.perf_counter() - start_time) * 1000
|
|
529
|
+
if processing_time_ms > PERF_THRESHOLD_STALENESS_CHECK_MS:
|
|
530
|
+
_logger.warning(
|
|
531
|
+
"Staleness check processing exceeded threshold",
|
|
532
|
+
extra={
|
|
533
|
+
"processing_time_ms": processing_time_ms,
|
|
534
|
+
"threshold_ms": PERF_THRESHOLD_STALENESS_CHECK_MS,
|
|
535
|
+
"stale_cutoff": stale_cutoff.isoformat(),
|
|
536
|
+
},
|
|
537
|
+
)
|
|
538
|
+
|
|
539
|
+
return self._build_output(
|
|
540
|
+
state=new_state,
|
|
541
|
+
intents=(intent,),
|
|
542
|
+
processing_time_ms=processing_time_ms,
|
|
543
|
+
items_processed=1,
|
|
544
|
+
)
|
|
545
|
+
|
|
546
|
+
# =========================================================================
|
|
547
|
+
# Helper Methods
|
|
548
|
+
# =========================================================================
|
|
549
|
+
|
|
550
|
+
def _resolve_correlation_id(
|
|
551
|
+
self,
|
|
552
|
+
event_id: UUID,
|
|
553
|
+
correlation_id: UUID | None,
|
|
554
|
+
) -> UUID:
|
|
555
|
+
"""Resolve correlation ID, falling back to event_id if not provided.
|
|
556
|
+
|
|
557
|
+
Args:
|
|
558
|
+
event_id: The event's unique identifier.
|
|
559
|
+
correlation_id: Optional correlation ID from the event.
|
|
560
|
+
|
|
561
|
+
Returns:
|
|
562
|
+
The correlation_id if provided, otherwise the event_id.
|
|
563
|
+
"""
|
|
564
|
+
if correlation_id is None:
|
|
565
|
+
_logger.debug(
|
|
566
|
+
"Using event_id as correlation_id (none provided)",
|
|
567
|
+
extra={"event_id": str(event_id)},
|
|
568
|
+
)
|
|
569
|
+
return event_id
|
|
570
|
+
return correlation_id
|
|
571
|
+
|
|
572
|
+
@staticmethod
|
|
573
|
+
def _derive_contract_id(node_name: str, version: ModelSemVer) -> str:
|
|
574
|
+
"""Derive contract identity from node name and version.
|
|
575
|
+
|
|
576
|
+
Contract ID is a natural key in format: node_name:major.minor.patch
|
|
577
|
+
|
|
578
|
+
Args:
|
|
579
|
+
node_name: ONEX node name from contract.
|
|
580
|
+
version: Semantic version of the contract.
|
|
581
|
+
|
|
582
|
+
Returns:
|
|
583
|
+
Contract ID string (e.g., "my-node:1.0.0").
|
|
584
|
+
"""
|
|
585
|
+
return f"{node_name}:{version.major}.{version.minor}.{version.patch}"
|
|
586
|
+
|
|
587
|
+
def _build_upsert_contract_intent(
|
|
588
|
+
self,
|
|
589
|
+
event: ModelContractRegisteredEvent,
|
|
590
|
+
correlation_id: UUID,
|
|
591
|
+
) -> ModelIntent:
|
|
592
|
+
"""Build PostgreSQL upsert intent for contract record.
|
|
593
|
+
|
|
594
|
+
Args:
|
|
595
|
+
event: Contract registered event with typed fields.
|
|
596
|
+
correlation_id: Correlation ID for tracing.
|
|
597
|
+
|
|
598
|
+
Returns:
|
|
599
|
+
ModelIntent for postgres.upsert_contract.
|
|
600
|
+
"""
|
|
601
|
+
version = event.node_version
|
|
602
|
+
contract_id = self._derive_contract_id(event.node_name, version)
|
|
603
|
+
|
|
604
|
+
payload = ModelPayloadUpsertContract(
|
|
605
|
+
correlation_id=correlation_id,
|
|
606
|
+
contract_id=contract_id,
|
|
607
|
+
node_name=event.node_name,
|
|
608
|
+
version_major=version.major,
|
|
609
|
+
version_minor=version.minor,
|
|
610
|
+
version_patch=version.patch,
|
|
611
|
+
contract_hash=event.contract_hash,
|
|
612
|
+
contract_yaml=event.contract_yaml,
|
|
613
|
+
source_node_id=str(event.source_node_id) if event.source_node_id else None,
|
|
614
|
+
is_active=True,
|
|
615
|
+
registered_at=event.timestamp,
|
|
616
|
+
last_seen_at=event.timestamp,
|
|
617
|
+
)
|
|
618
|
+
|
|
619
|
+
return ModelIntent(
|
|
620
|
+
intent_type="extension",
|
|
621
|
+
target=f"postgres://contracts/{contract_id}",
|
|
622
|
+
payload=payload,
|
|
623
|
+
)
|
|
624
|
+
|
|
625
|
+
def _build_topic_update_intents(
|
|
626
|
+
self,
|
|
627
|
+
event: ModelContractRegisteredEvent,
|
|
628
|
+
correlation_id: UUID,
|
|
629
|
+
) -> list[ModelIntent]:
|
|
630
|
+
"""Extract topics from contract_yaml and build update intents.
|
|
631
|
+
|
|
632
|
+
Parses the contract_yaml for consumed_events and published_events,
|
|
633
|
+
then creates postgres.update_topic intents for each topic suffix.
|
|
634
|
+
|
|
635
|
+
Environment Placeholder Handling:
|
|
636
|
+
Topic suffixes from contract_yaml may contain ``{env}.`` placeholders
|
|
637
|
+
(e.g., ``{env}.onex.evt.platform.contract-registered.v1``). This reducer
|
|
638
|
+
stores these values **as-is** without stripping the placeholder.
|
|
639
|
+
|
|
640
|
+
This is intentional for several reasons:
|
|
641
|
+
|
|
642
|
+
1. **Reducer Purity**: The reducer remains environment-agnostic and
|
|
643
|
+
deterministic - it doesn't need to know about deployment environments.
|
|
644
|
+
|
|
645
|
+
2. **Effect Layer Responsibility**: The PostgresAdapter (Effect layer)
|
|
646
|
+
is responsible for resolving or stripping the ``{env}.`` placeholder
|
|
647
|
+
at write time, when the actual environment context is available.
|
|
648
|
+
|
|
649
|
+
3. **Auditing**: Storing the raw contract value preserves the original
|
|
650
|
+
contract specification for debugging and auditing purposes.
|
|
651
|
+
|
|
652
|
+
4. **Query Flexibility**: Downstream consumers can query topics with
|
|
653
|
+
or without the placeholder depending on their needs.
|
|
654
|
+
|
|
655
|
+
The Effect layer should handle ``{env}.`` resolution via one of:
|
|
656
|
+
- Stripping the prefix before storage (simple)
|
|
657
|
+
- Replacing with actual environment (e.g., ``dev.``, ``prod.``)
|
|
658
|
+
- Storing as-is with environment-aware queries
|
|
659
|
+
|
|
660
|
+
Args:
|
|
661
|
+
event: Contract registered event with contract_yaml.
|
|
662
|
+
correlation_id: Correlation ID for tracing.
|
|
663
|
+
|
|
664
|
+
Returns:
|
|
665
|
+
List of ModelIntent for postgres.update_topic operations.
|
|
666
|
+
"""
|
|
667
|
+
intents: list[ModelIntent] = []
|
|
668
|
+
contract_yaml_raw = event.contract_yaml
|
|
669
|
+
|
|
670
|
+
# Parse contract_yaml if it's a string
|
|
671
|
+
contract_yaml: dict
|
|
672
|
+
if isinstance(contract_yaml_raw, str):
|
|
673
|
+
try:
|
|
674
|
+
parsed = yaml.safe_load(contract_yaml_raw)
|
|
675
|
+
if not isinstance(parsed, dict):
|
|
676
|
+
_logger.debug(
|
|
677
|
+
"Parsed contract_yaml is not a dict, skipping topic extraction",
|
|
678
|
+
extra={"correlation_id": str(correlation_id)},
|
|
679
|
+
)
|
|
680
|
+
return intents
|
|
681
|
+
contract_yaml = parsed
|
|
682
|
+
except yaml.YAMLError as e:
|
|
683
|
+
_logger.warning(
|
|
684
|
+
"Failed to parse contract_yaml, skipping topic extraction",
|
|
685
|
+
extra={"correlation_id": str(correlation_id), "error": str(e)},
|
|
686
|
+
)
|
|
687
|
+
return intents
|
|
688
|
+
elif isinstance(contract_yaml_raw, dict):
|
|
689
|
+
contract_yaml = contract_yaml_raw
|
|
690
|
+
else:
|
|
691
|
+
return intents
|
|
692
|
+
|
|
693
|
+
contract_id = self._derive_contract_id(event.node_name, event.node_version)
|
|
694
|
+
|
|
695
|
+
# Extract consumed_events (subscribe topics)
|
|
696
|
+
consumed_events = contract_yaml.get("consumed_events", [])
|
|
697
|
+
if isinstance(consumed_events, list):
|
|
698
|
+
for consumed in consumed_events:
|
|
699
|
+
if isinstance(consumed, dict):
|
|
700
|
+
# NOTE: topic_suffix may contain {env}. placeholder (e.g.,
|
|
701
|
+
# "{env}.onex.evt.platform.contract-registered.v1").
|
|
702
|
+
# We store it as-is; the Effect layer handles resolution.
|
|
703
|
+
topic_suffix = consumed.get("topic")
|
|
704
|
+
if topic_suffix and isinstance(topic_suffix, str):
|
|
705
|
+
payload = ModelPayloadUpdateTopic(
|
|
706
|
+
correlation_id=correlation_id,
|
|
707
|
+
topic_suffix=topic_suffix,
|
|
708
|
+
direction="subscribe",
|
|
709
|
+
contract_id=contract_id,
|
|
710
|
+
node_name=event.node_name,
|
|
711
|
+
event_type=consumed.get("event_type"),
|
|
712
|
+
last_seen_at=event.timestamp,
|
|
713
|
+
)
|
|
714
|
+
intents.append(
|
|
715
|
+
ModelIntent(
|
|
716
|
+
intent_type="extension",
|
|
717
|
+
target=f"postgres://topics/{topic_suffix}",
|
|
718
|
+
payload=payload,
|
|
719
|
+
)
|
|
720
|
+
)
|
|
721
|
+
|
|
722
|
+
# Extract published_events (publish topics)
|
|
723
|
+
published_events = contract_yaml.get("published_events", [])
|
|
724
|
+
if isinstance(published_events, list):
|
|
725
|
+
for published in published_events:
|
|
726
|
+
if isinstance(published, dict):
|
|
727
|
+
# NOTE: topic_suffix may contain {env}. placeholder - stored as-is,
|
|
728
|
+
# Effect layer handles resolution (see docstring above).
|
|
729
|
+
topic_suffix = published.get("topic")
|
|
730
|
+
if topic_suffix and isinstance(topic_suffix, str):
|
|
731
|
+
payload = ModelPayloadUpdateTopic(
|
|
732
|
+
correlation_id=correlation_id,
|
|
733
|
+
topic_suffix=topic_suffix,
|
|
734
|
+
direction="publish",
|
|
735
|
+
contract_id=contract_id,
|
|
736
|
+
node_name=event.node_name,
|
|
737
|
+
event_type=published.get("event_type"),
|
|
738
|
+
last_seen_at=event.timestamp,
|
|
739
|
+
)
|
|
740
|
+
intents.append(
|
|
741
|
+
ModelIntent(
|
|
742
|
+
intent_type="extension",
|
|
743
|
+
target=f"postgres://topics/{topic_suffix}",
|
|
744
|
+
payload=payload,
|
|
745
|
+
)
|
|
746
|
+
)
|
|
747
|
+
|
|
748
|
+
return intents
|
|
749
|
+
|
|
750
|
+
def _build_output(
|
|
751
|
+
self,
|
|
752
|
+
state: ModelContractRegistryState,
|
|
753
|
+
intents: tuple[ModelIntent, ...],
|
|
754
|
+
processing_time_ms: float,
|
|
755
|
+
items_processed: int,
|
|
756
|
+
) -> ModelReducerOutput[ModelContractRegistryState]:
|
|
757
|
+
"""Build standardized ModelReducerOutput.
|
|
758
|
+
|
|
759
|
+
Args:
|
|
760
|
+
state: New contract registry state to return.
|
|
761
|
+
intents: Tuple of ModelIntent objects to emit.
|
|
762
|
+
processing_time_ms: Time taken to process the event.
|
|
763
|
+
items_processed: Number of events processed (0 or 1).
|
|
764
|
+
|
|
765
|
+
Returns:
|
|
766
|
+
ModelReducerOutput containing the state and intents.
|
|
767
|
+
"""
|
|
768
|
+
return ModelReducerOutput(
|
|
769
|
+
result=state,
|
|
770
|
+
operation_id=uuid4(),
|
|
771
|
+
reduction_type=EnumReductionType.MERGE,
|
|
772
|
+
processing_time_ms=processing_time_ms,
|
|
773
|
+
items_processed=items_processed,
|
|
774
|
+
conflicts_resolved=0,
|
|
775
|
+
streaming_mode=EnumStreamingMode.BATCH,
|
|
776
|
+
batches_processed=1,
|
|
777
|
+
intents=intents,
|
|
778
|
+
)
|
|
779
|
+
|
|
780
|
+
|
|
781
|
+
__all__ = [
|
|
782
|
+
"ContractRegistryReducer",
|
|
783
|
+
"ContractRegistryEvent",
|
|
784
|
+
]
|