omnibase_infra 0.2.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- omnibase_infra/__init__.py +101 -0
- omnibase_infra/cli/__init__.py +1 -0
- omnibase_infra/cli/commands.py +216 -0
- omnibase_infra/clients/__init__.py +0 -0
- omnibase_infra/contracts/handlers/filesystem/handler_contract.yaml +261 -0
- omnibase_infra/contracts/handlers/mcp/handler_contract.yaml +138 -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 +123 -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_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 +101 -0
- omnibase_infra/enums/enum_handler_loader_error.py +178 -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_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 +156 -0
- omnibase_infra/errors/error_architecture_violation.py +152 -0
- omnibase_infra/errors/error_chain_propagation.py +188 -0
- omnibase_infra/errors/error_compute_registry.py +92 -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 +102 -0
- omnibase_infra/errors/error_infra.py +608 -0
- omnibase_infra/errors/error_message_type_registry.py +101 -0
- omnibase_infra/errors/error_policy_registry.py +112 -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 +86 -0
- omnibase_infra/event_bus/event_bus_inmemory.py +743 -0
- omnibase_infra/event_bus/event_bus_kafka.py +1658 -0
- omnibase_infra/event_bus/mixin_kafka_broadcast.py +184 -0
- omnibase_infra/event_bus/mixin_kafka_dlq.py +765 -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 +725 -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/topic_constants.py +376 -0
- omnibase_infra/handlers/__init__.py +75 -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 +787 -0
- omnibase_infra/handlers/handler_db.py +1039 -0
- omnibase_infra/handlers/handler_filesystem.py +1478 -0
- omnibase_infra/handlers/handler_graph.py +1154 -0
- omnibase_infra/handlers/handler_http.py +920 -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 +748 -0
- omnibase_infra/handlers/handler_qdrant.py +1076 -0
- omnibase_infra/handlers/handler_vault.py +422 -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 +42 -0
- omnibase_infra/handlers/mixins/mixin_consul_initialization.py +349 -0
- omnibase_infra/handlers/mixins/mixin_consul_kv.py +337 -0
- omnibase_infra/handlers/mixins/mixin_consul_service.py +277 -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 +915 -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 +747 -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 +99 -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/mixins/__init__.py +71 -0
- omnibase_infra/mixins/mixin_async_circuit_breaker.py +655 -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 +2465 -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 +136 -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 +311 -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 +147 -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_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 +37 -0
- omnibase_infra/models/handlers/model_contract_discovery_result.py +80 -0
- omnibase_infra/models/handlers/model_handler_descriptor.py +185 -0
- omnibase_infra/models/handlers/model_handler_identifier.py +215 -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/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 +590 -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 +59 -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_introspection_metrics.py +253 -0
- omnibase_infra/models/registration/model_node_capabilities.py +179 -0
- omnibase_infra/models/registration/model_node_heartbeat_event.py +126 -0
- omnibase_infra/models/registration/model_node_introspection_event.py +175 -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 +40 -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 +280 -0
- omnibase_infra/models/runtime/model_loaded_handler.py +120 -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 +48 -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 +208 -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 +99 -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/effects/README.md +358 -0
- omnibase_infra/nodes/effects/__init__.py +26 -0
- omnibase_infra/nodes/effects/contract.yaml +172 -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/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 +475 -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 +609 -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 +525 -0
- omnibase_infra/nodes/node_registration_orchestrator/timeout_coordinator.py +392 -0
- omnibase_infra/nodes/node_registration_orchestrator/wiring.py +742 -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 +225 -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 +109 -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 +194 -0
- omnibase_infra/nodes/node_registry_effect/__init__.py +85 -0
- omnibase_infra/nodes/node_registry_effect/contract.yaml +682 -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 +416 -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 +214 -0
- omnibase_infra/nodes/reducers/__init__.py +30 -0
- omnibase_infra/nodes/reducers/models/__init__.py +32 -0
- omnibase_infra/nodes/reducers/models/model_payload_consul_register.py +76 -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 +1137 -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 +435 -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 +99 -0
- omnibase_infra/protocols/protocol_capability_projection.py +253 -0
- omnibase_infra/protocols/protocol_capability_query.py +251 -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 +296 -0
- omnibase_infra/runtime/binding_config_resolver.py +2706 -0
- omnibase_infra/runtime/chain_aware_dispatch.py +467 -0
- omnibase_infra/runtime/contract_handler_discovery.py +582 -0
- omnibase_infra/runtime/contract_loaders/__init__.py +42 -0
- omnibase_infra/runtime/contract_loaders/handler_routing_loader.py +464 -0
- omnibase_infra/runtime/dispatch_context_enforcer.py +427 -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/handler_contract_source.py +669 -0
- omnibase_infra/runtime/handler_plugin_loader.py +2029 -0
- omnibase_infra/runtime/handler_registry.py +321 -0
- omnibase_infra/runtime/invocation_security_enforcer.py +427 -0
- omnibase_infra/runtime/kernel.py +40 -0
- omnibase_infra/runtime/mixin_policy_validation.py +522 -0
- omnibase_infra/runtime/mixin_semver_cache.py +378 -0
- omnibase_infra/runtime/mixins/__init__.py +17 -0
- omnibase_infra/runtime/mixins/mixin_projector_sql_operations.py +757 -0
- omnibase_infra/runtime/models/__init__.py +192 -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_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 +228 -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_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_scheduler_config.py +624 -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_shutdown_batch_result.py +75 -0
- omnibase_infra/runtime/models/model_shutdown_config.py +94 -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 +1102 -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 +27 -0
- omnibase_infra/runtime/protocols/protocol_runtime_scheduler.py +468 -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 +444 -0
- omnibase_infra/runtime/registry_compute.py +1143 -0
- omnibase_infra/runtime/registry_dispatcher.py +678 -0
- omnibase_infra/runtime/registry_policy.py +1502 -0
- omnibase_infra/runtime/runtime_scheduler.py +1070 -0
- omnibase_infra/runtime/secret_resolver.py +2110 -0
- omnibase_infra/runtime/security_metadata_validator.py +776 -0
- omnibase_infra/runtime/service_kernel.py +1573 -0
- omnibase_infra/runtime/service_message_dispatch_engine.py +1805 -0
- omnibase_infra/runtime/service_runtime_host_process.py +2260 -0
- omnibase_infra/runtime/util_container_wiring.py +1123 -0
- omnibase_infra/runtime/util_validation.py +314 -0
- omnibase_infra/runtime/util_version.py +98 -0
- omnibase_infra/runtime/util_wiring.py +566 -0
- omnibase_infra/schemas/schema_registration_projection.sql +320 -0
- omnibase_infra/services/__init__.py +68 -0
- omnibase_infra/services/corpus_capture.py +678 -0
- omnibase_infra/services/service_capability_query.py +945 -0
- omnibase_infra/services/service_health.py +897 -0
- omnibase_infra/services/service_node_selector.py +530 -0
- omnibase_infra/services/service_timeout_emitter.py +682 -0
- omnibase_infra/services/service_timeout_scanner.py +390 -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/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 +21 -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 +89 -0
- omnibase_infra/utils/correlation.py +208 -0
- omnibase_infra/utils/util_datetime.py +372 -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_semver.py +233 -0
- omnibase_infra/validation/__init__.py +307 -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 +1486 -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 +1710 -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 +410 -0
- omnibase_infra/validation/validator_topic_category.py +1152 -0
- omnibase_infra-0.2.1.dist-info/METADATA +197 -0
- omnibase_infra-0.2.1.dist-info/RECORD +675 -0
- omnibase_infra-0.2.1.dist-info/WHEEL +4 -0
- omnibase_infra-0.2.1.dist-info/entry_points.txt +4 -0
- omnibase_infra-0.2.1.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,907 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""
|
|
4
|
+
ONEX Infrastructure Contract Linter.
|
|
5
|
+
|
|
6
|
+
Validates contract.yaml files against ONEX infrastructure requirements:
|
|
7
|
+
- Required fields: name, node_type, contract_version, input_model, output_model
|
|
8
|
+
- Type consistency: input_model/output_model module references are importable
|
|
9
|
+
- YAML syntax validity
|
|
10
|
+
- Node type constraints (EFFECT_GENERIC, COMPUTE_GENERIC, REDUCER_GENERIC, ORCHESTRATOR_GENERIC)
|
|
11
|
+
|
|
12
|
+
This linter complements omnibase_core.validation.validate_contracts by adding
|
|
13
|
+
infrastructure-specific validation that is not covered by the base validator.
|
|
14
|
+
|
|
15
|
+
Integration with Structured Error Reporting (OMN-1091):
|
|
16
|
+
The linter now supports converting contract violations to structured
|
|
17
|
+
ModelHandlerValidationError instances with unique rule IDs, handler
|
|
18
|
+
identities, and remediation hints. Use ModelContractLintResult.to_handler_errors()
|
|
19
|
+
to convert violations to structured errors.
|
|
20
|
+
|
|
21
|
+
Rule ID Mapping:
|
|
22
|
+
CONTRACT-001: YAML parse error
|
|
23
|
+
CONTRACT-002: Missing required field
|
|
24
|
+
CONTRACT-003: Invalid node_type
|
|
25
|
+
CONTRACT-004: Invalid field type
|
|
26
|
+
CONTRACT-005: Import error for models
|
|
27
|
+
CONTRACT-006: Invalid contract_version format
|
|
28
|
+
CONTRACT-007: Invalid model reference
|
|
29
|
+
CONTRACT-008: Invalid name convention
|
|
30
|
+
CONTRACT-009: File not found
|
|
31
|
+
CONTRACT-010: Non-dict contract
|
|
32
|
+
CONTRACT-011: Model not found in module
|
|
33
|
+
CONTRACT-012: Encoding error
|
|
34
|
+
|
|
35
|
+
Usage:
|
|
36
|
+
from omnibase_infra.validation.contract_linter import (
|
|
37
|
+
ContractLinter,
|
|
38
|
+
lint_contracts_in_directory,
|
|
39
|
+
lint_contract_file,
|
|
40
|
+
convert_violation_to_handler_error,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
# Lint all contracts in a directory
|
|
44
|
+
result = lint_contracts_in_directory("src/omnibase_infra/nodes/")
|
|
45
|
+
|
|
46
|
+
# Lint a single contract file
|
|
47
|
+
result = lint_contract_file("path/to/contract.yaml")
|
|
48
|
+
|
|
49
|
+
# Convert violations to structured errors
|
|
50
|
+
errors = result.to_handler_errors()
|
|
51
|
+
for error in errors:
|
|
52
|
+
logger.error(error.format_for_logging())
|
|
53
|
+
|
|
54
|
+
Exit Codes (for CI):
|
|
55
|
+
0: All contracts valid
|
|
56
|
+
1: Validation failures found
|
|
57
|
+
2: Runtime error (file not found, YAML parse error, etc.)
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
import importlib
|
|
61
|
+
import logging
|
|
62
|
+
import re
|
|
63
|
+
from pathlib import Path
|
|
64
|
+
from typing import Literal
|
|
65
|
+
from uuid import UUID, uuid4
|
|
66
|
+
|
|
67
|
+
import yaml
|
|
68
|
+
|
|
69
|
+
from omnibase_infra.enums import EnumValidationSeverity
|
|
70
|
+
from omnibase_infra.models.errors import ModelHandlerValidationError
|
|
71
|
+
from omnibase_infra.models.handlers import ModelHandlerIdentifier
|
|
72
|
+
from omnibase_infra.types import PathInput
|
|
73
|
+
from omnibase_infra.validation.enums.enum_contract_violation_severity import (
|
|
74
|
+
EnumContractViolationSeverity,
|
|
75
|
+
)
|
|
76
|
+
from omnibase_infra.validation.models.model_contract_lint_result import (
|
|
77
|
+
ModelContractLintResult,
|
|
78
|
+
)
|
|
79
|
+
from omnibase_infra.validation.models.model_contract_violation import (
|
|
80
|
+
ModelContractViolation,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
# Module-level logger
|
|
84
|
+
logger = logging.getLogger(__name__)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
# Valid node types per ONEX 4-node architecture (omnibase_core 0.7.0+)
|
|
88
|
+
VALID_NODE_TYPES = frozenset(
|
|
89
|
+
{"EFFECT_GENERIC", "COMPUTE_GENERIC", "REDUCER_GENERIC", "ORCHESTRATOR_GENERIC"}
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
# Rule ID mapping for contract violations
|
|
94
|
+
class ContractRuleId:
|
|
95
|
+
"""Rule IDs for contract validation errors.
|
|
96
|
+
|
|
97
|
+
These IDs provide unique identifiers for each type of contract validation
|
|
98
|
+
failure, enabling structured error tracking and remediation guidance.
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
YAML_PARSE_ERROR = "CONTRACT-001"
|
|
102
|
+
MISSING_REQUIRED_FIELD = "CONTRACT-002"
|
|
103
|
+
INVALID_NODE_TYPE = "CONTRACT-003"
|
|
104
|
+
INVALID_FIELD_TYPE = "CONTRACT-004"
|
|
105
|
+
IMPORT_ERROR = "CONTRACT-005"
|
|
106
|
+
INVALID_CONTRACT_VERSION = "CONTRACT-006"
|
|
107
|
+
INVALID_MODEL_REFERENCE = "CONTRACT-007"
|
|
108
|
+
INVALID_NAME_CONVENTION = "CONTRACT-008"
|
|
109
|
+
FILE_NOT_FOUND = "CONTRACT-009"
|
|
110
|
+
NON_DICT_CONTRACT = "CONTRACT-010"
|
|
111
|
+
MODEL_NOT_FOUND = "CONTRACT-011"
|
|
112
|
+
ENCODING_ERROR = "CONTRACT-012"
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def convert_violation_to_handler_error(
|
|
116
|
+
violation: ModelContractViolation,
|
|
117
|
+
correlation_id: UUID | None = None,
|
|
118
|
+
) -> ModelHandlerValidationError:
|
|
119
|
+
"""Convert contract violation to structured handler validation error.
|
|
120
|
+
|
|
121
|
+
Maps ModelContractViolation to ModelHandlerValidationError with appropriate
|
|
122
|
+
rule IDs, handler identity, and remediation hints for structured error reporting.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
violation: Contract violation to convert.
|
|
126
|
+
correlation_id: Optional correlation ID for distributed tracing.
|
|
127
|
+
|
|
128
|
+
Returns:
|
|
129
|
+
ModelHandlerValidationError with structured error information.
|
|
130
|
+
|
|
131
|
+
Example:
|
|
132
|
+
>>> violation = ModelContractViolation(
|
|
133
|
+
... file_path="nodes/registration/contract.yaml",
|
|
134
|
+
... field_path="node_type",
|
|
135
|
+
... message="Invalid node_type 'INVALID'",
|
|
136
|
+
... severity=EnumContractViolationSeverity.ERROR,
|
|
137
|
+
... )
|
|
138
|
+
>>> error = convert_violation_to_handler_error(violation)
|
|
139
|
+
>>> error.rule_id
|
|
140
|
+
'CONTRACT-003'
|
|
141
|
+
"""
|
|
142
|
+
# Derive handler_id from file path (e.g., nodes/registration/contract.yaml -> registration)
|
|
143
|
+
file_path = violation.file_path
|
|
144
|
+
handler_id = _derive_handler_id_from_path(file_path)
|
|
145
|
+
|
|
146
|
+
# Create handler identifier
|
|
147
|
+
handler_identity = ModelHandlerIdentifier.from_handler_id(handler_id)
|
|
148
|
+
|
|
149
|
+
# Map violation to rule ID based on field_path and message
|
|
150
|
+
rule_id = _map_violation_to_rule_id(violation)
|
|
151
|
+
|
|
152
|
+
# Map severity
|
|
153
|
+
severity = (
|
|
154
|
+
EnumValidationSeverity.ERROR
|
|
155
|
+
if violation.severity == EnumContractViolationSeverity.ERROR
|
|
156
|
+
else EnumValidationSeverity.WARNING
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
# Use suggestion as remediation hint, or provide default
|
|
160
|
+
remediation_hint = (
|
|
161
|
+
violation.suggestion or "Review contract.yaml and fix the validation error"
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
return ModelHandlerValidationError.from_contract_error(
|
|
165
|
+
rule_id=rule_id,
|
|
166
|
+
message=violation.message,
|
|
167
|
+
file_path=file_path,
|
|
168
|
+
remediation_hint=remediation_hint,
|
|
169
|
+
handler_identity=handler_identity,
|
|
170
|
+
line_number=None, # Contract linter doesn't track line numbers currently
|
|
171
|
+
correlation_id=correlation_id or uuid4(),
|
|
172
|
+
severity=severity,
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def _derive_handler_id_from_path(file_path: str) -> str:
|
|
177
|
+
"""Derive handler ID from contract file path.
|
|
178
|
+
|
|
179
|
+
Extracts the node name from the contract file path to use as handler_id.
|
|
180
|
+
For root-level contract.yaml files without a meaningful parent directory,
|
|
181
|
+
falls back to using the filename stem as the handler ID.
|
|
182
|
+
|
|
183
|
+
Args:
|
|
184
|
+
file_path: Path to contract.yaml file.
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
Derived handler ID (e.g., "registration" from "nodes/registration/contract.yaml").
|
|
188
|
+
|
|
189
|
+
Example:
|
|
190
|
+
>>> _derive_handler_id_from_path("nodes/registration/contract.yaml")
|
|
191
|
+
'registration'
|
|
192
|
+
>>> _derive_handler_id_from_path("contract.yaml")
|
|
193
|
+
'contract'
|
|
194
|
+
>>> _derive_handler_id_from_path("./contract.yaml")
|
|
195
|
+
'contract'
|
|
196
|
+
>>> _derive_handler_id_from_path("/tmp/contract.yaml")
|
|
197
|
+
'tmp'
|
|
198
|
+
"""
|
|
199
|
+
# Extract parent directory name as handler ID
|
|
200
|
+
path = Path(file_path)
|
|
201
|
+
if path.name == "contract.yaml":
|
|
202
|
+
# Get parent directory name, but only if it's meaningful (not ".", "", or just "/")
|
|
203
|
+
parent_name = path.parent.name
|
|
204
|
+
if parent_name and parent_name not in {".", "", "/"}:
|
|
205
|
+
return parent_name
|
|
206
|
+
# Fallback to filename without extension for root-level files
|
|
207
|
+
return path.stem
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def _map_violation_to_rule_id(violation: ModelContractViolation) -> str:
|
|
211
|
+
"""Map contract violation to appropriate rule ID using keyword heuristics.
|
|
212
|
+
|
|
213
|
+
This function uses a decision tree based on keyword matching in the violation's
|
|
214
|
+
field_path and message to determine the appropriate CONTRACT-xxx rule ID.
|
|
215
|
+
The mapping provides unique, stable rule IDs for structured error reporting.
|
|
216
|
+
|
|
217
|
+
Mapping Logic (evaluated in order):
|
|
218
|
+
|
|
219
|
+
1. **YAML/File-Level Errors** (no field_path):
|
|
220
|
+
- "not found" → CONTRACT-009 (FILE_NOT_FOUND)
|
|
221
|
+
- "yaml" + "parse" → CONTRACT-001 (YAML_PARSE_ERROR)
|
|
222
|
+
- "encoding" or "binary" → CONTRACT-012 (ENCODING_ERROR)
|
|
223
|
+
- "must be a yaml mapping" or "must be a dict" → CONTRACT-010 (NON_DICT_CONTRACT)
|
|
224
|
+
|
|
225
|
+
2. **Missing Fields**:
|
|
226
|
+
- "missing" + "required field" → CONTRACT-002 (MISSING_REQUIRED_FIELD)
|
|
227
|
+
|
|
228
|
+
3. **Field-Specific Errors** (based on field_path):
|
|
229
|
+
- field_path == "node_type":
|
|
230
|
+
- "invalid node_type" → CONTRACT-003 (INVALID_NODE_TYPE)
|
|
231
|
+
- "must be a string" → CONTRACT-004 (INVALID_FIELD_TYPE)
|
|
232
|
+
- field_path starts with "contract_version" → CONTRACT-006 (INVALID_CONTRACT_VERSION)
|
|
233
|
+
- field_path starts with "input_model" or "output_model":
|
|
234
|
+
- "cannot import" → CONTRACT-005 (IMPORT_ERROR)
|
|
235
|
+
- "not found in module" → CONTRACT-011 (MODEL_NOT_FOUND)
|
|
236
|
+
- Otherwise → CONTRACT-007 (INVALID_MODEL_REFERENCE)
|
|
237
|
+
- field_path == "name" → CONTRACT-008 (INVALID_NAME_CONVENTION)
|
|
238
|
+
|
|
239
|
+
4. **Default Fallback**:
|
|
240
|
+
- CONTRACT-004 (INVALID_FIELD_TYPE) for any unmatched violations
|
|
241
|
+
|
|
242
|
+
Args:
|
|
243
|
+
violation: Contract violation to map.
|
|
244
|
+
|
|
245
|
+
Returns:
|
|
246
|
+
Rule ID string (e.g., "CONTRACT-001").
|
|
247
|
+
|
|
248
|
+
Note:
|
|
249
|
+
This heuristic-based approach enables automatic rule ID assignment without
|
|
250
|
+
requiring explicit rule IDs at violation creation time. The keyword patterns
|
|
251
|
+
are chosen to match the actual error messages generated by ContractLinter,
|
|
252
|
+
ensuring consistent and predictable rule ID assignment.
|
|
253
|
+
|
|
254
|
+
The decision tree is evaluated top-to-bottom with early returns, so more
|
|
255
|
+
specific patterns should be checked before general ones.
|
|
256
|
+
"""
|
|
257
|
+
field_path = violation.field_path
|
|
258
|
+
message_lower = violation.message.lower()
|
|
259
|
+
|
|
260
|
+
# YAML/file errors
|
|
261
|
+
if "not found" in message_lower and not field_path:
|
|
262
|
+
return ContractRuleId.FILE_NOT_FOUND
|
|
263
|
+
if "yaml" in message_lower and "parse" in message_lower:
|
|
264
|
+
return ContractRuleId.YAML_PARSE_ERROR
|
|
265
|
+
if "encoding" in message_lower or "binary" in message_lower:
|
|
266
|
+
return ContractRuleId.ENCODING_ERROR
|
|
267
|
+
if "must be a yaml mapping" in message_lower or "must be a dict" in message_lower:
|
|
268
|
+
return ContractRuleId.NON_DICT_CONTRACT
|
|
269
|
+
|
|
270
|
+
# Field-specific errors
|
|
271
|
+
if not field_path:
|
|
272
|
+
return ContractRuleId.YAML_PARSE_ERROR
|
|
273
|
+
|
|
274
|
+
# Missing required fields
|
|
275
|
+
if "missing" in message_lower and "required field" in message_lower:
|
|
276
|
+
return ContractRuleId.MISSING_REQUIRED_FIELD
|
|
277
|
+
|
|
278
|
+
# Node type validation
|
|
279
|
+
if field_path == "node_type":
|
|
280
|
+
if "invalid node_type" in message_lower:
|
|
281
|
+
return ContractRuleId.INVALID_NODE_TYPE
|
|
282
|
+
if "must be a string" in message_lower:
|
|
283
|
+
return ContractRuleId.INVALID_FIELD_TYPE
|
|
284
|
+
|
|
285
|
+
# Contract version validation
|
|
286
|
+
if field_path.startswith("contract_version"):
|
|
287
|
+
return ContractRuleId.INVALID_CONTRACT_VERSION
|
|
288
|
+
|
|
289
|
+
# Model reference validation
|
|
290
|
+
if field_path.startswith(("input_model", "output_model")):
|
|
291
|
+
if "cannot import" in message_lower:
|
|
292
|
+
return ContractRuleId.IMPORT_ERROR
|
|
293
|
+
if "not found in module" in message_lower:
|
|
294
|
+
return ContractRuleId.MODEL_NOT_FOUND
|
|
295
|
+
return ContractRuleId.INVALID_MODEL_REFERENCE
|
|
296
|
+
|
|
297
|
+
# Name convention validation
|
|
298
|
+
if field_path == "name":
|
|
299
|
+
return ContractRuleId.INVALID_NAME_CONVENTION
|
|
300
|
+
|
|
301
|
+
# Default to invalid field type
|
|
302
|
+
return ContractRuleId.INVALID_FIELD_TYPE
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
class ContractLinter:
|
|
306
|
+
"""
|
|
307
|
+
ONEX Infrastructure Contract Linter.
|
|
308
|
+
|
|
309
|
+
Validates contract.yaml files for required fields, type consistency,
|
|
310
|
+
and ONEX compliance. Designed for CI integration with clear exit codes.
|
|
311
|
+
|
|
312
|
+
Required Fields:
|
|
313
|
+
- name: Node identifier (snake_case)
|
|
314
|
+
- node_type: One of EFFECT_GENERIC, COMPUTE_GENERIC, REDUCER_GENERIC, ORCHESTRATOR_GENERIC
|
|
315
|
+
- contract_version: Semantic version dict with major, minor, patch
|
|
316
|
+
- input_model: Dict with name and module fields
|
|
317
|
+
- output_model: Dict with name and module fields
|
|
318
|
+
|
|
319
|
+
Optional but Recommended Fields:
|
|
320
|
+
- description: Human-readable description
|
|
321
|
+
- node_version: Semantic version string
|
|
322
|
+
- dependencies: List of dependency declarations
|
|
323
|
+
- consumed_events: Event topics the node subscribes to
|
|
324
|
+
- published_events: Event topics the node publishes to
|
|
325
|
+
"""
|
|
326
|
+
|
|
327
|
+
def __init__(
|
|
328
|
+
self,
|
|
329
|
+
*,
|
|
330
|
+
check_imports: bool = True,
|
|
331
|
+
strict_mode: bool = False,
|
|
332
|
+
):
|
|
333
|
+
"""
|
|
334
|
+
Initialize the contract linter.
|
|
335
|
+
|
|
336
|
+
Args:
|
|
337
|
+
check_imports: Whether to verify input_model/output_model modules
|
|
338
|
+
are importable. Disable for faster validation when
|
|
339
|
+
modules may not be in the Python path.
|
|
340
|
+
strict_mode: If True, treat warnings as errors.
|
|
341
|
+
"""
|
|
342
|
+
self.check_imports = check_imports
|
|
343
|
+
self.strict_mode = strict_mode
|
|
344
|
+
|
|
345
|
+
def lint_file(self, file_path: Path) -> ModelContractLintResult:
|
|
346
|
+
"""
|
|
347
|
+
Lint a single contract.yaml file.
|
|
348
|
+
|
|
349
|
+
Args:
|
|
350
|
+
file_path: Path to the contract.yaml file.
|
|
351
|
+
|
|
352
|
+
Returns:
|
|
353
|
+
ModelContractLintResult with violations found.
|
|
354
|
+
"""
|
|
355
|
+
violations: list[ModelContractViolation] = []
|
|
356
|
+
file_str = str(file_path)
|
|
357
|
+
|
|
358
|
+
# Check file exists
|
|
359
|
+
if not file_path.exists():
|
|
360
|
+
violations.append(
|
|
361
|
+
ModelContractViolation(
|
|
362
|
+
file_path=file_str,
|
|
363
|
+
field_path="",
|
|
364
|
+
message=f"Contract file not found: {file_path}",
|
|
365
|
+
severity=EnumContractViolationSeverity.ERROR,
|
|
366
|
+
)
|
|
367
|
+
)
|
|
368
|
+
return ModelContractLintResult(
|
|
369
|
+
is_valid=False,
|
|
370
|
+
violations=violations,
|
|
371
|
+
files_checked=1,
|
|
372
|
+
files_with_errors=1,
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
# Parse YAML
|
|
376
|
+
try:
|
|
377
|
+
with file_path.open("r", encoding="utf-8") as f:
|
|
378
|
+
content = yaml.safe_load(f)
|
|
379
|
+
except yaml.YAMLError as e:
|
|
380
|
+
violations.append(
|
|
381
|
+
ModelContractViolation(
|
|
382
|
+
file_path=file_str,
|
|
383
|
+
field_path="",
|
|
384
|
+
message=f"YAML parse error: {e}",
|
|
385
|
+
severity=EnumContractViolationSeverity.ERROR,
|
|
386
|
+
)
|
|
387
|
+
)
|
|
388
|
+
return ModelContractLintResult(
|
|
389
|
+
is_valid=False,
|
|
390
|
+
violations=violations,
|
|
391
|
+
files_checked=1,
|
|
392
|
+
files_with_errors=1,
|
|
393
|
+
)
|
|
394
|
+
except UnicodeDecodeError as e:
|
|
395
|
+
violations.append(
|
|
396
|
+
ModelContractViolation(
|
|
397
|
+
file_path=file_str,
|
|
398
|
+
field_path="",
|
|
399
|
+
message=f"Contract file contains binary or non-UTF-8 content: "
|
|
400
|
+
f"encoding error at position {e.start}-{e.end}: {e.reason}",
|
|
401
|
+
severity=EnumContractViolationSeverity.ERROR,
|
|
402
|
+
)
|
|
403
|
+
)
|
|
404
|
+
return ModelContractLintResult(
|
|
405
|
+
is_valid=False,
|
|
406
|
+
violations=violations,
|
|
407
|
+
files_checked=1,
|
|
408
|
+
files_with_errors=1,
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
if not isinstance(content, dict):
|
|
412
|
+
violations.append(
|
|
413
|
+
ModelContractViolation(
|
|
414
|
+
file_path=file_str,
|
|
415
|
+
field_path="",
|
|
416
|
+
message="Contract must be a YAML mapping (dict), not a scalar or list",
|
|
417
|
+
severity=EnumContractViolationSeverity.ERROR,
|
|
418
|
+
)
|
|
419
|
+
)
|
|
420
|
+
return ModelContractLintResult(
|
|
421
|
+
is_valid=False,
|
|
422
|
+
violations=violations,
|
|
423
|
+
files_checked=1,
|
|
424
|
+
files_with_errors=1,
|
|
425
|
+
)
|
|
426
|
+
|
|
427
|
+
# Validate required fields
|
|
428
|
+
violations.extend(self._validate_required_fields(file_str, content))
|
|
429
|
+
|
|
430
|
+
# Validate node_type
|
|
431
|
+
violations.extend(self._validate_node_type(file_str, content))
|
|
432
|
+
|
|
433
|
+
# Validate contract_version format
|
|
434
|
+
violations.extend(self._validate_contract_version(file_str, content))
|
|
435
|
+
|
|
436
|
+
# Validate input_model and output_model
|
|
437
|
+
violations.extend(
|
|
438
|
+
self._validate_model_reference(file_str, content, "input_model")
|
|
439
|
+
)
|
|
440
|
+
violations.extend(
|
|
441
|
+
self._validate_model_reference(file_str, content, "output_model")
|
|
442
|
+
)
|
|
443
|
+
|
|
444
|
+
# Validate naming convention (name should be snake_case)
|
|
445
|
+
violations.extend(self._validate_name_convention(file_str, content))
|
|
446
|
+
|
|
447
|
+
# Check for recommended fields
|
|
448
|
+
violations.extend(self._check_recommended_fields(file_str, content))
|
|
449
|
+
|
|
450
|
+
# Calculate result
|
|
451
|
+
has_errors = any(
|
|
452
|
+
v.severity == EnumContractViolationSeverity.ERROR for v in violations
|
|
453
|
+
)
|
|
454
|
+
if self.strict_mode:
|
|
455
|
+
has_errors = has_errors or any(
|
|
456
|
+
v.severity == EnumContractViolationSeverity.WARNING for v in violations
|
|
457
|
+
)
|
|
458
|
+
|
|
459
|
+
return ModelContractLintResult(
|
|
460
|
+
is_valid=not has_errors,
|
|
461
|
+
violations=violations,
|
|
462
|
+
files_checked=1,
|
|
463
|
+
files_valid=0 if has_errors else 1,
|
|
464
|
+
files_with_errors=1 if has_errors else 0,
|
|
465
|
+
)
|
|
466
|
+
|
|
467
|
+
def lint_directory(
|
|
468
|
+
self,
|
|
469
|
+
directory: Path,
|
|
470
|
+
*,
|
|
471
|
+
recursive: bool = True,
|
|
472
|
+
) -> ModelContractLintResult:
|
|
473
|
+
"""
|
|
474
|
+
Lint all contract.yaml files in a directory.
|
|
475
|
+
|
|
476
|
+
Args:
|
|
477
|
+
directory: Directory to search for contract.yaml files.
|
|
478
|
+
recursive: Whether to search subdirectories.
|
|
479
|
+
|
|
480
|
+
Returns:
|
|
481
|
+
ModelContractLintResult with aggregated violations.
|
|
482
|
+
"""
|
|
483
|
+
if not directory.exists():
|
|
484
|
+
return ModelContractLintResult(
|
|
485
|
+
is_valid=False,
|
|
486
|
+
violations=[
|
|
487
|
+
ModelContractViolation(
|
|
488
|
+
file_path=str(directory),
|
|
489
|
+
field_path="",
|
|
490
|
+
message=f"Directory not found: {directory}",
|
|
491
|
+
severity=EnumContractViolationSeverity.ERROR,
|
|
492
|
+
)
|
|
493
|
+
],
|
|
494
|
+
files_checked=0,
|
|
495
|
+
files_with_errors=0,
|
|
496
|
+
)
|
|
497
|
+
|
|
498
|
+
# Find all contract.yaml files
|
|
499
|
+
pattern = "**/contract.yaml" if recursive else "contract.yaml"
|
|
500
|
+
contract_files = list(directory.glob(pattern))
|
|
501
|
+
|
|
502
|
+
if not contract_files:
|
|
503
|
+
# No contracts found - this is informational, not an error
|
|
504
|
+
logger.info("No contract.yaml files found in %s", directory)
|
|
505
|
+
return ModelContractLintResult(
|
|
506
|
+
is_valid=True,
|
|
507
|
+
violations=[],
|
|
508
|
+
files_checked=0,
|
|
509
|
+
files_valid=0,
|
|
510
|
+
files_with_errors=0,
|
|
511
|
+
)
|
|
512
|
+
|
|
513
|
+
# Lint each file and aggregate results
|
|
514
|
+
all_violations: list[ModelContractViolation] = []
|
|
515
|
+
files_valid = 0
|
|
516
|
+
files_with_errors = 0
|
|
517
|
+
|
|
518
|
+
for contract_file in sorted(contract_files):
|
|
519
|
+
result = self.lint_file(contract_file)
|
|
520
|
+
all_violations.extend(result.violations)
|
|
521
|
+
files_valid += result.files_valid
|
|
522
|
+
files_with_errors += result.files_with_errors
|
|
523
|
+
|
|
524
|
+
has_errors = any(
|
|
525
|
+
v.severity == EnumContractViolationSeverity.ERROR for v in all_violations
|
|
526
|
+
)
|
|
527
|
+
if self.strict_mode:
|
|
528
|
+
has_errors = has_errors or any(
|
|
529
|
+
v.severity == EnumContractViolationSeverity.WARNING
|
|
530
|
+
for v in all_violations
|
|
531
|
+
)
|
|
532
|
+
|
|
533
|
+
return ModelContractLintResult(
|
|
534
|
+
is_valid=not has_errors,
|
|
535
|
+
violations=all_violations,
|
|
536
|
+
files_checked=len(contract_files),
|
|
537
|
+
files_valid=files_valid,
|
|
538
|
+
files_with_errors=files_with_errors,
|
|
539
|
+
)
|
|
540
|
+
|
|
541
|
+
def _validate_required_fields(
|
|
542
|
+
self,
|
|
543
|
+
file_path: str,
|
|
544
|
+
content: dict,
|
|
545
|
+
) -> list[ModelContractViolation]:
|
|
546
|
+
"""Validate that all required top-level fields are present."""
|
|
547
|
+
violations: list[ModelContractViolation] = []
|
|
548
|
+
required_fields = [
|
|
549
|
+
"name",
|
|
550
|
+
"node_type",
|
|
551
|
+
"contract_version",
|
|
552
|
+
"input_model",
|
|
553
|
+
"output_model",
|
|
554
|
+
]
|
|
555
|
+
|
|
556
|
+
for field in required_fields:
|
|
557
|
+
if field not in content:
|
|
558
|
+
violations.append(
|
|
559
|
+
ModelContractViolation(
|
|
560
|
+
file_path=file_path,
|
|
561
|
+
field_path=field,
|
|
562
|
+
message=f"Required field '{field}' is missing",
|
|
563
|
+
severity=EnumContractViolationSeverity.ERROR,
|
|
564
|
+
suggestion=f"Add '{field}:' to your contract.yaml",
|
|
565
|
+
)
|
|
566
|
+
)
|
|
567
|
+
|
|
568
|
+
return violations
|
|
569
|
+
|
|
570
|
+
def _validate_node_type(
|
|
571
|
+
self,
|
|
572
|
+
file_path: str,
|
|
573
|
+
content: dict,
|
|
574
|
+
) -> list[ModelContractViolation]:
|
|
575
|
+
"""Validate node_type is one of the valid ONEX 4-node types."""
|
|
576
|
+
violations: list[ModelContractViolation] = []
|
|
577
|
+
node_type = content.get("node_type")
|
|
578
|
+
|
|
579
|
+
if node_type is None:
|
|
580
|
+
return violations # Already caught by required fields check
|
|
581
|
+
|
|
582
|
+
if not isinstance(node_type, str):
|
|
583
|
+
violations.append(
|
|
584
|
+
ModelContractViolation(
|
|
585
|
+
file_path=file_path,
|
|
586
|
+
field_path="node_type",
|
|
587
|
+
message=f"node_type must be a string, got {type(node_type).__name__}",
|
|
588
|
+
severity=EnumContractViolationSeverity.ERROR,
|
|
589
|
+
)
|
|
590
|
+
)
|
|
591
|
+
return violations
|
|
592
|
+
|
|
593
|
+
if node_type not in VALID_NODE_TYPES:
|
|
594
|
+
violations.append(
|
|
595
|
+
ModelContractViolation(
|
|
596
|
+
file_path=file_path,
|
|
597
|
+
field_path="node_type",
|
|
598
|
+
message=f"Invalid node_type '{node_type}'. Must be one of: {', '.join(sorted(VALID_NODE_TYPES))}",
|
|
599
|
+
severity=EnumContractViolationSeverity.ERROR,
|
|
600
|
+
suggestion=f"Change node_type to one of: {', '.join(sorted(VALID_NODE_TYPES))}",
|
|
601
|
+
)
|
|
602
|
+
)
|
|
603
|
+
|
|
604
|
+
return violations
|
|
605
|
+
|
|
606
|
+
def _validate_contract_version(
|
|
607
|
+
self,
|
|
608
|
+
file_path: str,
|
|
609
|
+
content: dict,
|
|
610
|
+
) -> list[ModelContractViolation]:
|
|
611
|
+
"""Validate contract_version has proper semver structure."""
|
|
612
|
+
violations: list[ModelContractViolation] = []
|
|
613
|
+
version = content.get("contract_version")
|
|
614
|
+
|
|
615
|
+
if version is None:
|
|
616
|
+
return violations # Already caught by required fields check
|
|
617
|
+
|
|
618
|
+
if not isinstance(version, dict):
|
|
619
|
+
violations.append(
|
|
620
|
+
ModelContractViolation(
|
|
621
|
+
file_path=file_path,
|
|
622
|
+
field_path="contract_version",
|
|
623
|
+
message="contract_version must be a dict with 'major', 'minor', 'patch' keys",
|
|
624
|
+
severity=EnumContractViolationSeverity.ERROR,
|
|
625
|
+
suggestion="Use format: contract_version:\\n major: 1\\n minor: 0\\n patch: 0",
|
|
626
|
+
)
|
|
627
|
+
)
|
|
628
|
+
return violations
|
|
629
|
+
|
|
630
|
+
for key in ["major", "minor", "patch"]:
|
|
631
|
+
if key not in version:
|
|
632
|
+
violations.append(
|
|
633
|
+
ModelContractViolation(
|
|
634
|
+
file_path=file_path,
|
|
635
|
+
field_path=f"contract_version.{key}",
|
|
636
|
+
message=f"contract_version missing required field '{key}'",
|
|
637
|
+
severity=EnumContractViolationSeverity.ERROR,
|
|
638
|
+
)
|
|
639
|
+
)
|
|
640
|
+
elif not isinstance(version[key], int):
|
|
641
|
+
violations.append(
|
|
642
|
+
ModelContractViolation(
|
|
643
|
+
file_path=file_path,
|
|
644
|
+
field_path=f"contract_version.{key}",
|
|
645
|
+
message=f"contract_version.{key} must be an integer, got {type(version[key]).__name__}",
|
|
646
|
+
severity=EnumContractViolationSeverity.ERROR,
|
|
647
|
+
)
|
|
648
|
+
)
|
|
649
|
+
elif version[key] < 0:
|
|
650
|
+
violations.append(
|
|
651
|
+
ModelContractViolation(
|
|
652
|
+
file_path=file_path,
|
|
653
|
+
field_path=f"contract_version.{key}",
|
|
654
|
+
message=f"contract_version.{key} must be non-negative, got {version[key]}",
|
|
655
|
+
severity=EnumContractViolationSeverity.ERROR,
|
|
656
|
+
)
|
|
657
|
+
)
|
|
658
|
+
|
|
659
|
+
return violations
|
|
660
|
+
|
|
661
|
+
def _validate_model_reference(
|
|
662
|
+
self,
|
|
663
|
+
file_path: str,
|
|
664
|
+
content: dict,
|
|
665
|
+
field_name: Literal["input_model", "output_model"],
|
|
666
|
+
) -> list[ModelContractViolation]:
|
|
667
|
+
"""Validate input_model or output_model reference structure and importability."""
|
|
668
|
+
violations: list[ModelContractViolation] = []
|
|
669
|
+
model_ref = content.get(field_name)
|
|
670
|
+
|
|
671
|
+
if model_ref is None:
|
|
672
|
+
return violations # Already caught by required fields check
|
|
673
|
+
|
|
674
|
+
if not isinstance(model_ref, dict):
|
|
675
|
+
violations.append(
|
|
676
|
+
ModelContractViolation(
|
|
677
|
+
file_path=file_path,
|
|
678
|
+
field_path=field_name,
|
|
679
|
+
message=f"{field_name} must be a dict with 'name' and 'module' keys",
|
|
680
|
+
severity=EnumContractViolationSeverity.ERROR,
|
|
681
|
+
suggestion=f"Use format: {field_name}:\\n name: ModelName\\n module: package.module",
|
|
682
|
+
)
|
|
683
|
+
)
|
|
684
|
+
return violations
|
|
685
|
+
|
|
686
|
+
# Check required sub-fields
|
|
687
|
+
for key in ["name", "module"]:
|
|
688
|
+
if key not in model_ref:
|
|
689
|
+
violations.append(
|
|
690
|
+
ModelContractViolation(
|
|
691
|
+
file_path=file_path,
|
|
692
|
+
field_path=f"{field_name}.{key}",
|
|
693
|
+
message=f"{field_name} missing required field '{key}'",
|
|
694
|
+
severity=EnumContractViolationSeverity.ERROR,
|
|
695
|
+
)
|
|
696
|
+
)
|
|
697
|
+
elif not isinstance(model_ref[key], str):
|
|
698
|
+
violations.append(
|
|
699
|
+
ModelContractViolation(
|
|
700
|
+
file_path=file_path,
|
|
701
|
+
field_path=f"{field_name}.{key}",
|
|
702
|
+
message=f"{field_name}.{key} must be a string",
|
|
703
|
+
severity=EnumContractViolationSeverity.ERROR,
|
|
704
|
+
)
|
|
705
|
+
)
|
|
706
|
+
|
|
707
|
+
# Validate model name follows ONEX naming convention (Model* prefix)
|
|
708
|
+
model_name = model_ref.get("name")
|
|
709
|
+
if isinstance(model_name, str) and not model_name.startswith("Model"):
|
|
710
|
+
violations.append(
|
|
711
|
+
ModelContractViolation(
|
|
712
|
+
file_path=file_path,
|
|
713
|
+
field_path=f"{field_name}.name",
|
|
714
|
+
message=f"{field_name}.name should start with 'Model' prefix per ONEX conventions",
|
|
715
|
+
severity=EnumContractViolationSeverity.WARNING,
|
|
716
|
+
suggestion=f"Rename to 'Model{model_name}'",
|
|
717
|
+
)
|
|
718
|
+
)
|
|
719
|
+
|
|
720
|
+
# Check if module is importable (optional, can be slow)
|
|
721
|
+
if self.check_imports:
|
|
722
|
+
violations.extend(
|
|
723
|
+
self._check_module_importable(file_path, field_name, model_ref)
|
|
724
|
+
)
|
|
725
|
+
|
|
726
|
+
return violations
|
|
727
|
+
|
|
728
|
+
def _check_module_importable(
|
|
729
|
+
self,
|
|
730
|
+
file_path: str,
|
|
731
|
+
field_name: str,
|
|
732
|
+
model_ref: dict,
|
|
733
|
+
) -> list[ModelContractViolation]:
|
|
734
|
+
"""Check if the model's module is importable."""
|
|
735
|
+
violations: list[ModelContractViolation] = []
|
|
736
|
+
module_name = model_ref.get("module")
|
|
737
|
+
class_name = model_ref.get("name")
|
|
738
|
+
|
|
739
|
+
if not isinstance(module_name, str) or not isinstance(class_name, str):
|
|
740
|
+
return violations # Type errors already reported
|
|
741
|
+
|
|
742
|
+
try:
|
|
743
|
+
module = importlib.import_module(module_name)
|
|
744
|
+
if not hasattr(module, class_name):
|
|
745
|
+
violations.append(
|
|
746
|
+
ModelContractViolation(
|
|
747
|
+
file_path=file_path,
|
|
748
|
+
field_path=f"{field_name}.name",
|
|
749
|
+
message=f"Class '{class_name}' not found in module '{module_name}'",
|
|
750
|
+
severity=EnumContractViolationSeverity.ERROR,
|
|
751
|
+
suggestion=f"Verify the class name exists in {module_name}",
|
|
752
|
+
)
|
|
753
|
+
)
|
|
754
|
+
except ImportError as e:
|
|
755
|
+
# Import failures are ERROR severity because they violate the type
|
|
756
|
+
# consistency guarantee documented in the module docstring: contracts
|
|
757
|
+
# must reference importable modules to ensure type safety.
|
|
758
|
+
# Use check_imports=False to skip this check in environments where
|
|
759
|
+
# dependencies may not be available.
|
|
760
|
+
violations.append(
|
|
761
|
+
ModelContractViolation(
|
|
762
|
+
file_path=file_path,
|
|
763
|
+
field_path=f"{field_name}.module",
|
|
764
|
+
message=f"Cannot import module '{module_name}': {e}",
|
|
765
|
+
severity=EnumContractViolationSeverity.ERROR,
|
|
766
|
+
suggestion="Verify module path and ensure it's installed, or use check_imports=False",
|
|
767
|
+
)
|
|
768
|
+
)
|
|
769
|
+
|
|
770
|
+
return violations
|
|
771
|
+
|
|
772
|
+
def _validate_name_convention(
|
|
773
|
+
self,
|
|
774
|
+
file_path: str,
|
|
775
|
+
content: dict,
|
|
776
|
+
) -> list[ModelContractViolation]:
|
|
777
|
+
"""Validate name follows snake_case convention."""
|
|
778
|
+
violations: list[ModelContractViolation] = []
|
|
779
|
+
name = content.get("name")
|
|
780
|
+
|
|
781
|
+
if name is None or not isinstance(name, str):
|
|
782
|
+
return violations # Already caught by required fields check
|
|
783
|
+
|
|
784
|
+
# Check snake_case pattern
|
|
785
|
+
if not re.match(r"^[a-z][a-z0-9_]*$", name):
|
|
786
|
+
violations.append(
|
|
787
|
+
ModelContractViolation(
|
|
788
|
+
file_path=file_path,
|
|
789
|
+
field_path="name",
|
|
790
|
+
message=f"Node name '{name}' should be snake_case (lowercase with underscores)",
|
|
791
|
+
severity=EnumContractViolationSeverity.WARNING,
|
|
792
|
+
suggestion="Use snake_case: e.g., 'node_registration_orchestrator'",
|
|
793
|
+
)
|
|
794
|
+
)
|
|
795
|
+
|
|
796
|
+
return violations
|
|
797
|
+
|
|
798
|
+
def _check_recommended_fields(
|
|
799
|
+
self,
|
|
800
|
+
file_path: str,
|
|
801
|
+
content: dict,
|
|
802
|
+
) -> list[ModelContractViolation]:
|
|
803
|
+
"""Check for recommended but optional fields."""
|
|
804
|
+
violations: list[ModelContractViolation] = []
|
|
805
|
+
recommended_fields = ["description", "node_version"]
|
|
806
|
+
|
|
807
|
+
for field in recommended_fields:
|
|
808
|
+
if field not in content:
|
|
809
|
+
violations.append(
|
|
810
|
+
ModelContractViolation(
|
|
811
|
+
file_path=file_path,
|
|
812
|
+
field_path=field,
|
|
813
|
+
message=f"Recommended field '{field}' is missing",
|
|
814
|
+
severity=EnumContractViolationSeverity.INFO,
|
|
815
|
+
suggestion=f"Consider adding '{field}:' for better documentation",
|
|
816
|
+
)
|
|
817
|
+
)
|
|
818
|
+
|
|
819
|
+
return violations
|
|
820
|
+
|
|
821
|
+
|
|
822
|
+
def lint_contract_file(
|
|
823
|
+
file_path: PathInput,
|
|
824
|
+
*,
|
|
825
|
+
check_imports: bool = True,
|
|
826
|
+
strict_mode: bool = False,
|
|
827
|
+
) -> ModelContractLintResult:
|
|
828
|
+
"""
|
|
829
|
+
Lint a single contract.yaml file.
|
|
830
|
+
|
|
831
|
+
Convenience function that creates a ContractLinter and lints the file.
|
|
832
|
+
|
|
833
|
+
Args:
|
|
834
|
+
file_path: Path to the contract.yaml file.
|
|
835
|
+
check_imports: Whether to verify model modules are importable.
|
|
836
|
+
strict_mode: If True, treat warnings as errors.
|
|
837
|
+
|
|
838
|
+
Returns:
|
|
839
|
+
ModelContractLintResult with violations found.
|
|
840
|
+
"""
|
|
841
|
+
linter = ContractLinter(check_imports=check_imports, strict_mode=strict_mode)
|
|
842
|
+
return linter.lint_file(Path(file_path))
|
|
843
|
+
|
|
844
|
+
|
|
845
|
+
def lint_contracts_in_directory(
|
|
846
|
+
directory: PathInput,
|
|
847
|
+
*,
|
|
848
|
+
recursive: bool = True,
|
|
849
|
+
check_imports: bool = True,
|
|
850
|
+
strict_mode: bool = False,
|
|
851
|
+
) -> ModelContractLintResult:
|
|
852
|
+
"""
|
|
853
|
+
Lint all contract.yaml files in a directory.
|
|
854
|
+
|
|
855
|
+
Convenience function that creates a ContractLinter and lints the directory.
|
|
856
|
+
|
|
857
|
+
Args:
|
|
858
|
+
directory: Directory to search for contract.yaml files.
|
|
859
|
+
recursive: Whether to search subdirectories.
|
|
860
|
+
check_imports: Whether to verify model modules are importable.
|
|
861
|
+
strict_mode: If True, treat warnings as errors.
|
|
862
|
+
|
|
863
|
+
Returns:
|
|
864
|
+
ModelContractLintResult with aggregated violations.
|
|
865
|
+
"""
|
|
866
|
+
linter = ContractLinter(check_imports=check_imports, strict_mode=strict_mode)
|
|
867
|
+
return linter.lint_directory(Path(directory), recursive=recursive)
|
|
868
|
+
|
|
869
|
+
|
|
870
|
+
def lint_contracts_ci(
|
|
871
|
+
directory: PathInput = "src/omnibase_infra/nodes/",
|
|
872
|
+
*,
|
|
873
|
+
check_imports: bool = True,
|
|
874
|
+
strict_mode: bool = False,
|
|
875
|
+
verbose: bool = False,
|
|
876
|
+
) -> tuple[bool, ModelContractLintResult]:
|
|
877
|
+
"""
|
|
878
|
+
Lint contracts with CI-friendly output.
|
|
879
|
+
|
|
880
|
+
Returns a tuple of (success, result) for easy integration with CI scripts.
|
|
881
|
+
Prints violations to stdout for CI visibility.
|
|
882
|
+
|
|
883
|
+
Args:
|
|
884
|
+
directory: Directory to lint.
|
|
885
|
+
check_imports: Whether to verify model modules are importable.
|
|
886
|
+
strict_mode: If True, treat warnings as errors.
|
|
887
|
+
verbose: If True, print all violations including INFO level.
|
|
888
|
+
|
|
889
|
+
Returns:
|
|
890
|
+
Tuple of (success: bool, result: ModelContractLintResult).
|
|
891
|
+
success is True if no errors found (and no warnings if strict_mode).
|
|
892
|
+
"""
|
|
893
|
+
result = lint_contracts_in_directory(
|
|
894
|
+
directory,
|
|
895
|
+
check_imports=check_imports,
|
|
896
|
+
strict_mode=strict_mode,
|
|
897
|
+
)
|
|
898
|
+
|
|
899
|
+
# Print summary
|
|
900
|
+
print(str(result))
|
|
901
|
+
|
|
902
|
+
# Print violations
|
|
903
|
+
for violation in result.violations:
|
|
904
|
+
if verbose or violation.severity != EnumContractViolationSeverity.INFO:
|
|
905
|
+
print(f" {violation}")
|
|
906
|
+
|
|
907
|
+
return result.is_valid, result
|