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,967 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2025 OmniNode Team
3
+ """Structured Logging Handler - EFFECT handler for structured logging with buffer/flush.
4
+
5
+ This handler implements the ONEX EFFECT handler pattern for structured logging.
6
+ It manages the lifecycle of a SinkLoggingStructured instance, providing:
7
+ - Contract-driven lifecycle management (initialize, shutdown)
8
+ - Periodic background flush with configurable interval
9
+ - Buffer threshold flush (when buffer reaches capacity)
10
+ - Graceful shutdown with final flush
11
+
12
+ Architecture Principle: "Handlers own lifecycle, sinks own hot path"
13
+ - This handler: Contract-driven lifecycle, buffer/flush management
14
+ - SinkLoggingStructured: Fast in-process emission (synchronous, non-blocking)
15
+
16
+ Supported Operations:
17
+ - logging.emit: Emit a log entry to the buffer (delegates to sink)
18
+ - logging.flush: Force flush all buffered entries immediately
19
+ - logging.configure: Update logging configuration at runtime
20
+
21
+ Thread Safety:
22
+ The handler uses a multi-lock design for safe concurrent access:
23
+
24
+ 1. _config_lock (asyncio.Lock): Guards async configuration changes and prevents
25
+ concurrent configure operations from interfering with each other.
26
+
27
+ 2. _emit_lock (threading.Lock): Guards the critical section during emit and
28
+ reconfiguration to prevent log loss. This lock ensures that:
29
+ - While an emit is in progress, reconfiguration waits for it to complete
30
+ - While reconfiguration is in progress (swap + flush), emits are serialized
31
+
32
+ The underlying sink uses its own threading.Lock for buffer operations.
33
+ This multi-lock design allows safe operation from both async and sync contexts
34
+ while preventing log loss during reconfiguration.
35
+
36
+ Reconfiguration Log Loss Prevention:
37
+ Without synchronization, a race condition can cause log loss:
38
+ 1. emit reads self._sink -> gets old_sink reference
39
+ 2. configure swaps self._sink to new_sink
40
+ 3. emit calls old_sink.emit() -> log goes to abandoned sink (LOST)
41
+
42
+ The _emit_lock prevents this by ensuring the swap is atomic with respect
43
+ to emit operations. The swap-then-flush sequence is:
44
+ 1. Acquire _emit_lock (blocks all emits)
45
+ 2. Swap to new sink (atomic reference swap)
46
+ 3. Release _emit_lock (emits resume to new sink immediately)
47
+ 4. Flush old sink (outside lock - logs during flush go to new sink)
48
+
49
+ This guarantees no log loss while minimizing lock hold time. The old sink's
50
+ buffer is preserved until explicitly flushed, and any logs emitted during
51
+ the flush operation go directly to the new sink.
52
+
53
+ Drop Policy:
54
+ The drop_policy configuration field accepts only "drop_oldest", which is the
55
+ sole supported policy. When the buffer is full, the oldest entries are dropped
56
+ to make room for new ones, preserving recent logs. The policy is applied to
57
+ the sink during both initialization and reconfiguration.
58
+
59
+ Envelope-Based Routing:
60
+ This handler uses envelope-based operation routing. See CLAUDE.md section
61
+ "Intent Model Architecture > Envelope-Based Handler Routing" for the full
62
+ design pattern.
63
+ """
64
+
65
+ from __future__ import annotations
66
+
67
+ import asyncio
68
+ import logging
69
+ import threading
70
+ from typing import TYPE_CHECKING
71
+ from uuid import UUID, uuid4
72
+
73
+ from omnibase_core.types import JsonType
74
+ from omnibase_infra.enums import (
75
+ EnumHandlerType,
76
+ EnumHandlerTypeCategory,
77
+ EnumInfraTransportType,
78
+ EnumResponseStatus,
79
+ )
80
+ from omnibase_infra.errors import (
81
+ ModelInfraErrorContext,
82
+ ProtocolConfigurationError,
83
+ RuntimeHostError,
84
+ )
85
+ from omnibase_infra.mixins import MixinEnvelopeExtraction
86
+ from omnibase_infra.observability.handlers.model_logging_handler_config import (
87
+ ModelLoggingHandlerConfig,
88
+ )
89
+ from omnibase_infra.observability.handlers.model_logging_handler_response import (
90
+ ModelLoggingHandlerResponse,
91
+ )
92
+
93
+ # Dependency validation for structlog (via SinkLoggingStructured)
94
+ # The sink requires structlog; check availability here for early error detection
95
+ _STRUCTLOG_AVAILABLE: bool = False
96
+ try:
97
+ import structlog
98
+
99
+ _STRUCTLOG_AVAILABLE = True
100
+ del structlog # Not used at runtime, only for dependency check
101
+ except ImportError:
102
+ pass
103
+
104
+ # Import sink after dependency check (will fail at instantiation if structlog missing)
105
+ from omnibase_infra.observability.sinks import SinkLoggingStructured
106
+
107
+ if TYPE_CHECKING:
108
+ from omnibase_core.enums import EnumLogLevel
109
+
110
+ logger = logging.getLogger(__name__)
111
+
112
+ # Handler ID for responses
113
+ HANDLER_ID_LOGGING: str = "logging-handler"
114
+
115
+ # Supported operations
116
+ SUPPORTED_OPERATIONS: frozenset[str] = frozenset(
117
+ {
118
+ "logging.emit",
119
+ "logging.flush",
120
+ "logging.configure",
121
+ }
122
+ )
123
+
124
+
125
+ class HandlerLoggingStructured(MixinEnvelopeExtraction):
126
+ """Structured logging EFFECT handler with buffer/flush management.
127
+
128
+ This handler manages the lifecycle of a SinkLoggingStructured instance,
129
+ providing contract-driven initialization, periodic background flush,
130
+ and graceful shutdown with final flush.
131
+
132
+ Lifecycle:
133
+ 1. initialize(): Creates sink, starts periodic flush task
134
+ 2. execute(): Routes operations to sink methods
135
+ 3. shutdown(): Cancels flush task, performs final flush
136
+
137
+ Buffer Management:
138
+ - The sink maintains a bounded buffer with configurable size
139
+ - Periodic flush: Background task flushes at configured interval
140
+ - Threshold flush: Automatic flush when buffer nears capacity
141
+ - Shutdown flush: Final flush ensures no data loss
142
+
143
+ Buffer Metrics:
144
+ The periodic flush loop emits the following metrics for monitoring:
145
+ - logging_buffer_utilization_ratio: Gauge (0.0-1.0) of buffer usage
146
+ - logging_buffer_dropped_total: Counter of entries dropped since last flush
147
+
148
+ These metrics help detect if buffer size is insufficient before logs are lost.
149
+
150
+ Thread Safety:
151
+ - Configuration changes use asyncio.Lock (prevents concurrent configure calls)
152
+ - Emit operations use threading.Lock (prevents log loss during reconfiguration)
153
+ - Sink operations use threading.Lock (internal to sink for buffer access)
154
+ - Safe for concurrent async callers; emit is protected during sink swap
155
+
156
+ Example:
157
+ ```python
158
+ handler = HandlerLoggingStructured()
159
+ await handler.initialize({
160
+ "buffer_size": 500,
161
+ "flush_interval_seconds": 10.0,
162
+ "output_format": "json",
163
+ })
164
+
165
+ # Emit log entries
166
+ await handler.execute({
167
+ "operation": "logging.emit",
168
+ "payload": {
169
+ "level": "INFO",
170
+ "message": "User logged in",
171
+ "context": {"user_id": "u_123"},
172
+ },
173
+ })
174
+
175
+ # Force flush
176
+ await handler.execute({
177
+ "operation": "logging.flush",
178
+ "payload": {},
179
+ })
180
+
181
+ await handler.shutdown()
182
+ ```
183
+ """
184
+
185
+ def __init__(self) -> None:
186
+ """Initialize handler in uninitialized state."""
187
+ self._sink: SinkLoggingStructured | None = None
188
+ self._config: ModelLoggingHandlerConfig | None = None
189
+ self._initialized: bool = False
190
+ self._flush_task: asyncio.Task[None] | None = None
191
+ self._shutdown_event: asyncio.Event | None = None
192
+ self._config_lock: asyncio.Lock = asyncio.Lock()
193
+ # Threading lock to prevent log loss during reconfiguration.
194
+ # This lock ensures emit operations complete before sink swap+flush.
195
+ self._emit_lock: threading.Lock = threading.Lock()
196
+ # Track dropped count from previous flush cycle to emit delta
197
+ self._last_drop_count: int = 0
198
+
199
+ @property
200
+ def handler_type(self) -> EnumHandlerType:
201
+ """Return the architectural role of this handler.
202
+
203
+ Returns:
204
+ EnumHandlerType.INFRA_HANDLER - This handler is an infrastructure
205
+ handler that manages the logging sink lifecycle. It is not a
206
+ NODE_HANDLER (event processing) or COMPUTE_HANDLER (pure computation).
207
+
208
+ Note:
209
+ handler_type determines lifecycle, protocol selection, and runtime
210
+ invocation patterns. It answers "what is this handler in the architecture?"
211
+
212
+ See Also:
213
+ - handler_category: Behavioral classification (EFFECT/COMPUTE)
214
+ - docs/architecture/HANDLER_PROTOCOL_DRIVEN_ARCHITECTURE.md
215
+ """
216
+ return EnumHandlerType.INFRA_HANDLER
217
+
218
+ @property
219
+ def handler_category(self) -> EnumHandlerTypeCategory:
220
+ """Return the behavioral classification of this handler.
221
+
222
+ Returns:
223
+ EnumHandlerTypeCategory.EFFECT - This handler performs side-effecting
224
+ I/O operations (writing logs to stdout/files). EFFECT handlers are
225
+ not deterministic and interact with external systems.
226
+
227
+ Note:
228
+ handler_category determines security rules, determinism guarantees,
229
+ replay safety, and permissions. It answers "how does this handler
230
+ behave at runtime?"
231
+
232
+ Categories:
233
+ - COMPUTE: Pure, deterministic transformations (no side effects)
234
+ - EFFECT: Side-effecting I/O (database, HTTP, file writes, logging)
235
+ - NONDETERMINISTIC_COMPUTE: Pure but not deterministic (UUID, random)
236
+
237
+ See Also:
238
+ - handler_type: Architectural role (INFRA_HANDLER/NODE_HANDLER/etc.)
239
+ - docs/architecture/HANDLER_PROTOCOL_DRIVEN_ARCHITECTURE.md
240
+ """
241
+ return EnumHandlerTypeCategory.EFFECT
242
+
243
+ async def initialize(self, config: dict[str, object]) -> None:
244
+ """Initialize the logging handler with configuration.
245
+
246
+ Creates the SinkLoggingStructured instance and starts the periodic
247
+ flush background task if configured.
248
+
249
+ Args:
250
+ config: Configuration dict containing:
251
+ - buffer_size: Max buffer size (default: 1000)
252
+ - flush_interval_seconds: Flush interval (default: 5.0, 0 to disable)
253
+ - output_format: "json" or "console" (default: "json")
254
+ - drop_policy: "drop_oldest" (only supported policy)
255
+
256
+ Raises:
257
+ ProtocolConfigurationError: If structlog is not installed or
258
+ configuration validation fails.
259
+ RuntimeHostError: If handler is already initialized.
260
+ """
261
+ init_correlation_id = uuid4()
262
+
263
+ # Validate required dependencies before proceeding
264
+ if not _STRUCTLOG_AVAILABLE:
265
+ ctx = ModelInfraErrorContext.with_correlation(
266
+ correlation_id=init_correlation_id,
267
+ transport_type=EnumInfraTransportType.RUNTIME,
268
+ operation="initialize",
269
+ target_name="logging_handler",
270
+ )
271
+ raise ProtocolConfigurationError(
272
+ "Missing required dependency: structlog. "
273
+ "Install with: pip install structlog",
274
+ context=ctx,
275
+ )
276
+
277
+ logger.info(
278
+ "Initializing %s",
279
+ self.__class__.__name__,
280
+ extra={
281
+ "handler": self.__class__.__name__,
282
+ "correlation_id": str(init_correlation_id),
283
+ },
284
+ )
285
+
286
+ if self._initialized:
287
+ # Log warning before raising to help users understand their config
288
+ # is not being applied (the handler maintains existing configuration)
289
+ logger.warning(
290
+ "Handler %s already initialized; ignoring new configuration. "
291
+ "Call shutdown() first to reinitialize with new config.",
292
+ self.__class__.__name__,
293
+ extra={
294
+ "handler": self.__class__.__name__,
295
+ "correlation_id": str(init_correlation_id),
296
+ "existing_config": self._config.model_dump()
297
+ if self._config
298
+ else None,
299
+ },
300
+ )
301
+ ctx = ModelInfraErrorContext.with_correlation(
302
+ correlation_id=init_correlation_id,
303
+ transport_type=EnumInfraTransportType.RUNTIME,
304
+ operation="initialize",
305
+ target_name="logging_handler",
306
+ )
307
+ raise RuntimeHostError(
308
+ "Handler already initialized. Call shutdown() first.",
309
+ context=ctx,
310
+ )
311
+
312
+ # Validate and parse configuration
313
+ # NOTE: Broad Exception catch is intentional here because Pydantic can raise
314
+ # various exception types (ValidationError, TypeError, ValueError) depending
315
+ # on the validation failure. We wrap all in ProtocolConfigurationError.
316
+ try:
317
+ self._config = ModelLoggingHandlerConfig.model_validate(config)
318
+ except Exception as e:
319
+ ctx = ModelInfraErrorContext.with_correlation(
320
+ correlation_id=init_correlation_id,
321
+ transport_type=EnumInfraTransportType.RUNTIME,
322
+ operation="initialize",
323
+ target_name="logging_handler",
324
+ )
325
+ raise ProtocolConfigurationError(
326
+ f"Invalid logging handler configuration: {e}",
327
+ context=ctx,
328
+ ) from e
329
+
330
+ # Create the sink with ALL config fields applied, including drop_policy.
331
+ # The drop_policy controls buffer overflow behavior (currently only "drop_oldest").
332
+ self._sink = SinkLoggingStructured(
333
+ max_buffer_size=self._config.buffer_size,
334
+ output_format=self._config.output_format,
335
+ drop_policy=self._config.drop_policy,
336
+ )
337
+
338
+ # Reset drop count tracker for new sink
339
+ self._last_drop_count = 0
340
+
341
+ # Set up shutdown event and start periodic flush task
342
+ self._shutdown_event = asyncio.Event()
343
+
344
+ if self._config.flush_interval_seconds > 0:
345
+ self._flush_task = asyncio.create_task(
346
+ self._periodic_flush_loop(),
347
+ name="logging-handler-flush",
348
+ )
349
+
350
+ self._initialized = True
351
+
352
+ logger.info(
353
+ "%s initialized successfully",
354
+ self.__class__.__name__,
355
+ extra={
356
+ "handler": self.__class__.__name__,
357
+ "buffer_size": self._config.buffer_size,
358
+ "flush_interval_seconds": self._config.flush_interval_seconds,
359
+ "output_format": self._config.output_format,
360
+ "drop_policy": self._config.drop_policy,
361
+ "correlation_id": str(init_correlation_id),
362
+ },
363
+ )
364
+
365
+ async def shutdown(self) -> None:
366
+ """Shutdown the logging handler gracefully.
367
+
368
+ Cancels the periodic flush task, performs a final flush of all
369
+ buffered entries, and releases resources.
370
+
371
+ This method is idempotent - calling it multiple times is safe.
372
+ """
373
+ shutdown_correlation_id = uuid4()
374
+
375
+ logger.info(
376
+ "Shutting down %s",
377
+ self.__class__.__name__,
378
+ extra={
379
+ "handler": self.__class__.__name__,
380
+ "correlation_id": str(shutdown_correlation_id),
381
+ },
382
+ )
383
+
384
+ # Signal shutdown to flush loop
385
+ if self._shutdown_event is not None:
386
+ self._shutdown_event.set()
387
+
388
+ # Cancel periodic flush task
389
+ if self._flush_task is not None:
390
+ self._flush_task.cancel()
391
+ try:
392
+ await self._flush_task
393
+ except asyncio.CancelledError:
394
+ pass
395
+ self._flush_task = None
396
+
397
+ # Final flush - best effort, never fails shutdown
398
+ # NOTE: Broad Exception catch is intentional here to ensure shutdown
399
+ # always completes regardless of I/O errors. Any flush error during
400
+ # shutdown is logged but does not prevent cleanup from completing.
401
+ if self._sink is not None:
402
+ try:
403
+ self._sink.flush()
404
+ except Exception as e:
405
+ logger.warning(
406
+ "Error during final flush on shutdown: %s",
407
+ e,
408
+ extra={
409
+ "handler": self.__class__.__name__,
410
+ "correlation_id": str(shutdown_correlation_id),
411
+ "error_type": type(e).__name__,
412
+ },
413
+ )
414
+
415
+ # Clear state
416
+ self._sink = None
417
+ self._config = None
418
+ self._initialized = False
419
+ self._shutdown_event = None
420
+
421
+ logger.info(
422
+ "%s shutdown complete",
423
+ self.__class__.__name__,
424
+ extra={
425
+ "handler": self.__class__.__name__,
426
+ "correlation_id": str(shutdown_correlation_id),
427
+ },
428
+ )
429
+
430
+ async def execute(self, envelope: dict[str, object]) -> ModelLoggingHandlerResponse:
431
+ """Execute a logging operation from the envelope.
432
+
433
+ Supported operations:
434
+ - logging.emit: Buffer a log entry
435
+ - logging.flush: Force flush all buffered entries
436
+ - logging.configure: Update handler configuration
437
+
438
+ Args:
439
+ envelope: Request envelope containing:
440
+ - operation: Operation identifier (logging.emit, etc.)
441
+ - payload: Operation-specific payload
442
+ - correlation_id: Optional correlation ID for tracing
443
+ - envelope_id: Optional envelope ID for causality tracking
444
+
445
+ Returns:
446
+ ModelLoggingHandlerResponse with operation result
447
+
448
+ Raises:
449
+ RuntimeHostError: If handler not initialized or invalid operation.
450
+ """
451
+ correlation_id = self._extract_correlation_id(envelope)
452
+
453
+ if not self._initialized or self._sink is None or self._config is None:
454
+ ctx = ModelInfraErrorContext.with_correlation(
455
+ correlation_id=correlation_id,
456
+ transport_type=EnumInfraTransportType.RUNTIME,
457
+ operation="execute",
458
+ target_name="logging_handler",
459
+ )
460
+ raise RuntimeHostError(
461
+ "Logging handler not initialized. Call initialize() first.",
462
+ context=ctx,
463
+ )
464
+
465
+ operation = envelope.get("operation")
466
+ if not isinstance(operation, str):
467
+ ctx = ModelInfraErrorContext.with_correlation(
468
+ correlation_id=correlation_id,
469
+ transport_type=EnumInfraTransportType.RUNTIME,
470
+ operation="execute",
471
+ target_name="logging_handler",
472
+ )
473
+ raise RuntimeHostError(
474
+ "Missing or invalid 'operation' in envelope",
475
+ context=ctx,
476
+ )
477
+
478
+ if operation not in SUPPORTED_OPERATIONS:
479
+ ctx = ModelInfraErrorContext.with_correlation(
480
+ correlation_id=correlation_id,
481
+ transport_type=EnumInfraTransportType.RUNTIME,
482
+ operation=operation,
483
+ target_name="logging_handler",
484
+ )
485
+ raise RuntimeHostError(
486
+ f"Operation '{operation}' not supported. "
487
+ f"Available: {', '.join(sorted(SUPPORTED_OPERATIONS))}",
488
+ context=ctx,
489
+ )
490
+
491
+ payload = envelope.get("payload")
492
+ if not isinstance(payload, dict):
493
+ ctx = ModelInfraErrorContext.with_correlation(
494
+ correlation_id=correlation_id,
495
+ transport_type=EnumInfraTransportType.RUNTIME,
496
+ operation=operation,
497
+ target_name="logging_handler",
498
+ )
499
+ raise RuntimeHostError(
500
+ "Missing or invalid 'payload' in envelope",
501
+ context=ctx,
502
+ )
503
+
504
+ # Route to operation handler
505
+ if operation == "logging.emit":
506
+ return self._handle_emit(payload, correlation_id)
507
+ elif operation == "logging.flush":
508
+ return self._handle_flush(correlation_id)
509
+ else: # logging.configure
510
+ return await self._handle_configure(payload, correlation_id)
511
+
512
+ def _handle_emit(
513
+ self,
514
+ payload: dict[str, object],
515
+ correlation_id: UUID,
516
+ ) -> ModelLoggingHandlerResponse:
517
+ """Handle logging.emit operation.
518
+
519
+ Args:
520
+ payload: Payload containing:
521
+ - level: Log level (DEBUG, INFO, WARNING, ERROR, CRITICAL, etc.)
522
+ - message: Log message string
523
+ - context: Dict of string key-value context data
524
+ correlation_id: Correlation ID for tracing
525
+
526
+ Returns:
527
+ ModelLoggingHandlerResponse with operation result
528
+
529
+ Thread Safety:
530
+ This method acquires _emit_lock to prevent log loss during
531
+ reconfiguration. The lock ensures the sink reference is stable
532
+ throughout the emit operation.
533
+ """
534
+ # Extract and validate payload fields BEFORE acquiring lock
535
+ # to minimize time spent holding the lock
536
+ level_raw = payload.get("level")
537
+ message = payload.get("message")
538
+ context_raw = payload.get("context", {})
539
+
540
+ if not isinstance(message, str):
541
+ ctx = ModelInfraErrorContext.with_correlation(
542
+ correlation_id=correlation_id,
543
+ transport_type=EnumInfraTransportType.RUNTIME,
544
+ operation="logging.emit",
545
+ target_name="logging_handler",
546
+ )
547
+ raise RuntimeHostError(
548
+ "Missing or invalid 'message' in payload - must be string",
549
+ context=ctx,
550
+ )
551
+
552
+ if not isinstance(context_raw, dict):
553
+ ctx = ModelInfraErrorContext.with_correlation(
554
+ correlation_id=correlation_id,
555
+ transport_type=EnumInfraTransportType.RUNTIME,
556
+ operation="logging.emit",
557
+ target_name="logging_handler",
558
+ )
559
+ raise RuntimeHostError(
560
+ "Invalid 'context' in payload - must be dict",
561
+ context=ctx,
562
+ )
563
+
564
+ # Pass through JSON-compatible context values (sink accepts JsonType)
565
+ # This preserves rich context data (int, float, bool, list, dict) for structured logging
566
+ context: dict[str, JsonType] = {str(k): v for k, v in context_raw.items()}
567
+
568
+ # Parse log level
569
+ level = self._parse_log_level(level_raw, correlation_id)
570
+
571
+ # Critical section: acquire emit lock to prevent log loss during reconfiguration.
572
+ # This ensures the sink reference is stable and any logs emitted here will be
573
+ # flushed before the old sink is abandoned.
574
+ with self._emit_lock:
575
+ if self._sink is None:
576
+ ctx = ModelInfraErrorContext.with_correlation(
577
+ correlation_id=correlation_id,
578
+ transport_type=EnumInfraTransportType.RUNTIME,
579
+ operation="logging.emit",
580
+ target_name="logging_handler",
581
+ )
582
+ raise RuntimeHostError(
583
+ "Sink not initialized",
584
+ context=ctx,
585
+ )
586
+
587
+ # Emit to sink (synchronous, non-blocking)
588
+ self._sink.emit(level, message, context)
589
+
590
+ # Capture metrics while still holding the lock for consistency
591
+ buffer_size = self._sink.buffer_size
592
+ drop_count = self._sink.drop_count
593
+
594
+ return ModelLoggingHandlerResponse(
595
+ status=EnumResponseStatus.SUCCESS,
596
+ operation="logging.emit",
597
+ message="Log entry buffered",
598
+ correlation_id=correlation_id,
599
+ buffer_size=buffer_size,
600
+ drop_count=drop_count,
601
+ )
602
+
603
+ def _handle_flush(
604
+ self,
605
+ correlation_id: UUID,
606
+ ) -> ModelLoggingHandlerResponse:
607
+ """Handle logging.flush operation.
608
+
609
+ Args:
610
+ correlation_id: Correlation ID for tracing
611
+
612
+ Returns:
613
+ ModelLoggingHandlerResponse with operation result
614
+ """
615
+ if self._sink is None:
616
+ ctx = ModelInfraErrorContext.with_correlation(
617
+ correlation_id=correlation_id,
618
+ transport_type=EnumInfraTransportType.RUNTIME,
619
+ operation="logging.flush",
620
+ target_name="logging_handler",
621
+ )
622
+ raise RuntimeHostError(
623
+ "Sink not initialized",
624
+ context=ctx,
625
+ )
626
+
627
+ # Capture pre-flush metrics
628
+ pre_buffer_size = self._sink.buffer_size
629
+
630
+ # Flush (synchronous I/O)
631
+ self._sink.flush()
632
+
633
+ return ModelLoggingHandlerResponse(
634
+ status=EnumResponseStatus.SUCCESS,
635
+ operation="logging.flush",
636
+ message=f"Flushed {pre_buffer_size} entries",
637
+ correlation_id=correlation_id,
638
+ buffer_size=self._sink.buffer_size,
639
+ drop_count=self._sink.drop_count,
640
+ )
641
+
642
+ async def _handle_configure(
643
+ self,
644
+ payload: dict[str, object],
645
+ correlation_id: UUID,
646
+ ) -> ModelLoggingHandlerResponse:
647
+ """Handle logging.configure operation.
648
+
649
+ Note: Configuration changes require re-creating the sink. To prevent
650
+ log loss, the swap-then-flush sequence ensures the atomic swap happens
651
+ first under _emit_lock, then the old sink is flushed after releasing
652
+ the lock.
653
+
654
+ Thread Safety:
655
+ The _emit_lock is acquired during the atomic swap operation only.
656
+ This ensures that:
657
+ 1. All in-flight emits complete before we start the swap
658
+ 2. No new emits can start during the swap
659
+ 3. After swap completes, new emits immediately go to the new sink
660
+ 4. Old sink is flushed after the lock is released (no blocking I/O under lock)
661
+
662
+ Reconfiguration Sequence:
663
+ 1. Acquire _emit_lock
664
+ 2. Swap to new sink atomically (under lock)
665
+ 3. Update config reference (under lock)
666
+ 4. Release _emit_lock
667
+ 5. Flush old sink (outside lock - logs during flush go to new sink)
668
+ This order guarantees no log loss and minimizes lock hold time.
669
+
670
+ Args:
671
+ payload: Configuration payload (same fields as ModelLoggingHandlerConfig)
672
+ correlation_id: Correlation ID for tracing
673
+
674
+ Returns:
675
+ ModelLoggingHandlerResponse with operation result
676
+ """
677
+ async with self._config_lock:
678
+ if self._sink is None or self._config is None:
679
+ ctx = ModelInfraErrorContext.with_correlation(
680
+ correlation_id=correlation_id,
681
+ transport_type=EnumInfraTransportType.RUNTIME,
682
+ operation="logging.configure",
683
+ target_name="logging_handler",
684
+ )
685
+ raise RuntimeHostError(
686
+ "Handler not initialized",
687
+ context=ctx,
688
+ )
689
+
690
+ # Merge existing config with new values
691
+ current_dict = self._config.model_dump()
692
+ current_dict.update(payload)
693
+
694
+ # Validate new configuration BEFORE acquiring emit lock
695
+ # NOTE: Broad Exception catch is intentional here because Pydantic can raise
696
+ # various exception types (ValidationError, TypeError, ValueError) depending
697
+ # on the validation failure. We wrap all in ProtocolConfigurationError.
698
+ try:
699
+ new_config = ModelLoggingHandlerConfig.model_validate(current_dict)
700
+ except Exception as e:
701
+ ctx = ModelInfraErrorContext.with_correlation(
702
+ correlation_id=correlation_id,
703
+ transport_type=EnumInfraTransportType.RUNTIME,
704
+ operation="logging.configure",
705
+ target_name="logging_handler",
706
+ )
707
+ raise ProtocolConfigurationError(
708
+ f"Invalid configuration: {e}",
709
+ context=ctx,
710
+ ) from e
711
+
712
+ # Create new sink with updated config BEFORE acquiring emit lock
713
+ # to minimize time spent blocking emit operations.
714
+ # All config fields are applied including drop_policy.
715
+ new_sink = SinkLoggingStructured(
716
+ max_buffer_size=new_config.buffer_size,
717
+ output_format=new_config.output_format,
718
+ drop_policy=new_config.drop_policy,
719
+ )
720
+
721
+ # Critical section: acquire emit lock for atomic swap-then-flush.
722
+ # This prevents the race condition where:
723
+ # 1. emit reads self._sink -> gets old_sink
724
+ # 2. configure swaps to new_sink
725
+ # 3. emit calls old_sink.emit() -> log LOST (old sink abandoned)
726
+ #
727
+ # By swapping BEFORE flush and flushing AFTER releasing the lock:
728
+ # - New emits immediately go to the new sink (no blocking during flush)
729
+ # - Old sink's buffer is preserved until explicitly flushed
730
+ # - Lock hold time is minimized (fast swap, no I/O under lock)
731
+ with self._emit_lock:
732
+ # Step 1: Capture old sink reference and swap atomically
733
+ old_sink = self._sink
734
+ self._sink = new_sink
735
+ self._config = new_config
736
+
737
+ # Step 2: Reset drop count tracker for new sink
738
+ self._last_drop_count = 0
739
+
740
+ # Step 3: Flush old sink AFTER releasing lock.
741
+ # Logs emitted during this flush go to the new sink (not lost).
742
+ # This is safe because old_sink's buffer is independent.
743
+ if old_sink is not None:
744
+ old_sink.flush()
745
+
746
+ # Handle flush interval changes (outside emit lock - these are async)
747
+ if self._config.flush_interval_seconds > 0:
748
+ # Restart flush task if not running or interval changed
749
+ if self._flush_task is None or self._flush_task.done():
750
+ self._flush_task = asyncio.create_task(
751
+ self._periodic_flush_loop(),
752
+ name="logging-handler-flush",
753
+ )
754
+ # Cancel flush task if interval is 0
755
+ elif self._flush_task is not None and not self._flush_task.done():
756
+ self._flush_task.cancel()
757
+ try:
758
+ await self._flush_task
759
+ except asyncio.CancelledError:
760
+ pass
761
+ self._flush_task = None
762
+
763
+ return ModelLoggingHandlerResponse(
764
+ status=EnumResponseStatus.SUCCESS,
765
+ operation="logging.configure",
766
+ message="Configuration updated",
767
+ correlation_id=correlation_id,
768
+ buffer_size=self._sink.buffer_size if self._sink else 0,
769
+ drop_count=self._sink.drop_count if self._sink else 0,
770
+ )
771
+
772
+ def _parse_log_level(
773
+ self,
774
+ level_raw: object,
775
+ correlation_id: UUID,
776
+ ) -> EnumLogLevel:
777
+ """Parse log level from payload.
778
+
779
+ Accepts EnumLogLevel enum values or string level names.
780
+
781
+ Args:
782
+ level_raw: Raw level value from payload
783
+ correlation_id: Correlation ID for error context
784
+
785
+ Returns:
786
+ Parsed EnumLogLevel
787
+
788
+ Raises:
789
+ RuntimeHostError: If level is invalid
790
+ """
791
+ # Lazy import to avoid circular dependency
792
+ from omnibase_core.enums import EnumLogLevel
793
+
794
+ if isinstance(level_raw, EnumLogLevel):
795
+ return level_raw
796
+
797
+ if isinstance(level_raw, str):
798
+ # Try to match by value (case-insensitive)
799
+ level_upper = level_raw.upper()
800
+ for log_level in EnumLogLevel:
801
+ if log_level.value.upper() == level_upper:
802
+ return log_level
803
+ if log_level.name.upper() == level_upper:
804
+ return log_level
805
+
806
+ # Default to INFO for unknown levels
807
+ if level_raw is None:
808
+ return EnumLogLevel.INFO
809
+
810
+ ctx = ModelInfraErrorContext.with_correlation(
811
+ correlation_id=correlation_id,
812
+ transport_type=EnumInfraTransportType.RUNTIME,
813
+ operation="logging.emit",
814
+ target_name="logging_handler",
815
+ )
816
+ raise RuntimeHostError(
817
+ f"Invalid log level: {level_raw!r}. "
818
+ f"Valid levels: {[lvl.value for lvl in EnumLogLevel]}",
819
+ context=ctx,
820
+ )
821
+
822
+ async def _periodic_flush_loop(self) -> None:
823
+ """Background task for periodic buffer flush.
824
+
825
+ Runs until shutdown_event is set or task is cancelled.
826
+ Handles flush errors gracefully to prevent task crash.
827
+
828
+ Emits buffer utilization metrics before each flush:
829
+ - logging_buffer_utilization_ratio: Gauge showing buffer usage (0.0-1.0)
830
+ - logging_buffer_dropped_total: Counter of entries dropped since last flush
831
+ """
832
+ if self._shutdown_event is None:
833
+ return
834
+
835
+ while not self._shutdown_event.is_set():
836
+ try:
837
+ # Wait for flush interval or shutdown signal
838
+ flush_interval = (
839
+ self._config.flush_interval_seconds
840
+ if self._config is not None
841
+ else 5.0
842
+ )
843
+ try:
844
+ await asyncio.wait_for(
845
+ self._shutdown_event.wait(),
846
+ timeout=flush_interval,
847
+ )
848
+ # Shutdown signaled
849
+ break
850
+ except TimeoutError:
851
+ # Normal timeout - time to flush
852
+ pass
853
+
854
+ # Perform flush with metrics emission
855
+ if self._sink is not None:
856
+ # Emit buffer utilization metric (gauge: 0.0 to 1.0)
857
+ # Safe from division by zero: max_buffer_size validated >= 1 at init
858
+ max_size = self._sink.max_buffer_size
859
+ current_size = self._sink.buffer_size
860
+ utilization_ratio = current_size / max_size if max_size > 0 else 0.0
861
+
862
+ logger.debug(
863
+ "logging_buffer_utilization_ratio",
864
+ extra={
865
+ "handler": self.__class__.__name__,
866
+ "metric_type": "gauge",
867
+ "metric_name": "logging_buffer_utilization_ratio",
868
+ "value": utilization_ratio,
869
+ "buffer_size": current_size,
870
+ "max_buffer_size": max_size,
871
+ },
872
+ )
873
+
874
+ # Emit dropped logs counter (delta since last flush)
875
+ current_drop_count = self._sink.drop_count
876
+ dropped_since_last = current_drop_count - self._last_drop_count
877
+ if dropped_since_last > 0:
878
+ logger.warning(
879
+ "logging_buffer_dropped_total",
880
+ extra={
881
+ "handler": self.__class__.__name__,
882
+ "metric_type": "counter",
883
+ "metric_name": "logging_buffer_dropped_total",
884
+ "value": dropped_since_last,
885
+ "total_dropped": current_drop_count,
886
+ },
887
+ )
888
+ self._last_drop_count = current_drop_count
889
+
890
+ # Perform flush
891
+ self._sink.flush()
892
+
893
+ except asyncio.CancelledError:
894
+ # Task cancelled - exit gracefully
895
+ break
896
+ except Exception as e:
897
+ # NOTE: Broad Exception catch is intentional here to keep the
898
+ # background flush loop running despite transient I/O errors.
899
+ # This ensures the handler remains operational even if individual
900
+ # flush operations fail temporarily. The sleep prevents tight loops.
901
+ logger.warning(
902
+ "Error in periodic flush loop: %s",
903
+ e,
904
+ extra={
905
+ "handler": self.__class__.__name__,
906
+ "error_type": type(e).__name__,
907
+ },
908
+ )
909
+ # Brief sleep to prevent tight error loop on persistent failures
910
+ await asyncio.sleep(1.0)
911
+
912
+ def describe(self) -> dict[str, object]:
913
+ """Return handler metadata and capabilities for introspection.
914
+
915
+ This method exposes the handler's type classification along with its
916
+ operational configuration and capabilities.
917
+
918
+ Returns:
919
+ dict containing:
920
+ - handler_type: Architectural role (infra_handler)
921
+ - handler_category: Behavioral classification (effect)
922
+ - supported_operations: List of supported operations
923
+ - initialized: Whether the handler is initialized
924
+ - version: Handler version string
925
+ - config: Current configuration (if initialized)
926
+ - buffer_size: Current buffer size (if initialized)
927
+ - max_buffer_size: Maximum buffer capacity (if initialized)
928
+ - drop_count: Total dropped entries (if initialized)
929
+ - buffer_utilization_ratio: Current utilization (0.0-1.0)
930
+
931
+ See Also:
932
+ - handler_type property: Full documentation of architectural role
933
+ - handler_category property: Full documentation of behavioral classification
934
+ """
935
+ result: dict[str, object] = {
936
+ "handler_type": self.handler_type.value,
937
+ "handler_category": self.handler_category.value,
938
+ "supported_operations": sorted(SUPPORTED_OPERATIONS),
939
+ "initialized": self._initialized,
940
+ "version": "0.1.0-mvp",
941
+ }
942
+
943
+ if self._initialized and self._config is not None:
944
+ result["config"] = {
945
+ "buffer_size": self._config.buffer_size,
946
+ "flush_interval_seconds": self._config.flush_interval_seconds,
947
+ "output_format": self._config.output_format,
948
+ "drop_policy": self._config.drop_policy,
949
+ }
950
+
951
+ if self._sink is not None:
952
+ result["buffer_size"] = self._sink.buffer_size
953
+ result["max_buffer_size"] = self._sink.max_buffer_size
954
+ result["drop_count"] = self._sink.drop_count
955
+ # Include utilization ratio for monitoring
956
+ max_size = self._sink.max_buffer_size
957
+ result["buffer_utilization_ratio"] = (
958
+ self._sink.buffer_size / max_size if max_size > 0 else 0.0
959
+ )
960
+
961
+ return result
962
+
963
+
964
+ __all__: list[str] = [
965
+ "HandlerLoggingStructured",
966
+ "SUPPORTED_OPERATIONS",
967
+ ]