omnibase_infra 0.2.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (675) hide show
  1. omnibase_infra/__init__.py +101 -0
  2. omnibase_infra/cli/__init__.py +1 -0
  3. omnibase_infra/cli/commands.py +216 -0
  4. omnibase_infra/clients/__init__.py +0 -0
  5. omnibase_infra/contracts/handlers/filesystem/handler_contract.yaml +261 -0
  6. omnibase_infra/contracts/handlers/mcp/handler_contract.yaml +138 -0
  7. omnibase_infra/decorators/__init__.py +29 -0
  8. omnibase_infra/decorators/allow_any.py +109 -0
  9. omnibase_infra/dlq/__init__.py +90 -0
  10. omnibase_infra/dlq/constants_dlq.py +57 -0
  11. omnibase_infra/dlq/models/__init__.py +26 -0
  12. omnibase_infra/dlq/models/enum_replay_status.py +37 -0
  13. omnibase_infra/dlq/models/model_dlq_replay_record.py +135 -0
  14. omnibase_infra/dlq/models/model_dlq_tracking_config.py +184 -0
  15. omnibase_infra/dlq/service_dlq_tracking.py +611 -0
  16. omnibase_infra/enums/__init__.py +123 -0
  17. omnibase_infra/enums/enum_any_type_violation.py +104 -0
  18. omnibase_infra/enums/enum_backend_type.py +27 -0
  19. omnibase_infra/enums/enum_capture_outcome.py +42 -0
  20. omnibase_infra/enums/enum_capture_state.py +88 -0
  21. omnibase_infra/enums/enum_chain_violation_type.py +119 -0
  22. omnibase_infra/enums/enum_circuit_state.py +51 -0
  23. omnibase_infra/enums/enum_confirmation_event_type.py +27 -0
  24. omnibase_infra/enums/enum_contract_type.py +84 -0
  25. omnibase_infra/enums/enum_dedupe_strategy.py +46 -0
  26. omnibase_infra/enums/enum_dispatch_status.py +191 -0
  27. omnibase_infra/enums/enum_environment.py +46 -0
  28. omnibase_infra/enums/enum_execution_shape_violation.py +103 -0
  29. omnibase_infra/enums/enum_handler_error_type.py +101 -0
  30. omnibase_infra/enums/enum_handler_loader_error.py +178 -0
  31. omnibase_infra/enums/enum_handler_source_type.py +87 -0
  32. omnibase_infra/enums/enum_handler_type.py +77 -0
  33. omnibase_infra/enums/enum_handler_type_category.py +61 -0
  34. omnibase_infra/enums/enum_infra_transport_type.py +73 -0
  35. omnibase_infra/enums/enum_introspection_reason.py +154 -0
  36. omnibase_infra/enums/enum_message_category.py +213 -0
  37. omnibase_infra/enums/enum_node_archetype.py +74 -0
  38. omnibase_infra/enums/enum_node_output_type.py +185 -0
  39. omnibase_infra/enums/enum_non_retryable_error_category.py +224 -0
  40. omnibase_infra/enums/enum_policy_type.py +32 -0
  41. omnibase_infra/enums/enum_registration_state.py +261 -0
  42. omnibase_infra/enums/enum_registration_status.py +33 -0
  43. omnibase_infra/enums/enum_registry_response_status.py +28 -0
  44. omnibase_infra/enums/enum_response_status.py +26 -0
  45. omnibase_infra/enums/enum_retry_error_category.py +98 -0
  46. omnibase_infra/enums/enum_security_rule_id.py +103 -0
  47. omnibase_infra/enums/enum_selection_strategy.py +91 -0
  48. omnibase_infra/enums/enum_topic_standard.py +42 -0
  49. omnibase_infra/enums/enum_validation_severity.py +78 -0
  50. omnibase_infra/errors/__init__.py +156 -0
  51. omnibase_infra/errors/error_architecture_violation.py +152 -0
  52. omnibase_infra/errors/error_chain_propagation.py +188 -0
  53. omnibase_infra/errors/error_compute_registry.py +92 -0
  54. omnibase_infra/errors/error_consul.py +132 -0
  55. omnibase_infra/errors/error_container_wiring.py +243 -0
  56. omnibase_infra/errors/error_event_bus_registry.py +102 -0
  57. omnibase_infra/errors/error_infra.py +608 -0
  58. omnibase_infra/errors/error_message_type_registry.py +101 -0
  59. omnibase_infra/errors/error_policy_registry.py +112 -0
  60. omnibase_infra/errors/error_vault.py +123 -0
  61. omnibase_infra/event_bus/__init__.py +72 -0
  62. omnibase_infra/event_bus/configs/kafka_event_bus_config.yaml +86 -0
  63. omnibase_infra/event_bus/event_bus_inmemory.py +743 -0
  64. omnibase_infra/event_bus/event_bus_kafka.py +1658 -0
  65. omnibase_infra/event_bus/mixin_kafka_broadcast.py +184 -0
  66. omnibase_infra/event_bus/mixin_kafka_dlq.py +765 -0
  67. omnibase_infra/event_bus/models/__init__.py +29 -0
  68. omnibase_infra/event_bus/models/config/__init__.py +20 -0
  69. omnibase_infra/event_bus/models/config/model_kafka_event_bus_config.py +725 -0
  70. omnibase_infra/event_bus/models/model_dlq_event.py +206 -0
  71. omnibase_infra/event_bus/models/model_dlq_metrics.py +304 -0
  72. omnibase_infra/event_bus/models/model_event_headers.py +115 -0
  73. omnibase_infra/event_bus/models/model_event_message.py +60 -0
  74. omnibase_infra/event_bus/topic_constants.py +376 -0
  75. omnibase_infra/handlers/__init__.py +75 -0
  76. omnibase_infra/handlers/filesystem/__init__.py +48 -0
  77. omnibase_infra/handlers/filesystem/enum_file_system_operation.py +35 -0
  78. omnibase_infra/handlers/filesystem/model_file_system_request.py +298 -0
  79. omnibase_infra/handlers/filesystem/model_file_system_result.py +166 -0
  80. omnibase_infra/handlers/handler_consul.py +787 -0
  81. omnibase_infra/handlers/handler_db.py +1039 -0
  82. omnibase_infra/handlers/handler_filesystem.py +1478 -0
  83. omnibase_infra/handlers/handler_graph.py +1154 -0
  84. omnibase_infra/handlers/handler_http.py +920 -0
  85. omnibase_infra/handlers/handler_manifest_persistence.contract.yaml +184 -0
  86. omnibase_infra/handlers/handler_manifest_persistence.py +1539 -0
  87. omnibase_infra/handlers/handler_mcp.py +748 -0
  88. omnibase_infra/handlers/handler_qdrant.py +1076 -0
  89. omnibase_infra/handlers/handler_vault.py +422 -0
  90. omnibase_infra/handlers/mcp/__init__.py +19 -0
  91. omnibase_infra/handlers/mcp/adapter_onex_to_mcp.py +446 -0
  92. omnibase_infra/handlers/mcp/protocols.py +178 -0
  93. omnibase_infra/handlers/mcp/transport_streamable_http.py +352 -0
  94. omnibase_infra/handlers/mixins/__init__.py +42 -0
  95. omnibase_infra/handlers/mixins/mixin_consul_initialization.py +349 -0
  96. omnibase_infra/handlers/mixins/mixin_consul_kv.py +337 -0
  97. omnibase_infra/handlers/mixins/mixin_consul_service.py +277 -0
  98. omnibase_infra/handlers/mixins/mixin_vault_initialization.py +338 -0
  99. omnibase_infra/handlers/mixins/mixin_vault_retry.py +412 -0
  100. omnibase_infra/handlers/mixins/mixin_vault_secrets.py +450 -0
  101. omnibase_infra/handlers/mixins/mixin_vault_token.py +365 -0
  102. omnibase_infra/handlers/models/__init__.py +286 -0
  103. omnibase_infra/handlers/models/consul/__init__.py +81 -0
  104. omnibase_infra/handlers/models/consul/enum_consul_operation_type.py +57 -0
  105. omnibase_infra/handlers/models/consul/model_consul_deregister_payload.py +51 -0
  106. omnibase_infra/handlers/models/consul/model_consul_handler_config.py +153 -0
  107. omnibase_infra/handlers/models/consul/model_consul_handler_payload.py +89 -0
  108. omnibase_infra/handlers/models/consul/model_consul_kv_get_found_payload.py +55 -0
  109. omnibase_infra/handlers/models/consul/model_consul_kv_get_not_found_payload.py +49 -0
  110. omnibase_infra/handlers/models/consul/model_consul_kv_get_recurse_payload.py +50 -0
  111. omnibase_infra/handlers/models/consul/model_consul_kv_item.py +33 -0
  112. omnibase_infra/handlers/models/consul/model_consul_kv_put_payload.py +41 -0
  113. omnibase_infra/handlers/models/consul/model_consul_register_payload.py +53 -0
  114. omnibase_infra/handlers/models/consul/model_consul_retry_config.py +66 -0
  115. omnibase_infra/handlers/models/consul/model_payload_consul.py +66 -0
  116. omnibase_infra/handlers/models/consul/registry_payload_consul.py +214 -0
  117. omnibase_infra/handlers/models/graph/__init__.py +35 -0
  118. omnibase_infra/handlers/models/graph/enum_graph_operation_type.py +20 -0
  119. omnibase_infra/handlers/models/graph/model_graph_execute_payload.py +38 -0
  120. omnibase_infra/handlers/models/graph/model_graph_handler_config.py +54 -0
  121. omnibase_infra/handlers/models/graph/model_graph_handler_payload.py +44 -0
  122. omnibase_infra/handlers/models/graph/model_graph_query_payload.py +40 -0
  123. omnibase_infra/handlers/models/graph/model_graph_record.py +22 -0
  124. omnibase_infra/handlers/models/http/__init__.py +50 -0
  125. omnibase_infra/handlers/models/http/enum_http_operation_type.py +29 -0
  126. omnibase_infra/handlers/models/http/model_http_body_content.py +45 -0
  127. omnibase_infra/handlers/models/http/model_http_get_payload.py +88 -0
  128. omnibase_infra/handlers/models/http/model_http_handler_payload.py +90 -0
  129. omnibase_infra/handlers/models/http/model_http_post_payload.py +88 -0
  130. omnibase_infra/handlers/models/http/model_payload_http.py +66 -0
  131. omnibase_infra/handlers/models/http/registry_payload_http.py +212 -0
  132. omnibase_infra/handlers/models/mcp/__init__.py +23 -0
  133. omnibase_infra/handlers/models/mcp/enum_mcp_operation_type.py +24 -0
  134. omnibase_infra/handlers/models/mcp/model_mcp_handler_config.py +40 -0
  135. omnibase_infra/handlers/models/mcp/model_mcp_tool_call.py +32 -0
  136. omnibase_infra/handlers/models/mcp/model_mcp_tool_result.py +45 -0
  137. omnibase_infra/handlers/models/model_consul_handler_response.py +96 -0
  138. omnibase_infra/handlers/models/model_db_describe_response.py +83 -0
  139. omnibase_infra/handlers/models/model_db_query_payload.py +95 -0
  140. omnibase_infra/handlers/models/model_db_query_response.py +60 -0
  141. omnibase_infra/handlers/models/model_filesystem_config.py +98 -0
  142. omnibase_infra/handlers/models/model_filesystem_delete_payload.py +54 -0
  143. omnibase_infra/handlers/models/model_filesystem_delete_result.py +77 -0
  144. omnibase_infra/handlers/models/model_filesystem_directory_entry.py +75 -0
  145. omnibase_infra/handlers/models/model_filesystem_ensure_directory_payload.py +54 -0
  146. omnibase_infra/handlers/models/model_filesystem_ensure_directory_result.py +60 -0
  147. omnibase_infra/handlers/models/model_filesystem_list_directory_payload.py +60 -0
  148. omnibase_infra/handlers/models/model_filesystem_list_directory_result.py +68 -0
  149. omnibase_infra/handlers/models/model_filesystem_read_payload.py +62 -0
  150. omnibase_infra/handlers/models/model_filesystem_read_result.py +61 -0
  151. omnibase_infra/handlers/models/model_filesystem_write_payload.py +70 -0
  152. omnibase_infra/handlers/models/model_filesystem_write_result.py +55 -0
  153. omnibase_infra/handlers/models/model_graph_handler_response.py +98 -0
  154. omnibase_infra/handlers/models/model_handler_response.py +103 -0
  155. omnibase_infra/handlers/models/model_http_handler_response.py +101 -0
  156. omnibase_infra/handlers/models/model_manifest_metadata.py +75 -0
  157. omnibase_infra/handlers/models/model_manifest_persistence_config.py +62 -0
  158. omnibase_infra/handlers/models/model_manifest_query_payload.py +90 -0
  159. omnibase_infra/handlers/models/model_manifest_query_result.py +97 -0
  160. omnibase_infra/handlers/models/model_manifest_retrieve_payload.py +44 -0
  161. omnibase_infra/handlers/models/model_manifest_retrieve_result.py +98 -0
  162. omnibase_infra/handlers/models/model_manifest_store_payload.py +47 -0
  163. omnibase_infra/handlers/models/model_manifest_store_result.py +67 -0
  164. omnibase_infra/handlers/models/model_operation_context.py +187 -0
  165. omnibase_infra/handlers/models/model_qdrant_handler_response.py +98 -0
  166. omnibase_infra/handlers/models/model_retry_state.py +162 -0
  167. omnibase_infra/handlers/models/model_vault_handler_response.py +98 -0
  168. omnibase_infra/handlers/models/qdrant/__init__.py +44 -0
  169. omnibase_infra/handlers/models/qdrant/enum_qdrant_operation_type.py +26 -0
  170. omnibase_infra/handlers/models/qdrant/model_qdrant_collection_payload.py +42 -0
  171. omnibase_infra/handlers/models/qdrant/model_qdrant_delete_payload.py +36 -0
  172. omnibase_infra/handlers/models/qdrant/model_qdrant_handler_config.py +42 -0
  173. omnibase_infra/handlers/models/qdrant/model_qdrant_handler_payload.py +54 -0
  174. omnibase_infra/handlers/models/qdrant/model_qdrant_search_payload.py +42 -0
  175. omnibase_infra/handlers/models/qdrant/model_qdrant_search_result.py +30 -0
  176. omnibase_infra/handlers/models/qdrant/model_qdrant_upsert_payload.py +36 -0
  177. omnibase_infra/handlers/models/vault/__init__.py +69 -0
  178. omnibase_infra/handlers/models/vault/enum_vault_operation_type.py +35 -0
  179. omnibase_infra/handlers/models/vault/model_payload_vault.py +66 -0
  180. omnibase_infra/handlers/models/vault/model_vault_delete_payload.py +57 -0
  181. omnibase_infra/handlers/models/vault/model_vault_handler_config.py +148 -0
  182. omnibase_infra/handlers/models/vault/model_vault_handler_payload.py +101 -0
  183. omnibase_infra/handlers/models/vault/model_vault_list_payload.py +58 -0
  184. omnibase_infra/handlers/models/vault/model_vault_renew_token_payload.py +67 -0
  185. omnibase_infra/handlers/models/vault/model_vault_retry_config.py +66 -0
  186. omnibase_infra/handlers/models/vault/model_vault_secret_payload.py +106 -0
  187. omnibase_infra/handlers/models/vault/model_vault_write_payload.py +66 -0
  188. omnibase_infra/handlers/models/vault/registry_payload_vault.py +213 -0
  189. omnibase_infra/handlers/registration_storage/__init__.py +43 -0
  190. omnibase_infra/handlers/registration_storage/handler_registration_storage_mock.py +392 -0
  191. omnibase_infra/handlers/registration_storage/handler_registration_storage_postgres.py +915 -0
  192. omnibase_infra/handlers/registration_storage/models/__init__.py +23 -0
  193. omnibase_infra/handlers/registration_storage/models/model_delete_registration_request.py +58 -0
  194. omnibase_infra/handlers/registration_storage/models/model_update_registration_request.py +73 -0
  195. omnibase_infra/handlers/registration_storage/protocol_registration_persistence.py +191 -0
  196. omnibase_infra/handlers/service_discovery/__init__.py +43 -0
  197. omnibase_infra/handlers/service_discovery/handler_service_discovery_consul.py +747 -0
  198. omnibase_infra/handlers/service_discovery/handler_service_discovery_mock.py +258 -0
  199. omnibase_infra/handlers/service_discovery/models/__init__.py +22 -0
  200. omnibase_infra/handlers/service_discovery/models/model_discovery_result.py +64 -0
  201. omnibase_infra/handlers/service_discovery/models/model_registration_result.py +138 -0
  202. omnibase_infra/handlers/service_discovery/models/model_service_info.py +99 -0
  203. omnibase_infra/handlers/service_discovery/protocol_discovery_operations.py +170 -0
  204. omnibase_infra/idempotency/__init__.py +94 -0
  205. omnibase_infra/idempotency/models/__init__.py +43 -0
  206. omnibase_infra/idempotency/models/model_idempotency_check_result.py +85 -0
  207. omnibase_infra/idempotency/models/model_idempotency_guard_config.py +130 -0
  208. omnibase_infra/idempotency/models/model_idempotency_record.py +86 -0
  209. omnibase_infra/idempotency/models/model_idempotency_store_health_check_result.py +81 -0
  210. omnibase_infra/idempotency/models/model_idempotency_store_metrics.py +140 -0
  211. omnibase_infra/idempotency/models/model_postgres_idempotency_store_config.py +299 -0
  212. omnibase_infra/idempotency/protocol_idempotency_store.py +184 -0
  213. omnibase_infra/idempotency/store_inmemory.py +265 -0
  214. omnibase_infra/idempotency/store_postgres.py +923 -0
  215. omnibase_infra/infrastructure/__init__.py +0 -0
  216. omnibase_infra/mixins/__init__.py +71 -0
  217. omnibase_infra/mixins/mixin_async_circuit_breaker.py +655 -0
  218. omnibase_infra/mixins/mixin_dict_like_accessors.py +146 -0
  219. omnibase_infra/mixins/mixin_envelope_extraction.py +119 -0
  220. omnibase_infra/mixins/mixin_node_introspection.py +2465 -0
  221. omnibase_infra/mixins/mixin_retry_execution.py +386 -0
  222. omnibase_infra/mixins/protocol_circuit_breaker_aware.py +133 -0
  223. omnibase_infra/models/__init__.py +136 -0
  224. omnibase_infra/models/corpus/__init__.py +17 -0
  225. omnibase_infra/models/corpus/model_capture_config.py +133 -0
  226. omnibase_infra/models/corpus/model_capture_result.py +86 -0
  227. omnibase_infra/models/discovery/__init__.py +42 -0
  228. omnibase_infra/models/discovery/model_dependency_spec.py +319 -0
  229. omnibase_infra/models/discovery/model_discovered_capabilities.py +50 -0
  230. omnibase_infra/models/discovery/model_introspection_config.py +311 -0
  231. omnibase_infra/models/discovery/model_introspection_performance_metrics.py +169 -0
  232. omnibase_infra/models/discovery/model_introspection_task_config.py +116 -0
  233. omnibase_infra/models/dispatch/__init__.py +147 -0
  234. omnibase_infra/models/dispatch/model_dispatch_context.py +439 -0
  235. omnibase_infra/models/dispatch/model_dispatch_error.py +336 -0
  236. omnibase_infra/models/dispatch/model_dispatch_log_context.py +400 -0
  237. omnibase_infra/models/dispatch/model_dispatch_metadata.py +228 -0
  238. omnibase_infra/models/dispatch/model_dispatch_metrics.py +496 -0
  239. omnibase_infra/models/dispatch/model_dispatch_outcome.py +317 -0
  240. omnibase_infra/models/dispatch/model_dispatch_outputs.py +231 -0
  241. omnibase_infra/models/dispatch/model_dispatch_result.py +436 -0
  242. omnibase_infra/models/dispatch/model_dispatch_route.py +279 -0
  243. omnibase_infra/models/dispatch/model_dispatcher_metrics.py +275 -0
  244. omnibase_infra/models/dispatch/model_dispatcher_registration.py +352 -0
  245. omnibase_infra/models/dispatch/model_parsed_topic.py +135 -0
  246. omnibase_infra/models/dispatch/model_topic_parser.py +725 -0
  247. omnibase_infra/models/dispatch/model_tracing_context.py +285 -0
  248. omnibase_infra/models/errors/__init__.py +45 -0
  249. omnibase_infra/models/errors/model_handler_validation_error.py +594 -0
  250. omnibase_infra/models/errors/model_infra_error_context.py +99 -0
  251. omnibase_infra/models/errors/model_message_type_registry_error_context.py +71 -0
  252. omnibase_infra/models/errors/model_timeout_error_context.py +110 -0
  253. omnibase_infra/models/handlers/__init__.py +37 -0
  254. omnibase_infra/models/handlers/model_contract_discovery_result.py +80 -0
  255. omnibase_infra/models/handlers/model_handler_descriptor.py +185 -0
  256. omnibase_infra/models/handlers/model_handler_identifier.py +215 -0
  257. omnibase_infra/models/health/__init__.py +9 -0
  258. omnibase_infra/models/health/model_health_check_result.py +40 -0
  259. omnibase_infra/models/lifecycle/__init__.py +39 -0
  260. omnibase_infra/models/logging/__init__.py +51 -0
  261. omnibase_infra/models/logging/model_log_context.py +756 -0
  262. omnibase_infra/models/model_retry_error_classification.py +78 -0
  263. omnibase_infra/models/projection/__init__.py +43 -0
  264. omnibase_infra/models/projection/model_capability_fields.py +112 -0
  265. omnibase_infra/models/projection/model_registration_projection.py +434 -0
  266. omnibase_infra/models/projection/model_registration_snapshot.py +322 -0
  267. omnibase_infra/models/projection/model_sequence_info.py +182 -0
  268. omnibase_infra/models/projection/model_snapshot_topic_config.py +590 -0
  269. omnibase_infra/models/projectors/__init__.py +41 -0
  270. omnibase_infra/models/projectors/model_projector_column.py +289 -0
  271. omnibase_infra/models/projectors/model_projector_discovery_result.py +65 -0
  272. omnibase_infra/models/projectors/model_projector_index.py +270 -0
  273. omnibase_infra/models/projectors/model_projector_schema.py +415 -0
  274. omnibase_infra/models/projectors/model_projector_validation_error.py +63 -0
  275. omnibase_infra/models/projectors/util_sql_identifiers.py +115 -0
  276. omnibase_infra/models/registration/__init__.py +59 -0
  277. omnibase_infra/models/registration/commands/__init__.py +15 -0
  278. omnibase_infra/models/registration/commands/model_node_registration_acked.py +108 -0
  279. omnibase_infra/models/registration/events/__init__.py +56 -0
  280. omnibase_infra/models/registration/events/model_node_became_active.py +103 -0
  281. omnibase_infra/models/registration/events/model_node_liveness_expired.py +103 -0
  282. omnibase_infra/models/registration/events/model_node_registration_accepted.py +98 -0
  283. omnibase_infra/models/registration/events/model_node_registration_ack_received.py +98 -0
  284. omnibase_infra/models/registration/events/model_node_registration_ack_timed_out.py +112 -0
  285. omnibase_infra/models/registration/events/model_node_registration_initiated.py +107 -0
  286. omnibase_infra/models/registration/events/model_node_registration_rejected.py +104 -0
  287. omnibase_infra/models/registration/model_introspection_metrics.py +253 -0
  288. omnibase_infra/models/registration/model_node_capabilities.py +179 -0
  289. omnibase_infra/models/registration/model_node_heartbeat_event.py +126 -0
  290. omnibase_infra/models/registration/model_node_introspection_event.py +175 -0
  291. omnibase_infra/models/registration/model_node_metadata.py +79 -0
  292. omnibase_infra/models/registration/model_node_registration.py +162 -0
  293. omnibase_infra/models/registration/model_node_registration_record.py +162 -0
  294. omnibase_infra/models/registry/__init__.py +29 -0
  295. omnibase_infra/models/registry/model_domain_constraint.py +202 -0
  296. omnibase_infra/models/registry/model_message_type_entry.py +271 -0
  297. omnibase_infra/models/resilience/__init__.py +9 -0
  298. omnibase_infra/models/resilience/model_circuit_breaker_config.py +227 -0
  299. omnibase_infra/models/routing/__init__.py +25 -0
  300. omnibase_infra/models/routing/model_routing_entry.py +52 -0
  301. omnibase_infra/models/routing/model_routing_subcontract.py +70 -0
  302. omnibase_infra/models/runtime/__init__.py +40 -0
  303. omnibase_infra/models/runtime/model_contract_security_config.py +41 -0
  304. omnibase_infra/models/runtime/model_discovery_error.py +81 -0
  305. omnibase_infra/models/runtime/model_discovery_result.py +162 -0
  306. omnibase_infra/models/runtime/model_discovery_warning.py +74 -0
  307. omnibase_infra/models/runtime/model_failed_plugin_load.py +63 -0
  308. omnibase_infra/models/runtime/model_handler_contract.py +280 -0
  309. omnibase_infra/models/runtime/model_loaded_handler.py +120 -0
  310. omnibase_infra/models/runtime/model_plugin_load_context.py +93 -0
  311. omnibase_infra/models/runtime/model_plugin_load_summary.py +124 -0
  312. omnibase_infra/models/security/__init__.py +50 -0
  313. omnibase_infra/models/security/classification_levels.py +99 -0
  314. omnibase_infra/models/security/model_environment_policy.py +145 -0
  315. omnibase_infra/models/security/model_handler_security_policy.py +107 -0
  316. omnibase_infra/models/security/model_security_error.py +81 -0
  317. omnibase_infra/models/security/model_security_validation_result.py +328 -0
  318. omnibase_infra/models/security/model_security_warning.py +67 -0
  319. omnibase_infra/models/snapshot/__init__.py +27 -0
  320. omnibase_infra/models/snapshot/model_field_change.py +65 -0
  321. omnibase_infra/models/snapshot/model_snapshot.py +270 -0
  322. omnibase_infra/models/snapshot/model_snapshot_diff.py +203 -0
  323. omnibase_infra/models/snapshot/model_subject_ref.py +81 -0
  324. omnibase_infra/models/types/__init__.py +71 -0
  325. omnibase_infra/models/validation/__init__.py +89 -0
  326. omnibase_infra/models/validation/model_any_type_validation_result.py +118 -0
  327. omnibase_infra/models/validation/model_any_type_violation.py +141 -0
  328. omnibase_infra/models/validation/model_category_match_result.py +345 -0
  329. omnibase_infra/models/validation/model_chain_violation.py +166 -0
  330. omnibase_infra/models/validation/model_coverage_metrics.py +316 -0
  331. omnibase_infra/models/validation/model_execution_shape_rule.py +159 -0
  332. omnibase_infra/models/validation/model_execution_shape_validation.py +208 -0
  333. omnibase_infra/models/validation/model_execution_shape_validation_result.py +294 -0
  334. omnibase_infra/models/validation/model_execution_shape_violation.py +122 -0
  335. omnibase_infra/models/validation/model_localhandler_validation_result.py +139 -0
  336. omnibase_infra/models/validation/model_localhandler_violation.py +100 -0
  337. omnibase_infra/models/validation/model_output_validation_params.py +74 -0
  338. omnibase_infra/models/validation/model_validate_and_raise_params.py +84 -0
  339. omnibase_infra/models/validation/model_validation_error_params.py +84 -0
  340. omnibase_infra/models/validation/model_validation_outcome.py +287 -0
  341. omnibase_infra/nodes/__init__.py +48 -0
  342. omnibase_infra/nodes/architecture_validator/__init__.py +79 -0
  343. omnibase_infra/nodes/architecture_validator/contract.yaml +252 -0
  344. omnibase_infra/nodes/architecture_validator/contract_architecture_validator.yaml +208 -0
  345. omnibase_infra/nodes/architecture_validator/mixins/__init__.py +16 -0
  346. omnibase_infra/nodes/architecture_validator/mixins/mixin_file_path_rule.py +92 -0
  347. omnibase_infra/nodes/architecture_validator/models/__init__.py +36 -0
  348. omnibase_infra/nodes/architecture_validator/models/model_architecture_validation_request.py +56 -0
  349. omnibase_infra/nodes/architecture_validator/models/model_architecture_validation_result.py +311 -0
  350. omnibase_infra/nodes/architecture_validator/models/model_architecture_violation.py +163 -0
  351. omnibase_infra/nodes/architecture_validator/models/model_rule_check_result.py +265 -0
  352. omnibase_infra/nodes/architecture_validator/models/model_validation_request.py +105 -0
  353. omnibase_infra/nodes/architecture_validator/models/model_validation_result.py +314 -0
  354. omnibase_infra/nodes/architecture_validator/node.py +262 -0
  355. omnibase_infra/nodes/architecture_validator/node_architecture_validator.py +383 -0
  356. omnibase_infra/nodes/architecture_validator/protocols/__init__.py +9 -0
  357. omnibase_infra/nodes/architecture_validator/protocols/protocol_architecture_rule.py +225 -0
  358. omnibase_infra/nodes/architecture_validator/registry/__init__.py +28 -0
  359. omnibase_infra/nodes/architecture_validator/registry/registry_infra_architecture_validator.py +99 -0
  360. omnibase_infra/nodes/architecture_validator/validators/__init__.py +104 -0
  361. omnibase_infra/nodes/architecture_validator/validators/validator_no_direct_dispatch.py +422 -0
  362. omnibase_infra/nodes/architecture_validator/validators/validator_no_handler_publishing.py +481 -0
  363. omnibase_infra/nodes/architecture_validator/validators/validator_no_orchestrator_fsm.py +491 -0
  364. omnibase_infra/nodes/effects/README.md +358 -0
  365. omnibase_infra/nodes/effects/__init__.py +26 -0
  366. omnibase_infra/nodes/effects/contract.yaml +172 -0
  367. omnibase_infra/nodes/effects/models/__init__.py +32 -0
  368. omnibase_infra/nodes/effects/models/model_backend_result.py +190 -0
  369. omnibase_infra/nodes/effects/models/model_effect_idempotency_config.py +92 -0
  370. omnibase_infra/nodes/effects/models/model_registry_request.py +132 -0
  371. omnibase_infra/nodes/effects/models/model_registry_response.py +263 -0
  372. omnibase_infra/nodes/effects/protocol_consul_client.py +89 -0
  373. omnibase_infra/nodes/effects/protocol_effect_idempotency_store.py +143 -0
  374. omnibase_infra/nodes/effects/protocol_postgres_adapter.py +96 -0
  375. omnibase_infra/nodes/effects/registry_effect.py +525 -0
  376. omnibase_infra/nodes/effects/store_effect_idempotency_inmemory.py +425 -0
  377. omnibase_infra/nodes/node_registration_orchestrator/README.md +542 -0
  378. omnibase_infra/nodes/node_registration_orchestrator/__init__.py +120 -0
  379. omnibase_infra/nodes/node_registration_orchestrator/contract.yaml +475 -0
  380. omnibase_infra/nodes/node_registration_orchestrator/dispatchers/__init__.py +53 -0
  381. omnibase_infra/nodes/node_registration_orchestrator/dispatchers/dispatcher_node_introspected.py +376 -0
  382. omnibase_infra/nodes/node_registration_orchestrator/dispatchers/dispatcher_node_registration_acked.py +376 -0
  383. omnibase_infra/nodes/node_registration_orchestrator/dispatchers/dispatcher_runtime_tick.py +373 -0
  384. omnibase_infra/nodes/node_registration_orchestrator/handlers/__init__.py +62 -0
  385. omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_heartbeat.py +376 -0
  386. omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_introspected.py +609 -0
  387. omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_registration_acked.py +458 -0
  388. omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_runtime_tick.py +364 -0
  389. omnibase_infra/nodes/node_registration_orchestrator/introspection_event_router.py +544 -0
  390. omnibase_infra/nodes/node_registration_orchestrator/models/__init__.py +75 -0
  391. omnibase_infra/nodes/node_registration_orchestrator/models/model_consul_intent_payload.py +194 -0
  392. omnibase_infra/nodes/node_registration_orchestrator/models/model_consul_registration_intent.py +67 -0
  393. omnibase_infra/nodes/node_registration_orchestrator/models/model_intent_execution_result.py +50 -0
  394. omnibase_infra/nodes/node_registration_orchestrator/models/model_node_liveness_expired.py +107 -0
  395. omnibase_infra/nodes/node_registration_orchestrator/models/model_orchestrator_config.py +67 -0
  396. omnibase_infra/nodes/node_registration_orchestrator/models/model_orchestrator_input.py +41 -0
  397. omnibase_infra/nodes/node_registration_orchestrator/models/model_orchestrator_output.py +166 -0
  398. omnibase_infra/nodes/node_registration_orchestrator/models/model_postgres_intent_payload.py +235 -0
  399. omnibase_infra/nodes/node_registration_orchestrator/models/model_postgres_upsert_intent.py +68 -0
  400. omnibase_infra/nodes/node_registration_orchestrator/models/model_reducer_execution_result.py +384 -0
  401. omnibase_infra/nodes/node_registration_orchestrator/models/model_reducer_state.py +60 -0
  402. omnibase_infra/nodes/node_registration_orchestrator/models/model_registration_intent.py +177 -0
  403. omnibase_infra/nodes/node_registration_orchestrator/models/model_registry_intent.py +247 -0
  404. omnibase_infra/nodes/node_registration_orchestrator/node.py +195 -0
  405. omnibase_infra/nodes/node_registration_orchestrator/plugin.py +909 -0
  406. omnibase_infra/nodes/node_registration_orchestrator/protocols.py +439 -0
  407. omnibase_infra/nodes/node_registration_orchestrator/registry/__init__.py +41 -0
  408. omnibase_infra/nodes/node_registration_orchestrator/registry/registry_infra_node_registration_orchestrator.py +525 -0
  409. omnibase_infra/nodes/node_registration_orchestrator/timeout_coordinator.py +392 -0
  410. omnibase_infra/nodes/node_registration_orchestrator/wiring.py +742 -0
  411. omnibase_infra/nodes/node_registration_reducer/__init__.py +15 -0
  412. omnibase_infra/nodes/node_registration_reducer/contract.yaml +301 -0
  413. omnibase_infra/nodes/node_registration_reducer/models/__init__.py +38 -0
  414. omnibase_infra/nodes/node_registration_reducer/models/model_validation_result.py +113 -0
  415. omnibase_infra/nodes/node_registration_reducer/node.py +139 -0
  416. omnibase_infra/nodes/node_registration_reducer/registry/__init__.py +9 -0
  417. omnibase_infra/nodes/node_registration_reducer/registry/registry_infra_node_registration_reducer.py +79 -0
  418. omnibase_infra/nodes/node_registration_storage_effect/__init__.py +41 -0
  419. omnibase_infra/nodes/node_registration_storage_effect/contract.yaml +225 -0
  420. omnibase_infra/nodes/node_registration_storage_effect/models/__init__.py +44 -0
  421. omnibase_infra/nodes/node_registration_storage_effect/models/model_delete_result.py +132 -0
  422. omnibase_infra/nodes/node_registration_storage_effect/models/model_registration_record.py +199 -0
  423. omnibase_infra/nodes/node_registration_storage_effect/models/model_registration_update.py +155 -0
  424. omnibase_infra/nodes/node_registration_storage_effect/models/model_storage_health_check_details.py +123 -0
  425. omnibase_infra/nodes/node_registration_storage_effect/models/model_storage_health_check_result.py +117 -0
  426. omnibase_infra/nodes/node_registration_storage_effect/models/model_storage_query.py +100 -0
  427. omnibase_infra/nodes/node_registration_storage_effect/models/model_storage_result.py +136 -0
  428. omnibase_infra/nodes/node_registration_storage_effect/models/model_upsert_result.py +127 -0
  429. omnibase_infra/nodes/node_registration_storage_effect/node.py +109 -0
  430. omnibase_infra/nodes/node_registration_storage_effect/protocols/__init__.py +22 -0
  431. omnibase_infra/nodes/node_registration_storage_effect/protocols/protocol_registration_persistence.py +333 -0
  432. omnibase_infra/nodes/node_registration_storage_effect/registry/__init__.py +23 -0
  433. omnibase_infra/nodes/node_registration_storage_effect/registry/registry_infra_registration_storage.py +194 -0
  434. omnibase_infra/nodes/node_registry_effect/__init__.py +85 -0
  435. omnibase_infra/nodes/node_registry_effect/contract.yaml +682 -0
  436. omnibase_infra/nodes/node_registry_effect/handlers/__init__.py +70 -0
  437. omnibase_infra/nodes/node_registry_effect/handlers/handler_consul_deregister.py +211 -0
  438. omnibase_infra/nodes/node_registry_effect/handlers/handler_consul_register.py +212 -0
  439. omnibase_infra/nodes/node_registry_effect/handlers/handler_partial_retry.py +416 -0
  440. omnibase_infra/nodes/node_registry_effect/handlers/handler_postgres_deactivate.py +215 -0
  441. omnibase_infra/nodes/node_registry_effect/handlers/handler_postgres_upsert.py +208 -0
  442. omnibase_infra/nodes/node_registry_effect/models/__init__.py +43 -0
  443. omnibase_infra/nodes/node_registry_effect/models/model_partial_retry_request.py +92 -0
  444. omnibase_infra/nodes/node_registry_effect/node.py +165 -0
  445. omnibase_infra/nodes/node_registry_effect/registry/__init__.py +27 -0
  446. omnibase_infra/nodes/node_registry_effect/registry/registry_infra_registry_effect.py +196 -0
  447. omnibase_infra/nodes/node_service_discovery_effect/__init__.py +111 -0
  448. omnibase_infra/nodes/node_service_discovery_effect/contract.yaml +246 -0
  449. omnibase_infra/nodes/node_service_discovery_effect/models/__init__.py +67 -0
  450. omnibase_infra/nodes/node_service_discovery_effect/models/enum_health_status.py +72 -0
  451. omnibase_infra/nodes/node_service_discovery_effect/models/enum_service_discovery_operation.py +58 -0
  452. omnibase_infra/nodes/node_service_discovery_effect/models/model_discovery_query.py +99 -0
  453. omnibase_infra/nodes/node_service_discovery_effect/models/model_discovery_result.py +98 -0
  454. omnibase_infra/nodes/node_service_discovery_effect/models/model_health_check_config.py +121 -0
  455. omnibase_infra/nodes/node_service_discovery_effect/models/model_query_metadata.py +63 -0
  456. omnibase_infra/nodes/node_service_discovery_effect/models/model_registration_result.py +130 -0
  457. omnibase_infra/nodes/node_service_discovery_effect/models/model_service_discovery_health_check_details.py +111 -0
  458. omnibase_infra/nodes/node_service_discovery_effect/models/model_service_discovery_health_check_result.py +119 -0
  459. omnibase_infra/nodes/node_service_discovery_effect/models/model_service_info.py +106 -0
  460. omnibase_infra/nodes/node_service_discovery_effect/models/model_service_registration.py +121 -0
  461. omnibase_infra/nodes/node_service_discovery_effect/node.py +111 -0
  462. omnibase_infra/nodes/node_service_discovery_effect/protocols/__init__.py +14 -0
  463. omnibase_infra/nodes/node_service_discovery_effect/protocols/protocol_discovery_operations.py +279 -0
  464. omnibase_infra/nodes/node_service_discovery_effect/registry/__init__.py +13 -0
  465. omnibase_infra/nodes/node_service_discovery_effect/registry/registry_infra_service_discovery.py +214 -0
  466. omnibase_infra/nodes/reducers/__init__.py +30 -0
  467. omnibase_infra/nodes/reducers/models/__init__.py +32 -0
  468. omnibase_infra/nodes/reducers/models/model_payload_consul_register.py +76 -0
  469. omnibase_infra/nodes/reducers/models/model_payload_postgres_upsert_registration.py +60 -0
  470. omnibase_infra/nodes/reducers/models/model_registration_confirmation.py +166 -0
  471. omnibase_infra/nodes/reducers/models/model_registration_state.py +433 -0
  472. omnibase_infra/nodes/reducers/registration_reducer.py +1137 -0
  473. omnibase_infra/observability/__init__.py +143 -0
  474. omnibase_infra/observability/constants_metrics.py +91 -0
  475. omnibase_infra/observability/factory_observability_sink.py +525 -0
  476. omnibase_infra/observability/handlers/__init__.py +118 -0
  477. omnibase_infra/observability/handlers/handler_logging_structured.py +967 -0
  478. omnibase_infra/observability/handlers/handler_metrics_prometheus.py +1120 -0
  479. omnibase_infra/observability/handlers/model_logging_handler_config.py +71 -0
  480. omnibase_infra/observability/handlers/model_logging_handler_response.py +77 -0
  481. omnibase_infra/observability/handlers/model_metrics_handler_config.py +172 -0
  482. omnibase_infra/observability/handlers/model_metrics_handler_payload.py +135 -0
  483. omnibase_infra/observability/handlers/model_metrics_handler_response.py +101 -0
  484. omnibase_infra/observability/hooks/__init__.py +74 -0
  485. omnibase_infra/observability/hooks/hook_observability.py +1223 -0
  486. omnibase_infra/observability/models/__init__.py +30 -0
  487. omnibase_infra/observability/models/enum_required_log_context_key.py +77 -0
  488. omnibase_infra/observability/models/model_buffered_log_entry.py +117 -0
  489. omnibase_infra/observability/models/model_logging_sink_config.py +73 -0
  490. omnibase_infra/observability/models/model_metrics_sink_config.py +156 -0
  491. omnibase_infra/observability/sinks/__init__.py +69 -0
  492. omnibase_infra/observability/sinks/sink_logging_structured.py +809 -0
  493. omnibase_infra/observability/sinks/sink_metrics_prometheus.py +710 -0
  494. omnibase_infra/plugins/__init__.py +27 -0
  495. omnibase_infra/plugins/examples/__init__.py +28 -0
  496. omnibase_infra/plugins/examples/plugin_json_normalizer.py +271 -0
  497. omnibase_infra/plugins/examples/plugin_json_normalizer_error_handling.py +210 -0
  498. omnibase_infra/plugins/models/__init__.py +21 -0
  499. omnibase_infra/plugins/models/model_plugin_context.py +76 -0
  500. omnibase_infra/plugins/models/model_plugin_input_data.py +58 -0
  501. omnibase_infra/plugins/models/model_plugin_output_data.py +62 -0
  502. omnibase_infra/plugins/plugin_compute_base.py +435 -0
  503. omnibase_infra/projectors/__init__.py +30 -0
  504. omnibase_infra/projectors/contracts/__init__.py +63 -0
  505. omnibase_infra/projectors/contracts/registration_projector.yaml +370 -0
  506. omnibase_infra/projectors/projection_reader_registration.py +1559 -0
  507. omnibase_infra/projectors/snapshot_publisher_registration.py +1329 -0
  508. omnibase_infra/protocols/__init__.py +99 -0
  509. omnibase_infra/protocols/protocol_capability_projection.py +253 -0
  510. omnibase_infra/protocols/protocol_capability_query.py +251 -0
  511. omnibase_infra/protocols/protocol_event_bus_like.py +127 -0
  512. omnibase_infra/protocols/protocol_event_projector.py +96 -0
  513. omnibase_infra/protocols/protocol_idempotency_store.py +142 -0
  514. omnibase_infra/protocols/protocol_message_dispatcher.py +247 -0
  515. omnibase_infra/protocols/protocol_message_type_registry.py +306 -0
  516. omnibase_infra/protocols/protocol_plugin_compute.py +368 -0
  517. omnibase_infra/protocols/protocol_projector_schema_validator.py +82 -0
  518. omnibase_infra/protocols/protocol_registry_metrics.py +215 -0
  519. omnibase_infra/protocols/protocol_snapshot_publisher.py +396 -0
  520. omnibase_infra/protocols/protocol_snapshot_store.py +567 -0
  521. omnibase_infra/runtime/__init__.py +296 -0
  522. omnibase_infra/runtime/binding_config_resolver.py +2706 -0
  523. omnibase_infra/runtime/chain_aware_dispatch.py +467 -0
  524. omnibase_infra/runtime/contract_handler_discovery.py +582 -0
  525. omnibase_infra/runtime/contract_loaders/__init__.py +42 -0
  526. omnibase_infra/runtime/contract_loaders/handler_routing_loader.py +464 -0
  527. omnibase_infra/runtime/dispatch_context_enforcer.py +427 -0
  528. omnibase_infra/runtime/enums/__init__.py +18 -0
  529. omnibase_infra/runtime/enums/enum_config_ref_scheme.py +33 -0
  530. omnibase_infra/runtime/enums/enum_scheduler_status.py +170 -0
  531. omnibase_infra/runtime/envelope_validator.py +179 -0
  532. omnibase_infra/runtime/handler_contract_source.py +669 -0
  533. omnibase_infra/runtime/handler_plugin_loader.py +2029 -0
  534. omnibase_infra/runtime/handler_registry.py +321 -0
  535. omnibase_infra/runtime/invocation_security_enforcer.py +427 -0
  536. omnibase_infra/runtime/kernel.py +40 -0
  537. omnibase_infra/runtime/mixin_policy_validation.py +522 -0
  538. omnibase_infra/runtime/mixin_semver_cache.py +378 -0
  539. omnibase_infra/runtime/mixins/__init__.py +17 -0
  540. omnibase_infra/runtime/mixins/mixin_projector_sql_operations.py +757 -0
  541. omnibase_infra/runtime/models/__init__.py +192 -0
  542. omnibase_infra/runtime/models/model_batch_lifecycle_result.py +217 -0
  543. omnibase_infra/runtime/models/model_binding_config.py +168 -0
  544. omnibase_infra/runtime/models/model_binding_config_cache_stats.py +135 -0
  545. omnibase_infra/runtime/models/model_binding_config_resolver_config.py +329 -0
  546. omnibase_infra/runtime/models/model_cached_secret.py +138 -0
  547. omnibase_infra/runtime/models/model_compute_key.py +138 -0
  548. omnibase_infra/runtime/models/model_compute_registration.py +97 -0
  549. omnibase_infra/runtime/models/model_config_cache_entry.py +61 -0
  550. omnibase_infra/runtime/models/model_config_ref.py +331 -0
  551. omnibase_infra/runtime/models/model_config_ref_parse_result.py +125 -0
  552. omnibase_infra/runtime/models/model_domain_plugin_config.py +92 -0
  553. omnibase_infra/runtime/models/model_domain_plugin_result.py +270 -0
  554. omnibase_infra/runtime/models/model_duplicate_response.py +54 -0
  555. omnibase_infra/runtime/models/model_enabled_protocols_config.py +61 -0
  556. omnibase_infra/runtime/models/model_event_bus_config.py +54 -0
  557. omnibase_infra/runtime/models/model_failed_component.py +55 -0
  558. omnibase_infra/runtime/models/model_health_check_response.py +168 -0
  559. omnibase_infra/runtime/models/model_health_check_result.py +228 -0
  560. omnibase_infra/runtime/models/model_lifecycle_result.py +245 -0
  561. omnibase_infra/runtime/models/model_logging_config.py +42 -0
  562. omnibase_infra/runtime/models/model_optional_correlation_id.py +167 -0
  563. omnibase_infra/runtime/models/model_optional_string.py +94 -0
  564. omnibase_infra/runtime/models/model_optional_uuid.py +110 -0
  565. omnibase_infra/runtime/models/model_policy_context.py +100 -0
  566. omnibase_infra/runtime/models/model_policy_key.py +138 -0
  567. omnibase_infra/runtime/models/model_policy_registration.py +139 -0
  568. omnibase_infra/runtime/models/model_policy_result.py +103 -0
  569. omnibase_infra/runtime/models/model_policy_type_filter.py +157 -0
  570. omnibase_infra/runtime/models/model_projector_plugin_loader_config.py +47 -0
  571. omnibase_infra/runtime/models/model_protocol_registration_config.py +65 -0
  572. omnibase_infra/runtime/models/model_retry_policy.py +105 -0
  573. omnibase_infra/runtime/models/model_runtime_config.py +150 -0
  574. omnibase_infra/runtime/models/model_runtime_scheduler_config.py +624 -0
  575. omnibase_infra/runtime/models/model_runtime_scheduler_metrics.py +233 -0
  576. omnibase_infra/runtime/models/model_runtime_tick.py +193 -0
  577. omnibase_infra/runtime/models/model_secret_cache_stats.py +82 -0
  578. omnibase_infra/runtime/models/model_secret_mapping.py +63 -0
  579. omnibase_infra/runtime/models/model_secret_resolver_config.py +107 -0
  580. omnibase_infra/runtime/models/model_secret_resolver_metrics.py +111 -0
  581. omnibase_infra/runtime/models/model_secret_source_info.py +72 -0
  582. omnibase_infra/runtime/models/model_secret_source_spec.py +66 -0
  583. omnibase_infra/runtime/models/model_shutdown_batch_result.py +75 -0
  584. omnibase_infra/runtime/models/model_shutdown_config.py +94 -0
  585. omnibase_infra/runtime/projector_plugin_loader.py +1462 -0
  586. omnibase_infra/runtime/projector_schema_manager.py +565 -0
  587. omnibase_infra/runtime/projector_shell.py +1102 -0
  588. omnibase_infra/runtime/protocol_contract_descriptor.py +92 -0
  589. omnibase_infra/runtime/protocol_contract_source.py +92 -0
  590. omnibase_infra/runtime/protocol_domain_plugin.py +474 -0
  591. omnibase_infra/runtime/protocol_handler_discovery.py +221 -0
  592. omnibase_infra/runtime/protocol_handler_plugin_loader.py +327 -0
  593. omnibase_infra/runtime/protocol_lifecycle_executor.py +435 -0
  594. omnibase_infra/runtime/protocol_policy.py +366 -0
  595. omnibase_infra/runtime/protocols/__init__.py +27 -0
  596. omnibase_infra/runtime/protocols/protocol_runtime_scheduler.py +468 -0
  597. omnibase_infra/runtime/registry/__init__.py +93 -0
  598. omnibase_infra/runtime/registry/mixin_message_type_query.py +326 -0
  599. omnibase_infra/runtime/registry/mixin_message_type_registration.py +354 -0
  600. omnibase_infra/runtime/registry/registry_event_bus_binding.py +268 -0
  601. omnibase_infra/runtime/registry/registry_message_type.py +542 -0
  602. omnibase_infra/runtime/registry/registry_protocol_binding.py +444 -0
  603. omnibase_infra/runtime/registry_compute.py +1143 -0
  604. omnibase_infra/runtime/registry_dispatcher.py +678 -0
  605. omnibase_infra/runtime/registry_policy.py +1502 -0
  606. omnibase_infra/runtime/runtime_scheduler.py +1070 -0
  607. omnibase_infra/runtime/secret_resolver.py +2110 -0
  608. omnibase_infra/runtime/security_metadata_validator.py +776 -0
  609. omnibase_infra/runtime/service_kernel.py +1573 -0
  610. omnibase_infra/runtime/service_message_dispatch_engine.py +1805 -0
  611. omnibase_infra/runtime/service_runtime_host_process.py +2260 -0
  612. omnibase_infra/runtime/util_container_wiring.py +1123 -0
  613. omnibase_infra/runtime/util_validation.py +314 -0
  614. omnibase_infra/runtime/util_version.py +98 -0
  615. omnibase_infra/runtime/util_wiring.py +566 -0
  616. omnibase_infra/schemas/schema_registration_projection.sql +320 -0
  617. omnibase_infra/services/__init__.py +68 -0
  618. omnibase_infra/services/corpus_capture.py +678 -0
  619. omnibase_infra/services/service_capability_query.py +945 -0
  620. omnibase_infra/services/service_health.py +897 -0
  621. omnibase_infra/services/service_node_selector.py +530 -0
  622. omnibase_infra/services/service_timeout_emitter.py +682 -0
  623. omnibase_infra/services/service_timeout_scanner.py +390 -0
  624. omnibase_infra/services/snapshot/__init__.py +31 -0
  625. omnibase_infra/services/snapshot/service_snapshot.py +647 -0
  626. omnibase_infra/services/snapshot/store_inmemory.py +637 -0
  627. omnibase_infra/services/snapshot/store_postgres.py +1279 -0
  628. omnibase_infra/shared/__init__.py +8 -0
  629. omnibase_infra/testing/__init__.py +10 -0
  630. omnibase_infra/testing/utils.py +23 -0
  631. omnibase_infra/types/__init__.py +48 -0
  632. omnibase_infra/types/type_cache_info.py +49 -0
  633. omnibase_infra/types/type_dsn.py +173 -0
  634. omnibase_infra/types/type_infra_aliases.py +60 -0
  635. omnibase_infra/types/typed_dict/__init__.py +21 -0
  636. omnibase_infra/types/typed_dict/typed_dict_introspection_cache.py +128 -0
  637. omnibase_infra/types/typed_dict/typed_dict_performance_metrics_cache.py +140 -0
  638. omnibase_infra/types/typed_dict_capabilities.py +64 -0
  639. omnibase_infra/utils/__init__.py +89 -0
  640. omnibase_infra/utils/correlation.py +208 -0
  641. omnibase_infra/utils/util_datetime.py +372 -0
  642. omnibase_infra/utils/util_dsn_validation.py +333 -0
  643. omnibase_infra/utils/util_env_parsing.py +264 -0
  644. omnibase_infra/utils/util_error_sanitization.py +457 -0
  645. omnibase_infra/utils/util_pydantic_validators.py +477 -0
  646. omnibase_infra/utils/util_semver.py +233 -0
  647. omnibase_infra/validation/__init__.py +307 -0
  648. omnibase_infra/validation/enums/__init__.py +11 -0
  649. omnibase_infra/validation/enums/enum_contract_violation_severity.py +13 -0
  650. omnibase_infra/validation/infra_validators.py +1486 -0
  651. omnibase_infra/validation/linter_contract.py +907 -0
  652. omnibase_infra/validation/mixin_any_type_classification.py +120 -0
  653. omnibase_infra/validation/mixin_any_type_exemption.py +580 -0
  654. omnibase_infra/validation/mixin_any_type_reporting.py +106 -0
  655. omnibase_infra/validation/mixin_execution_shape_violation_checks.py +596 -0
  656. omnibase_infra/validation/mixin_node_archetype_detection.py +254 -0
  657. omnibase_infra/validation/models/__init__.py +15 -0
  658. omnibase_infra/validation/models/model_contract_lint_result.py +101 -0
  659. omnibase_infra/validation/models/model_contract_violation.py +41 -0
  660. omnibase_infra/validation/service_validation_aggregator.py +395 -0
  661. omnibase_infra/validation/validation_exemptions.yaml +1710 -0
  662. omnibase_infra/validation/validator_any_type.py +715 -0
  663. omnibase_infra/validation/validator_chain_propagation.py +839 -0
  664. omnibase_infra/validation/validator_execution_shape.py +465 -0
  665. omnibase_infra/validation/validator_localhandler.py +261 -0
  666. omnibase_infra/validation/validator_registration_security.py +410 -0
  667. omnibase_infra/validation/validator_routing_coverage.py +1020 -0
  668. omnibase_infra/validation/validator_runtime_shape.py +915 -0
  669. omnibase_infra/validation/validator_security.py +410 -0
  670. omnibase_infra/validation/validator_topic_category.py +1152 -0
  671. omnibase_infra-0.2.1.dist-info/METADATA +197 -0
  672. omnibase_infra-0.2.1.dist-info/RECORD +675 -0
  673. omnibase_infra-0.2.1.dist-info/WHEEL +4 -0
  674. omnibase_infra-0.2.1.dist-info/entry_points.txt +4 -0
  675. omnibase_infra-0.2.1.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,920 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2025 OmniNode Team
