omnibase_infra 0.2.6__py3-none-any.whl

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