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,1046 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2025 OmniNode Team
3
+ """PostgreSQL Database Handler - MVP implementation using asyncpg async client.
4
+
5
+ Supports query and execute operations with fixed pool size (5).
6
+ Transaction support deferred to Beta. Configurable pool size deferred to Beta.
7
+
8
+ All queries MUST use parameterized statements for SQL injection protection.
9
+
10
+ Envelope-Based Routing:
11
+ This handler uses envelope-based operation routing. See CLAUDE.md section
12
+ "Intent Model Architecture > Envelope-Based Handler Routing" for the full
13
+ design pattern and how orchestrators translate intents to handler envelopes.
14
+
15
+ Single-Statement SQL Limitation
16
+ ===============================
17
+
18
+ This handler uses asyncpg's ``execute()`` and ``fetch()`` methods, which only
19
+ support **single SQL statements per call**. Multi-statement SQL (statements
20
+ separated by semicolons) is NOT supported and will raise an error.
21
+
22
+ **Example - Incorrect (will fail):**
23
+
24
+ .. code-block:: python
25
+
26
+ # This will fail - multiple statements in one call
27
+ envelope = {
28
+ "operation": "db.execute",
29
+ "payload": {
30
+ "sql": "CREATE TABLE foo (id INT); INSERT INTO foo VALUES (1);",
31
+ "parameters": [],
32
+ },
33
+ }
34
+
35
+ **Example - Correct (split into separate calls):**
36
+
37
+ .. code-block:: python
38
+
39
+ # Execute each statement separately
40
+ create_envelope = {
41
+ "operation": "db.execute",
42
+ "payload": {"sql": "CREATE TABLE foo (id INT)", "parameters": []},
43
+ }
44
+ await handler.execute(create_envelope)
45
+
46
+ insert_envelope = {
47
+ "operation": "db.execute",
48
+ "payload": {"sql": "INSERT INTO foo VALUES (1)", "parameters": []},
49
+ }
50
+ await handler.execute(insert_envelope)
51
+
52
+ This is a deliberate design choice for security and clarity:
53
+ 1. Prevents SQL injection through statement concatenation
54
+ 2. Provides clear error attribution per statement
55
+ 3. Enables proper row count tracking per operation
56
+ 4. Aligns with asyncpg's native API design
57
+
58
+ For multi-statement operations requiring atomicity, use the ``db.transaction``
59
+ operation (planned for Beta release).
60
+
61
+ Note:
62
+ Environment variable configuration (ONEX_DB_POOL_SIZE, ONEX_DB_TIMEOUT) is parsed
63
+ at module import time, not at handler instantiation. This means:
64
+
65
+ - Changes to environment variables require application restart to take effect
66
+ - Tests should use ``unittest.mock.patch.dict(os.environ, ...)`` before importing,
67
+ or use ``importlib.reload()`` to re-import the module after patching
68
+ - This is an intentional design choice for startup-time validation
69
+ """
70
+
71
+ from __future__ import annotations
72
+
73
+ import logging
74
+ from uuid import UUID, uuid4
75
+
76
+ import asyncpg
77
+
78
+ from omnibase_core.container import ModelONEXContainer
79
+ from omnibase_core.models.dispatch import ModelHandlerOutput
80
+ from omnibase_core.types import JsonType
81
+ from omnibase_infra.enums import (
82
+ EnumHandlerType,
83
+ EnumHandlerTypeCategory,
84
+ EnumInfraTransportType,
85
+ EnumResponseStatus,
86
+ )
87
+ from omnibase_infra.errors import (
88
+ InfraAuthenticationError,
89
+ InfraConnectionError,
90
+ InfraTimeoutError,
91
+ ModelInfraErrorContext,
92
+ ModelTimeoutErrorContext,
93
+ RuntimeHostError,
94
+ )
95
+ from omnibase_infra.handlers.models import (
96
+ ModelDbDescribeResponse,
97
+ ModelDbQueryPayload,
98
+ ModelDbQueryResponse,
99
+ )
100
+ from omnibase_infra.mixins import MixinAsyncCircuitBreaker, MixinEnvelopeExtraction
101
+ from omnibase_infra.utils.util_env_parsing import parse_env_float, parse_env_int
102
+
103
+ logger = logging.getLogger(__name__)
104
+
105
+ # MVP pool size fixed at 5 connections.
106
+ # Note: Recommended range is 10-20 for production workloads.
107
+ # Configurable pool size deferred to Beta release.
108
+ _DEFAULT_POOL_SIZE: int = parse_env_int(
109
+ "ONEX_DB_POOL_SIZE",
110
+ 5,
111
+ min_value=1,
112
+ max_value=100,
113
+ transport_type=EnumInfraTransportType.DATABASE,
114
+ service_name="db_handler",
115
+ )
116
+
117
+ # Handler ID for ModelHandlerOutput
118
+ HANDLER_ID_DB: str = "db-handler"
119
+ _DEFAULT_TIMEOUT_SECONDS: float = parse_env_float(
120
+ "ONEX_DB_TIMEOUT",
121
+ 30.0,
122
+ min_value=0.1,
123
+ max_value=3600.0,
124
+ transport_type=EnumInfraTransportType.DATABASE,
125
+ service_name="db_handler",
126
+ )
127
+ _SUPPORTED_OPERATIONS: frozenset[str] = frozenset({"db.query", "db.execute"})
128
+
129
+ # Error message prefixes for PostgreSQL errors
130
+ # Used by _map_postgres_error to build descriptive error messages
131
+ _POSTGRES_ERROR_PREFIXES: dict[type[asyncpg.PostgresError], str] = {
132
+ asyncpg.PostgresSyntaxError: "SQL syntax error",
133
+ asyncpg.UndefinedTableError: "Table not found",
134
+ asyncpg.UndefinedColumnError: "Column not found",
135
+ asyncpg.UniqueViolationError: "Unique constraint violation",
136
+ asyncpg.ForeignKeyViolationError: "Foreign key constraint violation",
137
+ asyncpg.NotNullViolationError: "Not null constraint violation",
138
+ asyncpg.CheckViolationError: "Check constraint violation",
139
+ }
140
+
141
+ # PostgreSQL SQLSTATE class codes for error classification
142
+ # See: https://www.postgresql.org/docs/current/errcodes-appendix.html
143
+ #
144
+ # TRANSIENT errors (should trip circuit breaker):
145
+ # - Class 08: Connection Exception (database unreachable, connection lost)
146
+ # - Class 53: Insufficient Resources (out of memory, disk full, too many connections)
147
+ # - Class 57: Operator Intervention (admin shutdown, crash recovery, cannot connect now)
148
+ # - Class 58: System Error (I/O error, undefined file, duplicate file)
149
+ #
150
+ # PERMANENT errors (should NOT trip circuit breaker):
151
+ # - Class 23: Integrity Constraint Violation (FK, NOT NULL, unique, check)
152
+ # - Class 42: Syntax Error or Access Rule Violation (bad SQL, undefined table/column)
153
+ # - Class 28: Invalid Authorization Specification (bad credentials)
154
+ # - Class 22: Data Exception (division by zero, string data truncation)
155
+ # - Class 40: Transaction Rollback (serialization failure, deadlock detected)
156
+ #
157
+ # DESIGN DECISION: Classified as PERMANENT despite deadlocks being retry-able.
158
+ #
159
+ # Rationale:
160
+ # 1. Deadlocks indicate transaction contention, not infrastructure failure
161
+ # 2. The database is healthy - it correctly detected and resolved the deadlock
162
+ # 3. Retrying at application level (with backoff) typically succeeds
163
+ # 4. Tripping the circuit would block ALL queries, not just the conflicting ones
164
+ # 5. High deadlock rates indicate application design issues (lock ordering,
165
+ # transaction scope) that should be fixed in code, not masked by circuit breaker
166
+ #
167
+ # Note: If sustained deadlock storms occur, this is a symptom of application
168
+ # issues or schema contention that monitoring/alerting should surface, but
169
+ # the circuit breaker is not the right mitigation tool.
170
+ #
171
+ # The key insight: transient errors indicate the DATABASE INFRASTRUCTURE is unhealthy,
172
+ # while permanent errors indicate the QUERY/APPLICATION is invalid. The circuit breaker
173
+ # protects against infrastructure failures, not application bugs.
174
+ _TRANSIENT_SQLSTATE_CLASSES: frozenset[str] = frozenset({"08", "53", "57", "58"})
175
+ _PERMANENT_SQLSTATE_CLASSES: frozenset[str] = frozenset({"22", "23", "28", "42"})
176
+
177
+
178
+ class HandlerDb(MixinAsyncCircuitBreaker, MixinEnvelopeExtraction):
179
+ """PostgreSQL database handler using asyncpg connection pool (MVP: query, execute only).
180
+
181
+ Security Policy - DSN Handling:
182
+ The database connection string (DSN) contains sensitive credentials and is
183
+ treated as a secret throughout this handler. The following security measures
184
+ are enforced:
185
+
186
+ 1. DSN is stored internally in ``_dsn`` but NEVER logged or exposed in errors
187
+ 2. All error messages use generic descriptions (e.g., "check host and port")
188
+ rather than exposing connection details
189
+ 3. The ``_sanitize_dsn()`` method is available if DSN info ever needs to be
190
+ logged for debugging, but should only be used in development environments
191
+ 4. The ``describe()`` method returns capabilities without credentials
192
+
193
+ See CLAUDE.md "Error Sanitization Guidelines" for the full security policy
194
+ on what information is safe vs unsafe to include in errors and logs.
195
+
196
+ Production Database Safety:
197
+ When connecting to production databases, ensure the following safeguards:
198
+
199
+ 1. **Use read-only credentials** when possible to prevent accidental mutations
200
+ 2. **Connection isolation**: Use separate DSNs for read and write operations
201
+ 3. **Query timeouts**: Configure appropriate timeouts to prevent long-running
202
+ queries from exhausting connection pools (default: 30 seconds)
203
+ 4. **Pool limits**: Production workloads should use 10-20 connections
204
+ (currently fixed at 5 for MVP - see Beta roadmap)
205
+ 5. **SSL/TLS**: Always use encrypted connections (sslmode=require/verify-full)
206
+ 6. **Audit logging**: Enable PostgreSQL statement logging for compliance
207
+ 7. **Connection pooling**: Consider PgBouncer for high-traffic scenarios
208
+
209
+ WARNING: This handler executes arbitrary SQL. Ensure all queries use
210
+ parameterized statements to prevent SQL injection. Multi-statement SQL
211
+ is intentionally blocked for security.
212
+
213
+ Circuit Breaker:
214
+ This handler uses MixinAsyncCircuitBreaker for connection resilience.
215
+ The circuit breaker is initialized after the connection pool is created
216
+ in the initialize() method. Only connection-related errors (PostgresConnectionError,
217
+ QueryCanceledError) trip the circuit - application errors (syntax errors,
218
+ missing tables/columns) do not affect the circuit state.
219
+
220
+ States:
221
+ - CLOSED: Normal operation, requests allowed
222
+ - OPEN: Circuit tripped after threshold failures, requests blocked
223
+ - HALF_OPEN: Testing recovery after reset timeout, limited requests allowed
224
+ """
225
+
226
+ def __init__(self, container: ModelONEXContainer) -> None:
227
+ """Initialize HandlerDb with ONEX container for dependency injection.
228
+
229
+ Args:
230
+ container: ONEX container for dependency injection.
231
+ """
232
+ self._container = container
233
+ self._pool: asyncpg.Pool | None = None
234
+ self._pool_size: int = _DEFAULT_POOL_SIZE
235
+ self._timeout: float = _DEFAULT_TIMEOUT_SECONDS
236
+ self._initialized: bool = False
237
+ self._dsn: str = ""
238
+ self._circuit_breaker_initialized: bool = False
239
+
240
+ @property
241
+ def handler_type(self) -> EnumHandlerType:
242
+ """Return the architectural role of this handler.
243
+
244
+ Returns:
245
+ EnumHandlerType.INFRA_HANDLER - This handler is an infrastructure
246
+ protocol/transport handler (as opposed to NODE_HANDLER for event
247
+ processing, PROJECTION_HANDLER for read models, or COMPUTE_HANDLER
248
+ for pure computation).
249
+
250
+ Note:
251
+ handler_type determines lifecycle, protocol selection, and runtime
252
+ invocation patterns. It answers "what is this handler in the architecture?"
253
+
254
+ See Also:
255
+ - handler_category: Behavioral classification (EFFECT/COMPUTE)
256
+ - docs/architecture/HANDLER_PROTOCOL_DRIVEN_ARCHITECTURE.md
257
+ """
258
+ return EnumHandlerType.INFRA_HANDLER
259
+
260
+ @property
261
+ def handler_category(self) -> EnumHandlerTypeCategory:
262
+ """Return the behavioral classification of this handler.
263
+
264
+ Returns:
265
+ EnumHandlerTypeCategory.EFFECT - This handler performs side-effecting
266
+ I/O operations (database queries and mutations). EFFECT handlers are
267
+ not deterministic and interact with external systems.
268
+
269
+ Note:
270
+ handler_category determines security rules, determinism guarantees,
271
+ replay safety, and permissions. It answers "how does this handler
272
+ behave at runtime?"
273
+
274
+ Categories:
275
+ - COMPUTE: Pure, deterministic transformations (no side effects)
276
+ - EFFECT: Side-effecting I/O (database, HTTP, service calls)
277
+ - NONDETERMINISTIC_COMPUTE: Pure but not deterministic (UUID, random)
278
+
279
+ See Also:
280
+ - handler_type: Architectural role (INFRA_HANDLER/NODE_HANDLER/etc.)
281
+ - docs/architecture/HANDLER_PROTOCOL_DRIVEN_ARCHITECTURE.md
282
+ """
283
+ return EnumHandlerTypeCategory.EFFECT
284
+
285
+ async def initialize(self, config: dict[str, object]) -> None:
286
+ """Initialize database connection pool with fixed size (5).
287
+
288
+ Args:
289
+ config: Configuration dict containing:
290
+ - dsn: PostgreSQL connection string (required)
291
+ - timeout: Optional timeout in seconds (default: 30.0)
292
+
293
+ Raises:
294
+ RuntimeHostError: If DSN is missing or pool creation fails.
295
+ """
296
+ # Generate correlation_id for initialization tracing
297
+ init_correlation_id = uuid4()
298
+
299
+ logger.info(
300
+ "Initializing %s",
301
+ self.__class__.__name__,
302
+ extra={
303
+ "handler": self.__class__.__name__,
304
+ "correlation_id": str(init_correlation_id),
305
+ },
306
+ )
307
+
308
+ dsn = config.get("dsn")
309
+ if not isinstance(dsn, str) or not dsn:
310
+ ctx = ModelInfraErrorContext(
311
+ transport_type=EnumInfraTransportType.DATABASE,
312
+ operation="initialize",
313
+ target_name="db_handler",
314
+ correlation_id=init_correlation_id,
315
+ )
316
+ raise RuntimeHostError(
317
+ "Missing or invalid 'dsn' in config - PostgreSQL connection string required",
318
+ context=ctx,
319
+ )
320
+
321
+ timeout_raw = config.get("timeout", _DEFAULT_TIMEOUT_SECONDS)
322
+ if isinstance(timeout_raw, int | float):
323
+ self._timeout = float(timeout_raw)
324
+
325
+ try:
326
+ self._pool = await asyncpg.create_pool(
327
+ dsn=dsn,
328
+ min_size=1,
329
+ max_size=self._pool_size,
330
+ command_timeout=self._timeout,
331
+ )
332
+ self._dsn = dsn
333
+ # Note: DSN stored internally but never logged or exposed in errors.
334
+ # Use _sanitize_dsn() if DSN info ever needs to be logged.
335
+ self._initialized = True
336
+
337
+ # Initialize circuit breaker after pool creation succeeds
338
+ self._init_circuit_breaker(
339
+ threshold=5,
340
+ reset_timeout=30.0,
341
+ service_name="db_handler",
342
+ transport_type=EnumInfraTransportType.DATABASE,
343
+ )
344
+ self._circuit_breaker_initialized = True
345
+
346
+ logger.info(
347
+ "%s initialized successfully",
348
+ self.__class__.__name__,
349
+ extra={
350
+ "handler": self.__class__.__name__,
351
+ "pool_min_size": 1,
352
+ "pool_max_size": self._pool_size,
353
+ "timeout_seconds": self._timeout,
354
+ "correlation_id": str(init_correlation_id),
355
+ },
356
+ )
357
+ except asyncpg.InvalidPasswordError as e:
358
+ ctx = ModelInfraErrorContext(
359
+ transport_type=EnumInfraTransportType.DATABASE,
360
+ operation="initialize",
361
+ target_name="db_handler",
362
+ correlation_id=init_correlation_id,
363
+ )
364
+ raise InfraAuthenticationError(
365
+ "Database authentication failed - check credentials", context=ctx
366
+ ) from e
367
+ except asyncpg.InvalidCatalogNameError as e:
368
+ ctx = ModelInfraErrorContext(
369
+ transport_type=EnumInfraTransportType.DATABASE,
370
+ operation="initialize",
371
+ target_name="db_handler",
372
+ correlation_id=init_correlation_id,
373
+ )
374
+ raise RuntimeHostError(
375
+ "Database not found - check database name", context=ctx
376
+ ) from e
377
+ except OSError as e:
378
+ ctx = ModelInfraErrorContext(
379
+ transport_type=EnumInfraTransportType.DATABASE,
380
+ operation="initialize",
381
+ target_name="db_handler",
382
+ correlation_id=init_correlation_id,
383
+ )
384
+ raise InfraConnectionError(
385
+ "Failed to connect to database - check host and port", context=ctx
386
+ ) from e
387
+ except Exception as e:
388
+ ctx = ModelInfraErrorContext(
389
+ transport_type=EnumInfraTransportType.DATABASE,
390
+ operation="initialize",
391
+ target_name="db_handler",
392
+ correlation_id=init_correlation_id,
393
+ )
394
+ raise RuntimeHostError(
395
+ f"Failed to initialize database pool: {type(e).__name__}", context=ctx
396
+ ) from e
397
+
398
+ async def shutdown(self) -> None:
399
+ """Close database connection pool and release resources."""
400
+ # Reset circuit breaker state
401
+ if self._circuit_breaker_initialized:
402
+ async with self._circuit_breaker_lock:
403
+ await self._reset_circuit_breaker()
404
+ self._circuit_breaker_initialized = False
405
+
406
+ if self._pool is not None:
407
+ await self._pool.close()
408
+ self._pool = None
409
+ self._initialized = False
410
+ logger.info("HandlerDb shutdown complete")
411
+
412
+ async def execute(
413
+ self, envelope: dict[str, object]
414
+ ) -> ModelHandlerOutput[ModelDbQueryResponse]:
415
+ """Execute database operation (db.query or db.execute) from envelope.
416
+
417
+ Args:
418
+ envelope: Request envelope containing:
419
+ - operation: "db.query" or "db.execute"
420
+ - payload: dict with "sql" (required) and "parameters" (optional list)
421
+ - correlation_id: Optional correlation ID for tracing
422
+ - envelope_id: Optional envelope ID for causality tracking
423
+
424
+ Returns:
425
+ ModelHandlerOutput[ModelDbQueryResponse] containing:
426
+ - result: ModelDbQueryResponse with status, payload, and correlation_id
427
+ - input_envelope_id: UUID for causality tracking
428
+ - correlation_id: UUID for request/response correlation
429
+ - handler_id: "db-handler"
430
+
431
+ Raises:
432
+ RuntimeHostError: If handler not initialized or invalid input.
433
+ InfraConnectionError: If database connection fails.
434
+ InfraTimeoutError: If query times out.
435
+ """
436
+ correlation_id = self._extract_correlation_id(envelope)
437
+ input_envelope_id = self._extract_envelope_id(envelope)
438
+
439
+ if not self._initialized or self._pool is None:
440
+ ctx = ModelInfraErrorContext(
441
+ transport_type=EnumInfraTransportType.DATABASE,
442
+ operation="execute",
443
+ target_name="db_handler",
444
+ correlation_id=correlation_id,
445
+ )
446
+ raise RuntimeHostError(
447
+ "HandlerDb not initialized. Call initialize() first.", context=ctx
448
+ )
449
+
450
+ operation = envelope.get("operation")
451
+ if not isinstance(operation, str):
452
+ ctx = ModelInfraErrorContext(
453
+ transport_type=EnumInfraTransportType.DATABASE,
454
+ operation="execute",
455
+ target_name="db_handler",
456
+ correlation_id=correlation_id,
457
+ )
458
+ raise RuntimeHostError(
459
+ "Missing or invalid 'operation' in envelope", context=ctx
460
+ )
461
+
462
+ if operation not in _SUPPORTED_OPERATIONS:
463
+ ctx = ModelInfraErrorContext(
464
+ transport_type=EnumInfraTransportType.DATABASE,
465
+ operation=operation,
466
+ target_name="db_handler",
467
+ correlation_id=correlation_id,
468
+ )
469
+ raise RuntimeHostError(
470
+ f"Operation '{operation}' not supported in MVP. Available: {', '.join(sorted(_SUPPORTED_OPERATIONS))}",
471
+ context=ctx,
472
+ )
473
+
474
+ payload = envelope.get("payload")
475
+ if not isinstance(payload, dict):
476
+ ctx = ModelInfraErrorContext(
477
+ transport_type=EnumInfraTransportType.DATABASE,
478
+ operation=operation,
479
+ target_name="db_handler",
480
+ correlation_id=correlation_id,
481
+ )
482
+ raise RuntimeHostError(
483
+ "Missing or invalid 'payload' in envelope", context=ctx
484
+ )
485
+
486
+ sql = payload.get("sql")
487
+ if not isinstance(sql, str) or not sql.strip():
488
+ ctx = ModelInfraErrorContext(
489
+ transport_type=EnumInfraTransportType.DATABASE,
490
+ operation=operation,
491
+ target_name="db_handler",
492
+ correlation_id=correlation_id,
493
+ )
494
+ raise RuntimeHostError("Missing or invalid 'sql' in payload", context=ctx)
495
+
496
+ parameters = self._extract_parameters(payload, operation, correlation_id)
497
+
498
+ if operation == "db.query":
499
+ return await self._execute_query(
500
+ sql, parameters, correlation_id, input_envelope_id
501
+ )
502
+ else: # db.execute
503
+ return await self._execute_statement(
504
+ sql, parameters, correlation_id, input_envelope_id
505
+ )
506
+
507
+ def _sanitize_dsn(self, dsn: str) -> str:
508
+ """Sanitize DSN by removing password for safe logging.
509
+
510
+ SECURITY: This method exists to support debugging scenarios where
511
+ connection information may be helpful, while ensuring credentials
512
+ are never exposed. The raw DSN should NEVER be logged directly.
513
+
514
+ Uses urllib.parse for robust parsing instead of regex, handling
515
+ edge cases like IPv6 addresses and URL-encoded passwords.
516
+
517
+ Args:
518
+ dsn: Raw PostgreSQL connection string containing credentials.
519
+
520
+ Returns:
521
+ Sanitized DSN with password replaced by '***'.
522
+
523
+ Example:
524
+ >>> handler._sanitize_dsn("postgresql://user:secret@host:5432/db")
525
+ 'postgresql://user:***@host:5432/db'
526
+
527
+ >>> handler._sanitize_dsn("postgresql://user:p%40ss@[::1]:5432/db")
528
+ 'postgresql://user:***@[::1]:5432/db'
529
+
530
+ Note:
531
+ This method is intentionally NOT used in production error paths.
532
+ It exists as a utility for development/debugging only. See class
533
+ docstring "Security Policy - DSN Handling" for full policy.
534
+ """
535
+ from omnibase_infra.utils.util_dsn_validation import sanitize_dsn
536
+
537
+ return sanitize_dsn(dsn)
538
+
539
+ def _extract_parameters(
540
+ self, payload: dict[str, object], operation: str, correlation_id: UUID
541
+ ) -> list[object]:
542
+ """Extract and validate parameters from payload."""
543
+ params_raw = payload.get("parameters")
544
+ if params_raw is None:
545
+ return []
546
+ if isinstance(params_raw, list):
547
+ return list(params_raw)
548
+ ctx = ModelInfraErrorContext(
549
+ transport_type=EnumInfraTransportType.DATABASE,
550
+ operation=operation,
551
+ target_name="db_handler",
552
+ correlation_id=correlation_id,
553
+ )
554
+ raise RuntimeHostError(
555
+ "Invalid 'parameters' in payload - must be a list", context=ctx
556
+ )
557
+
558
+ def _is_transient_error(self, error: asyncpg.PostgresError) -> bool:
559
+ """Determine if a PostgreSQL error is transient (should trip circuit breaker).
560
+
561
+ Transient errors indicate infrastructure issues where retrying later may succeed:
562
+ - Connection failures (Class 08)
563
+ - Resource exhaustion (Class 53)
564
+ - Server shutdown/restart (Class 57)
565
+ - System I/O errors (Class 58)
566
+
567
+ Permanent errors indicate application/query bugs that won't be fixed by retrying:
568
+ - Constraint violations (Class 23): FK, NOT NULL, unique, check
569
+ - Syntax errors (Class 42): bad SQL, undefined table/column
570
+ - Authorization failures (Class 28): invalid credentials
571
+ - Data exceptions (Class 22): division by zero, truncation
572
+
573
+ The circuit breaker ONLY trips on transient errors because:
574
+ 1. Transient errors suggest the database infrastructure is unhealthy
575
+ 2. Opening the circuit prevents cascading failures and gives the DB time to recover
576
+ 3. Permanent errors are application bugs that should be fixed in code, not retried
577
+
578
+ Args:
579
+ error: The asyncpg PostgresError exception to classify.
580
+
581
+ Returns:
582
+ True if the error is transient (should increment circuit breaker failure count),
583
+ False if the error is permanent (should NOT affect circuit breaker state).
584
+
585
+ Examples:
586
+ >>> # Connection lost - transient, should trip circuit
587
+ >>> handler._is_transient_error(asyncpg.PostgresConnectionError())
588
+ True
589
+
590
+ >>> # FK violation - permanent, should NOT trip circuit
591
+ >>> handler._is_transient_error(asyncpg.ForeignKeyViolationError())
592
+ False
593
+ """
594
+ # Get SQLSTATE code from exception (5-character code like '23503')
595
+ sqlstate = getattr(error, "sqlstate", None)
596
+
597
+ if sqlstate is None:
598
+ # No SQLSTATE available - fall back to exception type classification
599
+ # Connection-related errors are always transient
600
+ if isinstance(error, asyncpg.PostgresConnectionError):
601
+ return True
602
+ # Query canceled (timeout) is transient - indicates server overload
603
+ if isinstance(error, asyncpg.QueryCanceledError):
604
+ return True
605
+ # Default: assume permanent (don't trip circuit for unknown errors)
606
+ # This is conservative - we'd rather miss a transient error than
607
+ # incorrectly trip the circuit on application bugs
608
+ logger.debug(
609
+ "No SQLSTATE for PostgreSQL error, defaulting to permanent classification",
610
+ extra={
611
+ "error_type": type(error).__name__,
612
+ },
613
+ )
614
+ return False
615
+
616
+ # Extract class code (first 2 characters of SQLSTATE)
617
+ # e.g., '23503' -> '23' (Integrity Constraint Violation)
618
+ sqlstate_class = sqlstate[:2]
619
+
620
+ # Check if class is explicitly transient
621
+ if sqlstate_class in _TRANSIENT_SQLSTATE_CLASSES:
622
+ logger.debug(
623
+ "Classified PostgreSQL error as TRANSIENT (will trip circuit)",
624
+ extra={
625
+ "sqlstate": sqlstate,
626
+ "sqlstate_class": sqlstate_class,
627
+ "error_type": type(error).__name__,
628
+ },
629
+ )
630
+ return True
631
+
632
+ # Check if class is explicitly permanent
633
+ if sqlstate_class in _PERMANENT_SQLSTATE_CLASSES:
634
+ logger.debug(
635
+ "Classified PostgreSQL error as PERMANENT (will NOT trip circuit)",
636
+ extra={
637
+ "sqlstate": sqlstate,
638
+ "sqlstate_class": sqlstate_class,
639
+ "error_type": type(error).__name__,
640
+ },
641
+ )
642
+ return False
643
+
644
+ # Unknown class - log warning and default to permanent (conservative)
645
+ # Unknown errors are more likely to be application bugs than infrastructure issues
646
+ logger.warning(
647
+ "Unknown PostgreSQL SQLSTATE class, defaulting to permanent classification",
648
+ extra={
649
+ "sqlstate": sqlstate,
650
+ "sqlstate_class": sqlstate_class,
651
+ "error_type": type(error).__name__,
652
+ },
653
+ )
654
+ return False
655
+
656
+ async def _execute_query(
657
+ self,
658
+ sql: str,
659
+ parameters: list[object],
660
+ correlation_id: UUID,
661
+ input_envelope_id: UUID,
662
+ ) -> ModelHandlerOutput[ModelDbQueryResponse]:
663
+ """Execute SELECT query and return rows."""
664
+ if self._pool is None:
665
+ ctx = ModelInfraErrorContext(
666
+ transport_type=EnumInfraTransportType.DATABASE,
667
+ operation="db.query",
668
+ target_name="db_handler",
669
+ correlation_id=correlation_id,
670
+ )
671
+ raise RuntimeHostError(
672
+ "HandlerDb not initialized - call initialize() first", context=ctx
673
+ )
674
+
675
+ ctx = ModelInfraErrorContext(
676
+ transport_type=EnumInfraTransportType.DATABASE,
677
+ operation="db.query",
678
+ target_name="db_handler",
679
+ correlation_id=correlation_id,
680
+ )
681
+
682
+ # Check circuit breaker before operation
683
+ if self._circuit_breaker_initialized:
684
+ async with self._circuit_breaker_lock:
685
+ await self._check_circuit_breaker(
686
+ operation="db.query",
687
+ correlation_id=correlation_id,
688
+ )
689
+
690
+ try:
691
+ async with self._pool.acquire() as conn:
692
+ rows = await conn.fetch(sql, *parameters)
693
+
694
+ # Reset circuit breaker immediately after successful operation,
695
+ # within connection context to avoid race conditions
696
+ if self._circuit_breaker_initialized:
697
+ async with self._circuit_breaker_lock:
698
+ await self._reset_circuit_breaker()
699
+
700
+ return self._build_response(
701
+ [dict(row) for row in rows],
702
+ len(rows),
703
+ correlation_id,
704
+ input_envelope_id,
705
+ )
706
+ except asyncpg.QueryCanceledError as e:
707
+ # Record failure for timeout errors (database overloaded)
708
+ if self._circuit_breaker_initialized:
709
+ async with self._circuit_breaker_lock:
710
+ await self._record_circuit_failure(
711
+ operation="db.query",
712
+ correlation_id=correlation_id,
713
+ )
714
+ timeout_ctx = ModelTimeoutErrorContext(
715
+ transport_type=EnumInfraTransportType.DATABASE,
716
+ operation="db.query",
717
+ target_name="db_handler",
718
+ correlation_id=correlation_id,
719
+ timeout_seconds=self._timeout,
720
+ )
721
+ raise InfraTimeoutError(
722
+ f"Query timed out after {self._timeout}s",
723
+ context=timeout_ctx,
724
+ ) from e
725
+ except asyncpg.PostgresConnectionError as e:
726
+ # Record failure for connection errors (database unavailable)
727
+ if self._circuit_breaker_initialized:
728
+ async with self._circuit_breaker_lock:
729
+ await self._record_circuit_failure(
730
+ operation="db.query",
731
+ correlation_id=correlation_id,
732
+ )
733
+ raise InfraConnectionError(
734
+ "Database connection lost during query", context=ctx
735
+ ) from e
736
+ except asyncpg.PostgresSyntaxError as e:
737
+ # Application error - do NOT trip circuit
738
+ raise RuntimeHostError(f"SQL syntax error: {e.message}", context=ctx) from e
739
+ except asyncpg.UndefinedTableError as e:
740
+ # Application error - do NOT trip circuit
741
+ raise RuntimeHostError(f"Table not found: {e.message}", context=ctx) from e
742
+ except asyncpg.UndefinedColumnError as e:
743
+ # Application error - do NOT trip circuit
744
+ raise RuntimeHostError(f"Column not found: {e.message}", context=ctx) from e
745
+ except asyncpg.ForeignKeyViolationError as e:
746
+ # Application error - do NOT trip circuit
747
+ raise RuntimeHostError(
748
+ f"Foreign key constraint violation: {e.message}", context=ctx
749
+ ) from e
750
+ except asyncpg.NotNullViolationError as e:
751
+ # Application error - do NOT trip circuit
752
+ raise RuntimeHostError(
753
+ f"Not null constraint violation: {e.message}", context=ctx
754
+ ) from e
755
+ except asyncpg.UniqueViolationError as e:
756
+ # Application error - do NOT trip circuit
757
+ raise RuntimeHostError(
758
+ f"Unique constraint violation: {e.message}", context=ctx
759
+ ) from e
760
+ except asyncpg.PostgresError as e:
761
+ # Generic PostgreSQL error - use intelligent classification based on SQLSTATE
762
+ # to determine if this is a transient infrastructure issue or permanent app bug
763
+ if self._is_transient_error(e):
764
+ # Transient error (e.g., resource exhaustion, system error)
765
+ # Record failure to potentially trip circuit breaker
766
+ if self._circuit_breaker_initialized:
767
+ async with self._circuit_breaker_lock:
768
+ await self._record_circuit_failure(
769
+ operation="db.query",
770
+ correlation_id=correlation_id,
771
+ )
772
+ # Re-raise as RuntimeHostError regardless of classification
773
+ raise RuntimeHostError(
774
+ f"Database error: {type(e).__name__}", context=ctx
775
+ ) from e
776
+
777
+ async def _execute_statement(
778
+ self,
779
+ sql: str,
780
+ parameters: list[object],
781
+ correlation_id: UUID,
782
+ input_envelope_id: UUID,
783
+ ) -> ModelHandlerOutput[ModelDbQueryResponse]:
784
+ """Execute INSERT/UPDATE/DELETE statement and return affected row count."""
785
+ if self._pool is None:
786
+ ctx = ModelInfraErrorContext(
787
+ transport_type=EnumInfraTransportType.DATABASE,
788
+ operation="db.execute",
789
+ target_name="db_handler",
790
+ correlation_id=correlation_id,
791
+ )
792
+ raise RuntimeHostError(
793
+ "HandlerDb not initialized - call initialize() first", context=ctx
794
+ )
795
+
796
+ ctx = ModelInfraErrorContext(
797
+ transport_type=EnumInfraTransportType.DATABASE,
798
+ operation="db.execute",
799
+ target_name="db_handler",
800
+ correlation_id=correlation_id,
801
+ )
802
+
803
+ # Check circuit breaker before operation
804
+ if self._circuit_breaker_initialized:
805
+ async with self._circuit_breaker_lock:
806
+ await self._check_circuit_breaker(
807
+ operation="db.execute",
808
+ correlation_id=correlation_id,
809
+ )
810
+
811
+ try:
812
+ async with self._pool.acquire() as conn:
813
+ result = await conn.execute(sql, *parameters)
814
+
815
+ # Reset circuit breaker immediately after successful operation,
816
+ # within connection context to avoid race conditions
817
+ if self._circuit_breaker_initialized:
818
+ async with self._circuit_breaker_lock:
819
+ await self._reset_circuit_breaker()
820
+
821
+ # asyncpg returns string like "INSERT 0 1" or "UPDATE 5"
822
+ row_count = self._parse_row_count(result)
823
+ return self._build_response(
824
+ [], row_count, correlation_id, input_envelope_id
825
+ )
826
+ except asyncpg.QueryCanceledError as e:
827
+ # Record failure for timeout errors (database overloaded)
828
+ if self._circuit_breaker_initialized:
829
+ async with self._circuit_breaker_lock:
830
+ await self._record_circuit_failure(
831
+ operation="db.execute",
832
+ correlation_id=correlation_id,
833
+ )
834
+ timeout_ctx = ModelTimeoutErrorContext(
835
+ transport_type=EnumInfraTransportType.DATABASE,
836
+ operation="db.execute",
837
+ target_name="db_handler",
838
+ correlation_id=correlation_id,
839
+ timeout_seconds=self._timeout,
840
+ )
841
+ raise InfraTimeoutError(
842
+ f"Statement timed out after {self._timeout}s",
843
+ context=timeout_ctx,
844
+ ) from e
845
+ except asyncpg.PostgresConnectionError as e:
846
+ # Record failure for connection errors (database unavailable)
847
+ if self._circuit_breaker_initialized:
848
+ async with self._circuit_breaker_lock:
849
+ await self._record_circuit_failure(
850
+ operation="db.execute",
851
+ correlation_id=correlation_id,
852
+ )
853
+ raise InfraConnectionError(
854
+ "Database connection lost during statement execution", context=ctx
855
+ ) from e
856
+ except asyncpg.PostgresSyntaxError as e:
857
+ # Application error - do NOT trip circuit
858
+ raise RuntimeHostError(f"SQL syntax error: {e.message}", context=ctx) from e
859
+ except asyncpg.UndefinedTableError as e:
860
+ # Application error - do NOT trip circuit
861
+ raise RuntimeHostError(f"Table not found: {e.message}", context=ctx) from e
862
+ except asyncpg.UndefinedColumnError as e:
863
+ # Application error - do NOT trip circuit
864
+ raise RuntimeHostError(f"Column not found: {e.message}", context=ctx) from e
865
+ except asyncpg.ForeignKeyViolationError as e:
866
+ # Application error - do NOT trip circuit
867
+ raise RuntimeHostError(
868
+ f"Foreign key constraint violation: {e.message}", context=ctx
869
+ ) from e
870
+ except asyncpg.NotNullViolationError as e:
871
+ # Application error - do NOT trip circuit
872
+ raise RuntimeHostError(
873
+ f"Not null constraint violation: {e.message}", context=ctx
874
+ ) from e
875
+ except asyncpg.UniqueViolationError as e:
876
+ # Application error - do NOT trip circuit
877
+ raise RuntimeHostError(
878
+ f"Unique constraint violation: {e.message}", context=ctx
879
+ ) from e
880
+ except asyncpg.PostgresError as e:
881
+ # Generic PostgreSQL error - use intelligent classification based on SQLSTATE
882
+ # to determine if this is a transient infrastructure issue or permanent app bug
883
+ if self._is_transient_error(e):
884
+ # Transient error (e.g., resource exhaustion, system error)
885
+ # Record failure to potentially trip circuit breaker
886
+ if self._circuit_breaker_initialized:
887
+ async with self._circuit_breaker_lock:
888
+ await self._record_circuit_failure(
889
+ operation="db.execute",
890
+ correlation_id=correlation_id,
891
+ )
892
+ # Re-raise as RuntimeHostError regardless of classification
893
+ raise RuntimeHostError(
894
+ f"Database error: {type(e).__name__}", context=ctx
895
+ ) from e
896
+
897
+ def _parse_row_count(self, result: str) -> int:
898
+ """Parse row count from asyncpg execute result string.
899
+
900
+ asyncpg returns strings like:
901
+ - "INSERT 0 1" -> 1 row inserted
902
+ - "UPDATE 5" -> 5 rows updated
903
+ - "DELETE 3" -> 3 rows deleted
904
+ """
905
+ try:
906
+ parts = result.split()
907
+ if len(parts) >= 2:
908
+ return int(parts[-1])
909
+ except (ValueError, IndexError):
910
+ pass
911
+ return 0
912
+
913
+ def _map_postgres_error(
914
+ self,
915
+ exc: asyncpg.PostgresError,
916
+ ctx: ModelInfraErrorContext,
917
+ ) -> RuntimeHostError | InfraTimeoutError | InfraConnectionError:
918
+ """Map asyncpg exception to ONEX infrastructure error.
919
+
920
+ This helper reduces complexity of _execute_statement and _execute_query
921
+ by centralizing exception-to-error mapping logic.
922
+
923
+ Args:
924
+ exc: The asyncpg exception that was raised.
925
+ ctx: Error context with transport type, operation, and correlation ID.
926
+
927
+ Returns:
928
+ Appropriate ONEX infrastructure error based on exception type.
929
+ """
930
+ exc_type = type(exc)
931
+
932
+ # Special cases requiring specific error types or additional arguments
933
+ if exc_type is asyncpg.QueryCanceledError:
934
+ # Convert ModelInfraErrorContext to ModelTimeoutErrorContext for stricter typing
935
+ timeout_ctx = ModelTimeoutErrorContext(
936
+ transport_type=ctx.transport_type or EnumInfraTransportType.DATABASE,
937
+ operation=ctx.operation or "db.statement",
938
+ target_name=ctx.target_name,
939
+ correlation_id=ctx.correlation_id,
940
+ timeout_seconds=self._timeout,
941
+ )
942
+ return InfraTimeoutError(
943
+ f"Statement timed out after {self._timeout}s",
944
+ context=timeout_ctx,
945
+ )
946
+
947
+ if exc_type is asyncpg.PostgresConnectionError:
948
+ return InfraConnectionError(
949
+ "Database connection lost during statement execution",
950
+ context=ctx,
951
+ )
952
+
953
+ # All other errors map to RuntimeHostError with descriptive message
954
+ prefix = _POSTGRES_ERROR_PREFIXES.get(exc_type, "Database error")
955
+ # Use message attribute if available and non-empty, else use type name
956
+ message = getattr(exc, "message", None) or type(exc).__name__
957
+ return RuntimeHostError(f"{prefix}: {message}", context=ctx)
958
+
959
+ def _build_response(
960
+ self,
961
+ rows: list[dict[str, object]],
962
+ row_count: int,
963
+ correlation_id: UUID,
964
+ input_envelope_id: UUID,
965
+ ) -> ModelHandlerOutput[ModelDbQueryResponse]:
966
+ """Build response wrapped in ModelHandlerOutput from query/execute result."""
967
+ result = ModelDbQueryResponse(
968
+ status=EnumResponseStatus.SUCCESS,
969
+ payload=ModelDbQueryPayload(rows=rows, row_count=row_count),
970
+ correlation_id=correlation_id,
971
+ )
972
+ return ModelHandlerOutput.for_compute(
973
+ input_envelope_id=input_envelope_id,
974
+ correlation_id=correlation_id,
975
+ handler_id=HANDLER_ID_DB,
976
+ result=result,
977
+ )
978
+
979
+ def describe(self) -> ModelDbDescribeResponse:
980
+ """Return handler metadata and capabilities for introspection.
981
+
982
+ This method exposes the handler's type classification along with its
983
+ operational configuration and capabilities.
984
+
985
+ Returns:
986
+ ModelDbDescribeResponse containing:
987
+ - handler_type: Architectural role from handler_type property
988
+ (e.g., "infra_handler"). See EnumHandlerType for valid values.
989
+ - handler_category: Behavioral classification from handler_category
990
+ property (e.g., "effect"). See EnumHandlerTypeCategory for valid values.
991
+ - supported_operations: List of supported operations
992
+ - pool_size: Connection pool size
993
+ - timeout_seconds: Query timeout in seconds
994
+ - initialized: Whether the handler is initialized
995
+ - version: Handler version string
996
+
997
+ Note:
998
+ The handler_type and handler_category fields form the handler
999
+ classification system:
1000
+
1001
+ 1. handler_type (architectural role): Determines lifecycle and invocation
1002
+ patterns. This handler is INFRA_HANDLER (protocol/transport handler).
1003
+
1004
+ 2. handler_category (behavioral classification): Determines security rules
1005
+ and replay safety. This handler is EFFECT (side-effecting I/O).
1006
+
1007
+ The transport type for this handler is DATABASE (PostgreSQL).
1008
+
1009
+ Security Consideration:
1010
+ The circuit_breaker field exposes operational state including failure counts.
1011
+ This information is intended for internal monitoring and observability.
1012
+
1013
+ WARNING: If describe() is exposed via external APIs, failure counts could
1014
+ reveal information useful to attackers (e.g., timing attacks when circuit
1015
+ is about to open). For external exposure, consider:
1016
+
1017
+ 1. Restricting describe() to authenticated admin/monitoring endpoints only
1018
+ 2. Sanitizing output to show only state (OPEN/CLOSED/HALF_OPEN), not counts
1019
+ 3. Rate-limiting describe() calls to prevent information harvesting
1020
+
1021
+ The current implementation assumes describe() is used for internal
1022
+ monitoring dashboards and health checks, not public APIs.
1023
+
1024
+ See Also:
1025
+ - handler_type property: Full documentation of architectural role
1026
+ - handler_category property: Full documentation of behavioral classification
1027
+ - docs/architecture/HANDLER_PROTOCOL_DRIVEN_ARCHITECTURE.md
1028
+ """
1029
+ # Get circuit breaker state if initialized
1030
+ cb_state: dict[str, JsonType] | None = None
1031
+ if self._circuit_breaker_initialized:
1032
+ cb_state = self._get_circuit_breaker_state()
1033
+
1034
+ return ModelDbDescribeResponse(
1035
+ handler_type=self.handler_type.value,
1036
+ handler_category=self.handler_category.value,
1037
+ supported_operations=sorted(_SUPPORTED_OPERATIONS),
1038
+ pool_size=self._pool_size,
1039
+ timeout_seconds=self._timeout,
1040
+ initialized=self._initialized,
1041
+ version="0.1.0-mvp",
1042
+ circuit_breaker=cb_state,
1043
+ )
1044
+
1045
+
1046
+ __all__: list[str] = ["HandlerDb"]