3
+ """HTTP REST Handler - MVP implementation using httpx async client.
4
+
5
+ Supports GET and POST operations with 30-second fixed timeout.
6
+ PUT, DELETE, PATCH deferred to Beta. Retry logic and rate limiting deferred to Beta.
7
+
8
+ Note:
9
+ Environment variable configuration (ONEX_HTTP_TIMEOUT, ONEX_HTTP_MAX_REQUEST_SIZE,
10
+ ONEX_HTTP_MAX_RESPONSE_SIZE) is parsed at module import time, not at handler
11
+ instantiation. This means:
12
+
13
+ - Changes to environment variables require application restart to take effect
14
+ - Tests should use ``unittest.mock.patch.dict(os.environ, ...)`` before importing,
15
+ or use ``importlib.reload()`` to re-import the module after patching
16
+ - This is an intentional design choice for startup-time validation
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ import json
22
+ import logging
23
+ from uuid import UUID, uuid4
24
+
25
+ import httpx
26
+
27
+ from omnibase_core.models.dispatch import ModelHandlerOutput
28
+ from omnibase_infra.enums import (
29
+ EnumHandlerType,
30
+ EnumHandlerTypeCategory,
31
+ EnumInfraTransportType,
32
+ )
33
+ from omnibase_infra.errors import (
34
+ InfraConnectionError,
35
+ InfraTimeoutError,
36
+ InfraUnavailableError,
37
+ ModelInfraErrorContext,
38
+ ModelTimeoutErrorContext,
39
+ ProtocolConfigurationError,
40
+ RuntimeHostError,
41
+ )
42
+ from omnibase_infra.handlers.models.http import ModelHttpBodyContent
43
+ from omnibase_infra.mixins import MixinEnvelopeExtraction
44
+ from omnibase_infra.utils import parse_env_float, parse_env_int
45
+
46
+ logger = logging.getLogger(__name__)
47
+
48
+
49
+ _DEFAULT_TIMEOUT_SECONDS: float = parse_env_float(
50
+ "ONEX_HTTP_TIMEOUT",
51
+ 30.0,
52
+ min_value=1.0,
53
+ max_value=300.0,
54
+ transport_type=EnumInfraTransportType.HTTP,
55
+ service_name="http_handler",
56
+ )
57
+ _DEFAULT_MAX_REQUEST_SIZE: int = parse_env_int(
58
+ "ONEX_HTTP_MAX_REQUEST_SIZE",
59
+ 10 * 1024 * 1024,
60
+ min_value=1024,
61
+ max_value=104857600,
62
+ transport_type=EnumInfraTransportType.HTTP,
63
+ service_name="http_handler",
64
+ ) # 10 MB default, min 1 KB, max 100 MB
65
+ _DEFAULT_MAX_RESPONSE_SIZE: int = parse_env_int(
66
+ "ONEX_HTTP_MAX_RESPONSE_SIZE",
67
+ 50 * 1024 * 1024,
68
+ min_value=1024,
69
+ max_value=104857600,
70
+ transport_type=EnumInfraTransportType.HTTP,
71
+ service_name="http_handler",
72
+ ) # 50 MB default, min 1 KB, max 100 MB
73
+ _SUPPORTED_OPERATIONS: frozenset[str] = frozenset({"http.get", "http.post"})
74
+ # Streaming chunk size for responses without Content-Length header
75
+ _STREAMING_CHUNK_SIZE: int = 8192 # 8 KB chunks
76
+
77
+ # Handler ID for ModelHandlerOutput
78
+ HANDLER_ID_HTTP: str = "http-handler"
79
+
80
+ # Size category thresholds for sanitized logging
81
+ _SIZE_THRESHOLD_KB: int = 1024 # 1 KB
82
+ _SIZE_THRESHOLD_MB: int = 1024 * 1024 # 1 MB
83
+ _SIZE_THRESHOLD_10MB: int = 10 * 1024 * 1024 # 10 MB
84
+
85
+
86
+ def _categorize_size(size: int) -> str:
87
+ """Categorize byte size into security-safe categories.
88
+
89
+ This prevents exact payload sizes from being exposed in error messages
90
+ and logs, which could help attackers probe size limits.
91
+
92
+ Args:
93
+ size: Size in bytes
94
+
95
+ Returns:
96
+ Size category: "small", "medium", "large", or "very_large"
97
+ """
98
+ if size < _SIZE_THRESHOLD_KB:
99
+ return "small"
100
+ elif size < _SIZE_THRESHOLD_MB:
101
+ return "medium"
102
+ elif size < _SIZE_THRESHOLD_10MB:
103
+ return "large"
104
+ else:
105
+ return "very_large"
106
+
107
+
108
+ class HandlerHttpRest(MixinEnvelopeExtraction):
109
+ """HTTP REST protocol handler using httpx async client (MVP: GET, POST only).
110
+
111
+ Security Features:
112
+ - Configurable request/response size limits to prevent DoS attacks
113
+ - Pre-read Content-Length validation to prevent memory exhaustion
114
+ - Streaming body validation for chunked transfer encoding
115
+ """
116
+
117
+ def __init__(self) -> None:
118
+ """Initialize HandlerHttpRest in uninitialized state."""
119
+ self._client: httpx.AsyncClient | None = None
120
+ self._timeout: float = _DEFAULT_TIMEOUT_SECONDS
121
+ self._max_request_size: int = _DEFAULT_MAX_REQUEST_SIZE
122
+ self._max_response_size: int = _DEFAULT_MAX_RESPONSE_SIZE
123
+ self._initialized: bool = False
124
+
125
+ @property
126
+ def handler_type(self) -> EnumHandlerType:
127
+ """Return the architectural role of this handler.
128
+
129
+ Returns:
130
+ EnumHandlerType.INFRA_HANDLER - This handler is an infrastructure
131
+ protocol/transport handler (as opposed to NODE_HANDLER for event
132
+ processing, PROJECTION_HANDLER for read models, or COMPUTE_HANDLER
133
+ for pure computation).
134
+
135
+ Note:
136
+ handler_type determines lifecycle, protocol selection, and runtime
137
+ invocation patterns. It answers "what is this handler in the architecture?"
138
+
139
+ See Also:
140
+ - handler_category: Behavioral classification (EFFECT/COMPUTE)
141
+ - transport_type: Specific transport protocol (HTTP/DATABASE/etc.)
142
+ - docs/architecture/HANDLER_PROTOCOL_DRIVEN_ARCHITECTURE.md
143
+ """
144
+ return EnumHandlerType.INFRA_HANDLER
145
+
146
+ @property
147
+ def handler_category(self) -> EnumHandlerTypeCategory:
148
+ """Return the behavioral classification of this handler.
149
+
150
+ Returns:
151
+ EnumHandlerTypeCategory.EFFECT - This handler performs side-effecting
152
+ I/O operations (external HTTP requests). EFFECT handlers are not
153
+ deterministic and interact with external systems.
154
+
155
+ Note:
156
+ handler_category determines security rules, determinism guarantees,
157
+ replay safety, and permissions. It answers "how does this handler
158
+ behave at runtime?"
159
+
160
+ Categories:
161
+ - COMPUTE: Pure, deterministic transformations (no side effects)
162
+ - EFFECT: Side-effecting I/O (database, HTTP, service calls)
163
+ - NONDETERMINISTIC_COMPUTE: Pure but not deterministic (UUID, random)
164
+
165
+ See Also:
166
+ - handler_type: Architectural role (INFRA_HANDLER/NODE_HANDLER/etc.)
167
+ - transport_type: Specific transport protocol (HTTP/DATABASE/etc.)
168
+ - docs/architecture/HANDLER_PROTOCOL_DRIVEN_ARCHITECTURE.md
169
+ """
170
+ return EnumHandlerTypeCategory.EFFECT
171
+
172
+ @property
173
+ def transport_type(self) -> EnumInfraTransportType:
174
+ """Return the transport protocol identifier for this handler.
175
+
176
+ Returns:
177
+ EnumInfraTransportType.HTTP - This handler uses HTTP/REST protocol.
178
+
179
+ Note:
180
+ transport_type identifies the specific transport/protocol this handler
181
+ uses. It is the third dimension of the handler type system, alongside
182
+ handler_type (architectural role) and handler_category (behavioral
183
+ classification).
184
+
185
+ The three dimensions together form a complete handler classification:
186
+ - handler_type: INFRA_HANDLER (what it is architecturally)
187
+ - handler_category: EFFECT (how it behaves at runtime)
188
+ - transport_type: HTTP (what protocol it uses)
189
+
190
+ See Also:
191
+ - handler_type: Architectural role
192
+ - handler_category: Behavioral classification
193
+ - docs/architecture/HANDLER_PROTOCOL_DRIVEN_ARCHITECTURE.md
194
+ """
195
+ return EnumInfraTransportType.HTTP
196
+
197
+ async def initialize(self, config: dict[str, object]) -> None:
198
+ """Initialize HTTP client with configurable timeout and size limits.
199
+
200
+ Args:
201
+ config: Configuration dict containing:
202
+ - max_request_size: Optional max request body size in bytes (default: 10 MB)
203
+ - max_response_size: Optional max response body size in bytes (default: 50 MB)
204
+ - correlation_id: Optional UUID or string for error tracing
205
+
206
+ Raises:
207
+ ProtocolConfigurationError: If client initialization fails.
208
+
209
+ Security:
210
+ Size limits provide DoS (Denial of Service) protection by preventing:
211
+ - Memory exhaustion from oversized request bodies
212
+ - Memory exhaustion from malicious/misconfigured server responses
213
+ - Resource starvation attacks via large payload processing
214
+
215
+ Content-Length headers are validated BEFORE reading response bodies,
216
+ and streaming validation protects against chunked transfer encoding attacks.
217
+
218
+ Note:
219
+ Size limit violations raise InfraUnavailableError with sanitized size
220
+ categories (small/medium/large/very_large) - exact sizes are not exposed
221
+ in error messages to prevent attackers from probing limits.
222
+ """
223
+ # Generate correlation_id for initialization tracing
224
+ init_correlation_id = uuid4()
225
+
226
+ logger.info(
227
+ "Initializing %s",
228
+ self.__class__.__name__,
229
+ extra={
230
+ "handler": self.__class__.__name__,
231
+ "correlation_id": str(init_correlation_id),
232
+ },
233
+ )
234
+
235
+ try:
236
+ self._timeout = _DEFAULT_TIMEOUT_SECONDS
237
+
238
+ # Extract configurable size limits
239
+ max_request_raw = config.get("max_request_size")
240
+ if max_request_raw is not None:
241
+ if isinstance(max_request_raw, int) and max_request_raw > 0:
242
+ self._max_request_size = max_request_raw
243
+ else:
244
+ logger.warning(
245
+ "Invalid max_request_size config value ignored, using default",
246
+ extra={
247
+ "provided_value": max_request_raw,
248
+ "default_value": self._max_request_size,
249
+ },
250
+ )
251
+
252
+ max_response_raw = config.get("max_response_size")
253
+ if max_response_raw is not None:
254
+ if isinstance(max_response_raw, int) and max_response_raw > 0:
255
+ self._max_response_size = max_response_raw
256
+ else:
257
+ logger.warning(
258
+ "Invalid max_response_size config value ignored, using default",
259
+ extra={
260
+ "provided_value": max_response_raw,
261
+ "default_value": self._max_response_size,
262
+ },
263
+ )
264
+
265
+ self._client = httpx.AsyncClient(
266
+ timeout=httpx.Timeout(self._timeout),
267
+ follow_redirects=True,
268
+ )
269
+ self._initialized = True
270
+ logger.info(
271
+ "%s initialized successfully",
272
+ self.__class__.__name__,
273
+ extra={
274
+ "handler": self.__class__.__name__,
275
+ "timeout_seconds": self._timeout,
276
+ "max_request_size_bytes": self._max_request_size,
277
+ "max_response_size_bytes": self._max_response_size,
278
+ "correlation_id": str(init_correlation_id),
279
+ },
280
+ )
281
+ except Exception as e:
282
+ ctx = ModelInfraErrorContext(
283
+ transport_type=EnumInfraTransportType.HTTP,
284
+ operation="initialize",
285
+ target_name="http_handler",
286
+ correlation_id=init_correlation_id,
287
+ )
288
+ raise ProtocolConfigurationError(
289
+ "Failed to initialize HTTP handler", context=ctx
290
+ ) from e
291
+
292
+ async def shutdown(self) -> None:
293
+ """Close HTTP client and release resources."""
294
+ if self._client is not None:
295
+ await self._client.aclose()
296
+ self._client = None
297
+ self._initialized = False
298
+ logger.info("HandlerHttpRest shutdown complete")
299
+
300
+ async def execute(
301
+ self, envelope: dict[str, object]
302
+ ) -> ModelHandlerOutput[dict[str, object]]:
303
+ """Execute HTTP operation (http.get or http.post) from envelope.
304
+
305
+ Args:
306
+ envelope: Request envelope containing:
307
+ - operation: "http.get" or "http.post"
308
+ - payload: dict with "url" (required), "headers" (optional), "body" (optional for POST)
309
+ - correlation_id: Optional correlation ID for tracing
310
+ - envelope_id: Optional envelope ID for causality tracking
311
+
312
+ Returns:
313
+ ModelHandlerOutput[dict[str, object]] containing:
314
+ - result: dict with status, payload (status_code, headers, body), and correlation_id
315
+ - input_envelope_id: UUID for causality tracking
316
+ - correlation_id: UUID for request/response correlation
317
+ - handler_id: "http-handler"
318
+ """
319
+ correlation_id = self._extract_correlation_id(envelope)
320
+ input_envelope_id = self._extract_envelope_id(envelope)
321
+
322
+ if not self._initialized or self._client is None:
323
+ ctx = ModelInfraErrorContext(
324
+ transport_type=EnumInfraTransportType.HTTP,
325
+ operation="execute",
326
+ target_name="http_handler",
327
+ correlation_id=correlation_id,
328
+ )
329
+ raise RuntimeHostError(
330
+ "HandlerHttpRest not initialized. Call initialize() first.", context=ctx
331
+ )
332
+
333
+ operation = envelope.get("operation")
334
+ if not isinstance(operation, str):
335
+ ctx = ModelInfraErrorContext(
336
+ transport_type=EnumInfraTransportType.HTTP,
337
+ operation="execute",
338
+ target_name="http_handler",
339
+ correlation_id=correlation_id,
340
+ )
341
+ raise ProtocolConfigurationError(
342
+ "Missing or invalid 'operation' in envelope", context=ctx
343
+ )
344
+
345
+ if operation not in _SUPPORTED_OPERATIONS:
346
+ ctx = ModelInfraErrorContext(
347
+ transport_type=EnumInfraTransportType.HTTP,
348
+ operation=operation,
349
+ target_name="http_handler",
350
+ correlation_id=correlation_id,
351
+ )
352
+ raise ProtocolConfigurationError(
353
+ f"Operation '{operation}' not supported in MVP. Available: {', '.join(sorted(_SUPPORTED_OPERATIONS))}",
354
+ context=ctx,
355
+ )
356
+
357
+ payload = envelope.get("payload")
358
+ if not isinstance(payload, dict):
359
+ ctx = ModelInfraErrorContext(
360
+ transport_type=EnumInfraTransportType.HTTP,
361
+ operation=operation,
362
+ target_name="http_handler",
363
+ correlation_id=correlation_id,
364
+ )
365
+ raise ProtocolConfigurationError(
366
+ "Missing or invalid 'payload' in envelope", context=ctx
367
+ )
368
+
369
+ url = payload.get("url")
370
+ if not isinstance(url, str) or not url:
371
+ ctx = ModelInfraErrorContext(
372
+ transport_type=EnumInfraTransportType.HTTP,
373
+ operation=operation,
374
+ target_name="http_handler",
375
+ correlation_id=correlation_id,
376
+ )
377
+ raise ProtocolConfigurationError(
378
+ "Missing or invalid 'url' in payload", context=ctx
379
+ )
380
+
381
+ headers = self._extract_headers(payload, operation, url, correlation_id)
382
+
383
+ if operation == "http.get":
384
+ return await self._execute_request(
385
+ "GET", url, headers, None, correlation_id, input_envelope_id, None
386
+ )
387
+ else: # http.post
388
+ body = payload.get("body")
389
+ # Validate request body size and get pre-serialized bytes for dict bodies.
390
+ # This avoids double serialization - dict bodies are serialized once here
391
+ # and the cached bytes are passed to _execute_request().
392
+ pre_serialized = self._validate_request_size(body, correlation_id)
393
+ return await self._execute_request(
394
+ "POST",
395
+ url,
396
+ headers,
397
+ body,
398
+ correlation_id,
399
+ input_envelope_id,
400
+ pre_serialized,
401
+ )
402
+
403
+ def _extract_headers(
404
+ self,
405
+ payload: dict[str, object],
406
+ operation: str,
407
+ url: str,
408
+ correlation_id: UUID,
409
+ ) -> dict[str, str]:
410
+ """Extract and validate headers from payload."""
411
+ headers_raw = payload.get("headers")
412
+ if headers_raw is None:
413
+ return {}
414
+ if isinstance(headers_raw, dict):
415
+ return {str(k): str(v) for k, v in headers_raw.items()}
416
+ ctx = ModelInfraErrorContext(
417
+ transport_type=EnumInfraTransportType.HTTP,
418
+ operation=operation,
419
+ target_name=url,
420
+ correlation_id=correlation_id,
421
+ )
422
+ raise ProtocolConfigurationError(
423
+ "Invalid 'headers' in payload - must be a dict", context=ctx
424
+ )
425
+
426
+ def _validate_request_size(
427
+ self, body: object, correlation_id: UUID
428
+ ) -> bytes | None:
429
+ """Validate request body size and cache serialized bytes for dict bodies.
430
+
431
+ For dict bodies, this method serializes the body once and returns the
432
+ serialized bytes. This avoids double serialization - the returned bytes
433
+ can be passed directly to _execute_request() instead of re-serializing.
434
+
435
+ Args:
436
+ body: Request body (str, dict, bytes, or None)
437
+ correlation_id: Correlation ID for error context
438
+
439
+ Returns:
440
+ For dict bodies: The pre-serialized JSON bytes (cached for reuse)
441
+ For other body types: None (no caching needed)
442
+
443
+ Raises:
444
+ InfraUnavailableError: If body size exceeds max_request_size limit.
445
+ """
446
+ if body is None:
447
+ return None
448
+
449
+ size: int = 0
450
+ serialized_bytes: bytes | None = None
451
+
452
+ if isinstance(body, str):
453
+ size = len(body.encode("utf-8"))
454
+ elif isinstance(body, dict):
455
+ # DESIGN TRADEOFF: Double-Serialization Avoidance
456
+ #
457
+ # We serialize dict bodies once here during validation and cache the bytes.
458
+ # The cached bytes are then passed to _execute_request() via the return value,
459
+ # avoiding re-serialization when building the HTTP request.
460
+ #
461
+ # Tradeoff considerations:
462
+ # - Memory: Serialized bytes are held in memory during validation and request
463
+ # execution. For large payloads near the size limit, this adds ~10MB overhead.
464
+ # - Performance: Single serialization is faster than serializing twice (once
465
+ # for size check, once for request body).
466
+ # - Alternative: We could serialize twice (once here for size, once in execute)
467
+ # which would use less peak memory but double the CPU cost for serialization.
468
+ #
469
+ # Current approach prioritizes CPU efficiency over peak memory usage, which is
470
+ # appropriate since we enforce max_request_size limits anyway.
471
+ try:
472
+ serialized_bytes = json.dumps(body).encode("utf-8")
473
+ size = len(serialized_bytes)
474
+ except (TypeError, ValueError):
475
+ # If we can't serialize, skip validation and let execute() handle it
476
+ return None
477
+ elif isinstance(body, bytes):
478
+ size = len(body)
479
+ else:
480
+ # Unknown type - skip validation, let execute() handle serialization
481
+ return None
482
+
483
+ if size > self._max_request_size:
484
+ ctx = ModelInfraErrorContext(
485
+ transport_type=EnumInfraTransportType.HTTP,
486
+ operation="validate_request_size",
487
+ target_name="http_handler",
488
+ correlation_id=correlation_id,
489
+ )
490
+ raise InfraUnavailableError(
491
+ f"Request body size ({_categorize_size(size)}) exceeds configured limit",
492
+ context=ctx,
493
+ )
494
+
495
+ logger.debug(
496
+ "Request size validated",
497
+ extra={
498
+ "request_size_category": _categorize_size(size),
499
+ "limit": self._max_request_size,
500
+ "correlation_id": str(correlation_id),
501
+ },
502
+ )
503
+
504
+ # Return cached serialized bytes for dict bodies, None for other types
505
+ return serialized_bytes
506
+
507
+ def _validate_content_length_header(
508
+ self, response: httpx.Response, url: str, correlation_id: UUID
509
+ ) -> None:
510
+ """Validate Content-Length header BEFORE reading response body.
511
+
512
+ This prevents memory exhaustion by rejecting large responses before
513
+ they are loaded into memory. This is critical for security as it
514
+ prevents denial-of-service attacks via large response payloads.
515
+
516
+ Args:
517
+ response: The httpx Response object (body not yet read)
518
+ url: Target URL for error context
519
+ correlation_id: Correlation ID for error context
520
+
521
+ Raises:
522
+ InfraUnavailableError: If Content-Length exceeds max_response_size limit.
523
+ """
524
+ content_length_header = response.headers.get("content-length")
525
+ if content_length_header is None:
526
+ # No Content-Length header - will use streaming validation
527
+ return
528
+
529
+ try:
530
+ content_length = int(content_length_header)
531
+ except ValueError:
532
+ # Invalid Content-Length header - log warning and proceed with body-based validation
533
+ logger.warning(
534
+ "Invalid Content-Length header value",
535
+ extra={
536
+ "content_length_header": content_length_header,
537
+ "url": url,
538
+ "correlation_id": str(correlation_id),
539
+ },
540
+ )
541
+ return
542
+
543
+ if content_length < 0:
544
+ # Negative Content-Length is invalid per HTTP spec - log warning and proceed
545
+ # with body-based validation (streaming protection still applies)
546
+ logger.warning(
547
+ "Negative Content-Length header value ignored",
548
+ extra={
549
+ "content_length_header": content_length_header,
550
+ "url": url,
551
+ "correlation_id": str(correlation_id),
552
+ },
553
+ )
554
+ return
555
+
556
+ if content_length > self._max_response_size:
557
+ ctx = ModelInfraErrorContext(
558
+ transport_type=EnumInfraTransportType.HTTP,
559
+ operation="validate_content_length",
560
+ target_name=url,
561
+ correlation_id=correlation_id,
562
+ )
563
+ raise InfraUnavailableError(
564
+ f"Response Content-Length ({_categorize_size(content_length)}) exceeds configured limit",
565
+ context=ctx,
566
+ )
567
+
568
+ logger.debug(
569
+ "Content-Length header validated",
570
+ extra={
571
+ "content_length_category": _categorize_size(content_length),
572
+ "limit": self._max_response_size,
573
+ "url": url,
574
+ "correlation_id": str(correlation_id),
575
+ },
576
+ )
577
+
578
+ async def _read_response_body_with_limit(
579
+ self, response: httpx.Response, url: str, correlation_id: UUID
580
+ ) -> bytes:
581
+ """Read response body with streaming size limit enforcement.
582
+
583
+ For responses without Content-Length header (e.g., chunked transfer encoding),
584
+ this method reads the body in chunks and tracks the total size, stopping
585
+ and raising an error if the limit is exceeded.
586
+
587
+ Security Note: This method provides DoS protection for chunked transfer
588
+ encoding responses where Content-Length is not available for pre-read
589
+ validation. By enforcing limits during streaming, we prevent memory
590
+ exhaustion attacks from maliciously large chunked responses.
591
+
592
+ Args:
593
+ response: The httpx Response object
594
+ url: Target URL for error context
595
+ correlation_id: Correlation ID for error context
596
+
597
+ Returns:
598
+ The complete response body as bytes
599
+
600
+ Raises:
601
+ InfraUnavailableError: If body size exceeds max_response_size during streaming.
602
+ """
603
+ chunks: list[bytes] = []
604
+ total_size: int = 0
605
+
606
+ async for chunk in response.aiter_bytes(chunk_size=_STREAMING_CHUNK_SIZE):
607
+ total_size += len(chunk)
608
+ if total_size > self._max_response_size:
609
+ logger.warning(
610
+ "Response body exceeded size limit during streaming read",
611
+ extra={
612
+ "size_category": _categorize_size(total_size),
613
+ "limit": self._max_response_size,
614
+ "url": url,
615
+ "correlation_id": str(correlation_id),
616
+ },
617
+ )
618
+ ctx = ModelInfraErrorContext(
619
+ transport_type=EnumInfraTransportType.HTTP,
620
+ operation="read_response_body",
621
+ target_name=url,
622
+ correlation_id=correlation_id,
623
+ )
624
+ raise InfraUnavailableError(
625
+ f"Response body size ({_categorize_size(total_size)}) exceeds configured limit during streaming read",
626
+ context=ctx,
627
+ )
628
+ chunks.append(chunk)
629
+
630
+ return b"".join(chunks)
631
+
632
+ def _prepare_request_content(
633
+ self,
634
+ method: str,
635
+ headers: dict[str, str],
636
+ body_content: ModelHttpBodyContent,
637
+ ctx: ModelInfraErrorContext,
638
+ ) -> tuple[bytes | str | None, dict[str, object] | None, dict[str, str]]:
639
+ """Prepare request content for HTTP request.
640
+
641
+ Handles body serialization for POST requests, managing pre-serialized bytes
642
+ from size validation and various body types (dict, str, other JSON-serializable).
643
+
644
+ Args:
645
+ method: HTTP method (GET, POST)
646
+ headers: Request headers (will be copied, not mutated)
647
+ body_content: Model containing body and optional pre-serialized bytes
648
+ ctx: Error context for exceptions
649
+
650
+ Returns:
651
+ Tuple of (request_content, request_json, request_headers):
652
+ - request_content: bytes or str content for the request
653
+ - request_json: dict for httpx json= parameter (mutually exclusive with content)
654
+ - request_headers: Headers dict (possibly with Content-Type added)
655
+
656
+ Raises:
657
+ ProtocolConfigurationError: If body is not JSON-serializable.
658
+ """
659
+ request_content: bytes | str | None = None
660
+ request_json: dict[str, object] | None = None
661
+ request_headers = dict(headers) # Copy to avoid mutating caller's headers
662
+
663
+ body = body_content.body
664
+ pre_serialized = body_content.pre_serialized
665
+
666
+ if method != "POST" or body is None:
667
+ return request_content, request_json, request_headers
668
+
669
+ if pre_serialized is not None:
670
+ # Use pre-serialized bytes from _validate_request_size to avoid
671
+ # double serialization. Set Content-Type header since we're using
672
+ # content= instead of json= parameter.
673
+ request_content = pre_serialized
674
+ if "content-type" not in {k.lower() for k in request_headers}:
675
+ request_headers["Content-Type"] = "application/json"
676
+ elif isinstance(body, dict):
677
+ # Fallback for dict bodies without pre-serialized content
678
+ # (shouldn't happen in normal flow, but handles edge cases)
679
+ request_json = body
680
+ elif isinstance(body, str):
681
+ request_content = body
682
+ else:
683
+ try:
684
+ request_content = json.dumps(body)
685
+ except TypeError as e:
686
+ raise ProtocolConfigurationError(
687
+ f"Body is not JSON-serializable: {type(body).__name__}",
688
+ context=ctx,
689
+ ) from e
690
+
691
+ return request_content, request_json, request_headers
692
+
693
+ async def _execute_request(
694
+ self,
695
+ method: str,
696
+ url: str,
697
+ headers: dict[str, str],
698
+ body: object,
699
+ correlation_id: UUID,
700
+ input_envelope_id: UUID,
701
+ pre_serialized: bytes | None = None,
702
+ ) -> ModelHandlerOutput[dict[str, object]]:
703
+ """Execute HTTP request with pre-read response size validation.
704
+
705
+ Uses httpx streaming to validate Content-Length header BEFORE reading
706
+ the response body into memory, preventing memory exhaustion attacks.
707
+
708
+ Args:
709
+ method: HTTP method (GET, POST)
710
+ url: Target URL
711
+ headers: Request headers
712
+ body: Request body (used only if pre_serialized is None)
713
+ correlation_id: Correlation ID for tracing
714
+ input_envelope_id: Envelope ID for causality tracking
715
+ pre_serialized: Pre-serialized JSON bytes for dict bodies (from
716
+ _validate_request_size). When provided, this is used directly
717
+ instead of re-serializing the body, avoiding double serialization.
718
+
719
+ Returns:
720
+ ModelHandlerOutput[dict[str, object]] with wrapped response data
721
+ """
722
+ if self._client is None:
723
+ ctx = ModelInfraErrorContext(
724
+ transport_type=EnumInfraTransportType.HTTP,
725
+ operation=f"http.{method.lower()}",
726
+ target_name=url,
727
+ correlation_id=correlation_id,
728
+ )
729
+ raise RuntimeHostError(
730
+ "HandlerHttpRest not initialized - call initialize() first", context=ctx
731
+ )
732
+
733
+ ctx = ModelInfraErrorContext(
734
+ transport_type=EnumInfraTransportType.HTTP,
735
+ operation=f"http.{method.lower()}",
736
+ target_name=url,
737
+ correlation_id=correlation_id,
738
+ )
739
+
740
+ # Prepare request content for POST
741
+ body_content = ModelHttpBodyContent(body=body, pre_serialized=pre_serialized)
742
+ request_content, request_json, request_headers = self._prepare_request_content(
743
+ method, headers, body_content, ctx
744
+ )
745
+
746
+ try:
747
+ # Use streaming request to get response headers before reading body
748
+ # This allows us to check Content-Length before loading body into memory
749
+ async with self._client.stream(
750
+ method,
751
+ url,
752
+ headers=request_headers,
753
+ content=request_content,
754
+ json=request_json,
755
+ ) as response:
756
+ # CRITICAL: Validate Content-Length header BEFORE reading body
757
+ # This prevents memory exhaustion from large responses
758
+ self._validate_content_length_header(response, url, correlation_id)
759
+
760
+ # Read body with streaming size limit enforcement
761
+ # For responses without Content-Length, this stops early if limit exceeded
762
+ response_body_bytes = await self._read_response_body_with_limit(
763
+ response, url, correlation_id
764
+ )
765
+
766
+ return self._build_response_from_bytes(
767
+ response, response_body_bytes, correlation_id, input_envelope_id
768
+ )
769
+
770
+ except httpx.TimeoutException as e:
771
+ timeout_ctx = ModelTimeoutErrorContext(
772
+ transport_type=EnumInfraTransportType.HTTP,
773
+ operation=f"http.{method.lower()}",
774
+ target_name=url,
775
+ correlation_id=correlation_id,
776
+ timeout_seconds=self._timeout,
777
+ )
778
+ raise InfraTimeoutError(
779
+ f"HTTP {method} request timed out after {self._timeout}s",
780
+ context=timeout_ctx,
781
+ ) from e
782
+ except httpx.ConnectError as e:
783
+ raise InfraConnectionError(
784
+ f"Failed to connect to {url}", context=ctx
785
+ ) from e
786
+ except httpx.HTTPError as e:
787
+ raise InfraConnectionError(
788
+ f"HTTP error during {method} request: {type(e).__name__}", context=ctx
789
+ ) from e
790
+
791
+ def _build_response_from_bytes(
792
+ self,
793
+ response: httpx.Response,
794
+ body_bytes: bytes,
795
+ correlation_id: UUID,
796
+ input_envelope_id: UUID,
797
+ ) -> ModelHandlerOutput[dict[str, object]]:
798
+ """Build response envelope from httpx Response and pre-read body bytes.
799
+
800
+ This method is used with streaming responses where the body has already
801
+ been read with size limit enforcement.
802
+
803
+ Args:
804
+ response: The httpx Response object (headers already available)
805
+ body_bytes: The pre-read response body bytes
806
+ correlation_id: Correlation ID for tracing
807
+ input_envelope_id: Envelope ID for causality tracking
808
+
809
+ Returns:
810
+ ModelHandlerOutput wrapping response dict with status, payload, and correlation_id
811
+ """
812
+ content_type = response.headers.get("content-type", "")
813
+ body: object
814
+
815
+ # TODO(OMN-43): When rate limiting is implemented, extract and log rate limit
816
+ # response headers: x-ratelimit-remaining, x-ratelimit-limit, x-ratelimit-reset
817
+ # These headers will be added to the debug log metadata below for observability.
818
+
819
+ logger.debug(
820
+ "Response body received",
821
+ extra={
822
+ "body_size": len(body_bytes),
823
+ "size_utilization_pct": round(
824
+ (len(body_bytes) / self._max_response_size) * 100, 2
825
+ ),
826
+ "content_type": content_type,
827
+ "status_code": response.status_code,
828
+ "correlation_id": str(correlation_id),
829
+ # TODO(OMN-43): Add rate limit metadata here when rate limiting is implemented:
830
+ # "ratelimit_remaining": response.headers.get("x-ratelimit-remaining"),
831
+ # "ratelimit_limit": response.headers.get("x-ratelimit-limit"),
832
+ # "ratelimit_reset": response.headers.get("x-ratelimit-reset"),
833
+ },
834
+ )
835
+
836
+ # Decode bytes to string first
837
+ try:
838
+ body_text = body_bytes.decode("utf-8")
839
+ except UnicodeDecodeError:
840
+ # If UTF-8 decoding fails, try latin-1 as fallback
841
+ body_text = body_bytes.decode("latin-1")
842
+
843
+ # Try to parse as JSON if content type indicates JSON
844
+ if "application/json" in content_type:
845
+ try:
846
+ body = json.loads(body_text)
847
+ except json.JSONDecodeError:
848
+ body = body_text
849
+ else:
850
+ body = body_text
851
+
852
+ return ModelHandlerOutput.for_compute(
853
+ input_envelope_id=input_envelope_id,
854
+ correlation_id=correlation_id,
855
+ handler_id=HANDLER_ID_HTTP,
856
+ result={
857
+ "status": "success",
858
+ "payload": {
859
+ "status_code": response.status_code,
860
+ "headers": dict(response.headers),
861
+ "body": body,
862
+ },
863
+ "correlation_id": str(correlation_id),
864
+ },
865
+ )
866
+
867
+ def describe(self) -> dict[str, object]:
868
+ """Return handler metadata and capabilities for introspection.
869
+
870
+ This method exposes the handler's three-dimensional type classification
871
+ along with its operational configuration and capabilities.
872
+
873
+ Returns:
874
+ dict containing:
875
+ - handler_type: Architectural role from handler_type property
876
+ (e.g., "infra_handler"). See EnumHandlerType for valid values.
877
+ - handler_category: Behavioral classification from handler_category
878
+ property (e.g., "effect"). See EnumHandlerTypeCategory for valid values.
879
+ - transport_type: Protocol identifier from transport_type property
880
+ (e.g., "http"). See EnumInfraTransportType for valid values.
881
+ - supported_operations: List of supported operations
882
+ - timeout_seconds: Request timeout in seconds
883
+ - max_request_size: Maximum request body size in bytes
884
+ - max_response_size: Maximum response body size in bytes
885
+ - initialized: Whether the handler is initialized
886
+ - version: Handler version string
887
+
888
+ Note:
889
+ The handler_type, handler_category, and transport_type fields form the
890
+ three-dimensional handler classification system:
891
+
892
+ 1. handler_type (architectural role): Determines lifecycle and invocation
893
+ patterns. This handler is INFRA_HANDLER (protocol/transport handler).
894
+
895
+ 2. handler_category (behavioral classification): Determines security rules
896
+ and replay safety. This handler is EFFECT (side-effecting I/O).
897
+
898
+ 3. transport_type (protocol identifier): Identifies the specific transport.
899
+ This handler uses HTTP protocol.
900
+
901
+ See Also:
902
+ - handler_type property: Full documentation of architectural role
903
+ - handler_category property: Full documentation of behavioral classification
904
+ - transport_type property: Full documentation of transport identifier
905
+ - docs/architecture/HANDLER_PROTOCOL_DRIVEN_ARCHITECTURE.md
906
+ """
907
+ return {
908
+ "handler_type": self.handler_type.value,
909
+ "handler_category": self.handler_category.value,
910
+ "transport_type": self.transport_type.value,
911
+ "supported_operations": sorted(_SUPPORTED_OPERATIONS),
912
+ "timeout_seconds": self._timeout,
913
+ "max_request_size": self._max_request_size,
914
+ "max_response_size": self._max_response_size,
915
+ "initialized": self._initialized,
916
+ "version": "0.1.0-mvp",
917
+ }
918
+
919
+
920
+ __all__: list[str] = ["HandlerHttpRest"]