omnibase_infra 0.2.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (675) hide show
  1. omnibase_infra/__init__.py +101 -0
  2. omnibase_infra/cli/__init__.py +1 -0
  3. omnibase_infra/cli/commands.py +216 -0
  4. omnibase_infra/clients/__init__.py +0 -0
  5. omnibase_infra/contracts/handlers/filesystem/handler_contract.yaml +261 -0
  6. omnibase_infra/contracts/handlers/mcp/handler_contract.yaml +138 -0
  7. omnibase_infra/decorators/__init__.py +29 -0
  8. omnibase_infra/decorators/allow_any.py +109 -0
  9. omnibase_infra/dlq/__init__.py +90 -0
  10. omnibase_infra/dlq/constants_dlq.py +57 -0
  11. omnibase_infra/dlq/models/__init__.py +26 -0
  12. omnibase_infra/dlq/models/enum_replay_status.py +37 -0
  13. omnibase_infra/dlq/models/model_dlq_replay_record.py +135 -0
  14. omnibase_infra/dlq/models/model_dlq_tracking_config.py +184 -0
  15. omnibase_infra/dlq/service_dlq_tracking.py +611 -0
  16. omnibase_infra/enums/__init__.py +123 -0
  17. omnibase_infra/enums/enum_any_type_violation.py +104 -0
  18. omnibase_infra/enums/enum_backend_type.py +27 -0
  19. omnibase_infra/enums/enum_capture_outcome.py +42 -0
  20. omnibase_infra/enums/enum_capture_state.py +88 -0
  21. omnibase_infra/enums/enum_chain_violation_type.py +119 -0
  22. omnibase_infra/enums/enum_circuit_state.py +51 -0
  23. omnibase_infra/enums/enum_confirmation_event_type.py +27 -0
  24. omnibase_infra/enums/enum_contract_type.py +84 -0
  25. omnibase_infra/enums/enum_dedupe_strategy.py +46 -0
  26. omnibase_infra/enums/enum_dispatch_status.py +191 -0
  27. omnibase_infra/enums/enum_environment.py +46 -0
  28. omnibase_infra/enums/enum_execution_shape_violation.py +103 -0
  29. omnibase_infra/enums/enum_handler_error_type.py +101 -0
  30. omnibase_infra/enums/enum_handler_loader_error.py +178 -0
  31. omnibase_infra/enums/enum_handler_source_type.py +87 -0
  32. omnibase_infra/enums/enum_handler_type.py +77 -0
  33. omnibase_infra/enums/enum_handler_type_category.py +61 -0
  34. omnibase_infra/enums/enum_infra_transport_type.py +73 -0
  35. omnibase_infra/enums/enum_introspection_reason.py +154 -0
  36. omnibase_infra/enums/enum_message_category.py +213 -0
  37. omnibase_infra/enums/enum_node_archetype.py +74 -0
  38. omnibase_infra/enums/enum_node_output_type.py +185 -0
  39. omnibase_infra/enums/enum_non_retryable_error_category.py +224 -0
  40. omnibase_infra/enums/enum_policy_type.py +32 -0
  41. omnibase_infra/enums/enum_registration_state.py +261 -0
  42. omnibase_infra/enums/enum_registration_status.py +33 -0
  43. omnibase_infra/enums/enum_registry_response_status.py +28 -0
  44. omnibase_infra/enums/enum_response_status.py +26 -0
  45. omnibase_infra/enums/enum_retry_error_category.py +98 -0
  46. omnibase_infra/enums/enum_security_rule_id.py +103 -0
  47. omnibase_infra/enums/enum_selection_strategy.py +91 -0
  48. omnibase_infra/enums/enum_topic_standard.py +42 -0
  49. omnibase_infra/enums/enum_validation_severity.py +78 -0
  50. omnibase_infra/errors/__init__.py +156 -0
  51. omnibase_infra/errors/error_architecture_violation.py +152 -0
  52. omnibase_infra/errors/error_chain_propagation.py +188 -0
  53. omnibase_infra/errors/error_compute_registry.py +92 -0
  54. omnibase_infra/errors/error_consul.py +132 -0
  55. omnibase_infra/errors/error_container_wiring.py +243 -0
  56. omnibase_infra/errors/error_event_bus_registry.py +102 -0
  57. omnibase_infra/errors/error_infra.py +608 -0
  58. omnibase_infra/errors/error_message_type_registry.py +101 -0
  59. omnibase_infra/errors/error_policy_registry.py +112 -0
  60. omnibase_infra/errors/error_vault.py +123 -0
  61. omnibase_infra/event_bus/__init__.py +72 -0
  62. omnibase_infra/event_bus/configs/kafka_event_bus_config.yaml +86 -0
  63. omnibase_infra/event_bus/event_bus_inmemory.py +743 -0
  64. omnibase_infra/event_bus/event_bus_kafka.py +1658 -0
  65. omnibase_infra/event_bus/mixin_kafka_broadcast.py +184 -0
  66. omnibase_infra/event_bus/mixin_kafka_dlq.py +765 -0
  67. omnibase_infra/event_bus/models/__init__.py +29 -0
  68. omnibase_infra/event_bus/models/config/__init__.py +20 -0
  69. omnibase_infra/event_bus/models/config/model_kafka_event_bus_config.py +725 -0
  70. omnibase_infra/event_bus/models/model_dlq_event.py +206 -0
  71. omnibase_infra/event_bus/models/model_dlq_metrics.py +304 -0
  72. omnibase_infra/event_bus/models/model_event_headers.py +115 -0
  73. omnibase_infra/event_bus/models/model_event_message.py +60 -0
  74. omnibase_infra/event_bus/topic_constants.py +376 -0
  75. omnibase_infra/handlers/__init__.py +75 -0
  76. omnibase_infra/handlers/filesystem/__init__.py +48 -0
  77. omnibase_infra/handlers/filesystem/enum_file_system_operation.py +35 -0
  78. omnibase_infra/handlers/filesystem/model_file_system_request.py +298 -0
  79. omnibase_infra/handlers/filesystem/model_file_system_result.py +166 -0
  80. omnibase_infra/handlers/handler_consul.py +787 -0
  81. omnibase_infra/handlers/handler_db.py +1039 -0
  82. omnibase_infra/handlers/handler_filesystem.py +1478 -0
  83. omnibase_infra/handlers/handler_graph.py +1154 -0
  84. omnibase_infra/handlers/handler_http.py +920 -0
  85. omnibase_infra/handlers/handler_manifest_persistence.contract.yaml +184 -0
  86. omnibase_infra/handlers/handler_manifest_persistence.py +1539 -0
  87. omnibase_infra/handlers/handler_mcp.py +748 -0
  88. omnibase_infra/handlers/handler_qdrant.py +1076 -0
  89. omnibase_infra/handlers/handler_vault.py +422 -0
  90. omnibase_infra/handlers/mcp/__init__.py +19 -0
  91. omnibase_infra/handlers/mcp/adapter_onex_to_mcp.py +446 -0
  92. omnibase_infra/handlers/mcp/protocols.py +178 -0
  93. omnibase_infra/handlers/mcp/transport_streamable_http.py +352 -0
  94. omnibase_infra/handlers/mixins/__init__.py +42 -0
  95. omnibase_infra/handlers/mixins/mixin_consul_initialization.py +349 -0
  96. omnibase_infra/handlers/mixins/mixin_consul_kv.py +337 -0
  97. omnibase_infra/handlers/mixins/mixin_consul_service.py +277 -0
  98. omnibase_infra/handlers/mixins/mixin_vault_initialization.py +338 -0
  99. omnibase_infra/handlers/mixins/mixin_vault_retry.py +412 -0
  100. omnibase_infra/handlers/mixins/mixin_vault_secrets.py +450 -0
  101. omnibase_infra/handlers/mixins/mixin_vault_token.py +365 -0
  102. omnibase_infra/handlers/models/__init__.py +286 -0
  103. omnibase_infra/handlers/models/consul/__init__.py +81 -0
  104. omnibase_infra/handlers/models/consul/enum_consul_operation_type.py +57 -0
  105. omnibase_infra/handlers/models/consul/model_consul_deregister_payload.py +51 -0
  106. omnibase_infra/handlers/models/consul/model_consul_handler_config.py +153 -0
  107. omnibase_infra/handlers/models/consul/model_consul_handler_payload.py +89 -0
  108. omnibase_infra/handlers/models/consul/model_consul_kv_get_found_payload.py +55 -0
  109. omnibase_infra/handlers/models/consul/model_consul_kv_get_not_found_payload.py +49 -0
  110. omnibase_infra/handlers/models/consul/model_consul_kv_get_recurse_payload.py +50 -0
  111. omnibase_infra/handlers/models/consul/model_consul_kv_item.py +33 -0
  112. omnibase_infra/handlers/models/consul/model_consul_kv_put_payload.py +41 -0
  113. omnibase_infra/handlers/models/consul/model_consul_register_payload.py +53 -0
  114. omnibase_infra/handlers/models/consul/model_consul_retry_config.py +66 -0
  115. omnibase_infra/handlers/models/consul/model_payload_consul.py +66 -0
  116. omnibase_infra/handlers/models/consul/registry_payload_consul.py +214 -0
  117. omnibase_infra/handlers/models/graph/__init__.py +35 -0
  118. omnibase_infra/handlers/models/graph/enum_graph_operation_type.py +20 -0
  119. omnibase_infra/handlers/models/graph/model_graph_execute_payload.py +38 -0
  120. omnibase_infra/handlers/models/graph/model_graph_handler_config.py +54 -0
  121. omnibase_infra/handlers/models/graph/model_graph_handler_payload.py +44 -0
  122. omnibase_infra/handlers/models/graph/model_graph_query_payload.py +40 -0
  123. omnibase_infra/handlers/models/graph/model_graph_record.py +22 -0
  124. omnibase_infra/handlers/models/http/__init__.py +50 -0
  125. omnibase_infra/handlers/models/http/enum_http_operation_type.py +29 -0
  126. omnibase_infra/handlers/models/http/model_http_body_content.py +45 -0
  127. omnibase_infra/handlers/models/http/model_http_get_payload.py +88 -0
  128. omnibase_infra/handlers/models/http/model_http_handler_payload.py +90 -0
  129. omnibase_infra/handlers/models/http/model_http_post_payload.py +88 -0
  130. omnibase_infra/handlers/models/http/model_payload_http.py +66 -0
  131. omnibase_infra/handlers/models/http/registry_payload_http.py +212 -0
  132. omnibase_infra/handlers/models/mcp/__init__.py +23 -0
  133. omnibase_infra/handlers/models/mcp/enum_mcp_operation_type.py +24 -0
  134. omnibase_infra/handlers/models/mcp/model_mcp_handler_config.py +40 -0
  135. omnibase_infra/handlers/models/mcp/model_mcp_tool_call.py +32 -0
  136. omnibase_infra/handlers/models/mcp/model_mcp_tool_result.py +45 -0
  137. omnibase_infra/handlers/models/model_consul_handler_response.py +96 -0
  138. omnibase_infra/handlers/models/model_db_describe_response.py +83 -0
  139. omnibase_infra/handlers/models/model_db_query_payload.py +95 -0
  140. omnibase_infra/handlers/models/model_db_query_response.py +60 -0
  141. omnibase_infra/handlers/models/model_filesystem_config.py +98 -0
  142. omnibase_infra/handlers/models/model_filesystem_delete_payload.py +54 -0
  143. omnibase_infra/handlers/models/model_filesystem_delete_result.py +77 -0
  144. omnibase_infra/handlers/models/model_filesystem_directory_entry.py +75 -0
  145. omnibase_infra/handlers/models/model_filesystem_ensure_directory_payload.py +54 -0
  146. omnibase_infra/handlers/models/model_filesystem_ensure_directory_result.py +60 -0
  147. omnibase_infra/handlers/models/model_filesystem_list_directory_payload.py +60 -0
  148. omnibase_infra/handlers/models/model_filesystem_list_directory_result.py +68 -0
  149. omnibase_infra/handlers/models/model_filesystem_read_payload.py +62 -0
  150. omnibase_infra/handlers/models/model_filesystem_read_result.py +61 -0
  151. omnibase_infra/handlers/models/model_filesystem_write_payload.py +70 -0
  152. omnibase_infra/handlers/models/model_filesystem_write_result.py +55 -0
  153. omnibase_infra/handlers/models/model_graph_handler_response.py +98 -0
  154. omnibase_infra/handlers/models/model_handler_response.py +103 -0
  155. omnibase_infra/handlers/models/model_http_handler_response.py +101 -0
  156. omnibase_infra/handlers/models/model_manifest_metadata.py +75 -0
  157. omnibase_infra/handlers/models/model_manifest_persistence_config.py +62 -0
  158. omnibase_infra/handlers/models/model_manifest_query_payload.py +90 -0
  159. omnibase_infra/handlers/models/model_manifest_query_result.py +97 -0
  160. omnibase_infra/handlers/models/model_manifest_retrieve_payload.py +44 -0
  161. omnibase_infra/handlers/models/model_manifest_retrieve_result.py +98 -0
  162. omnibase_infra/handlers/models/model_manifest_store_payload.py +47 -0
  163. omnibase_infra/handlers/models/model_manifest_store_result.py +67 -0
  164. omnibase_infra/handlers/models/model_operation_context.py +187 -0
  165. omnibase_infra/handlers/models/model_qdrant_handler_response.py +98 -0
  166. omnibase_infra/handlers/models/model_retry_state.py +162 -0
  167. omnibase_infra/handlers/models/model_vault_handler_response.py +98 -0
  168. omnibase_infra/handlers/models/qdrant/__init__.py +44 -0
  169. omnibase_infra/handlers/models/qdrant/enum_qdrant_operation_type.py +26 -0
  170. omnibase_infra/handlers/models/qdrant/model_qdrant_collection_payload.py +42 -0
  171. omnibase_infra/handlers/models/qdrant/model_qdrant_delete_payload.py +36 -0
  172. omnibase_infra/handlers/models/qdrant/model_qdrant_handler_config.py +42 -0
  173. omnibase_infra/handlers/models/qdrant/model_qdrant_handler_payload.py +54 -0
  174. omnibase_infra/handlers/models/qdrant/model_qdrant_search_payload.py +42 -0
  175. omnibase_infra/handlers/models/qdrant/model_qdrant_search_result.py +30 -0
  176. omnibase_infra/handlers/models/qdrant/model_qdrant_upsert_payload.py +36 -0
  177. omnibase_infra/handlers/models/vault/__init__.py +69 -0
  178. omnibase_infra/handlers/models/vault/enum_vault_operation_type.py +35 -0
  179. omnibase_infra/handlers/models/vault/model_payload_vault.py +66 -0
  180. omnibase_infra/handlers/models/vault/model_vault_delete_payload.py +57 -0
  181. omnibase_infra/handlers/models/vault/model_vault_handler_config.py +148 -0
  182. omnibase_infra/handlers/models/vault/model_vault_handler_payload.py +101 -0
  183. omnibase_infra/handlers/models/vault/model_vault_list_payload.py +58 -0
  184. omnibase_infra/handlers/models/vault/model_vault_renew_token_payload.py +67 -0
  185. omnibase_infra/handlers/models/vault/model_vault_retry_config.py +66 -0
  186. omnibase_infra/handlers/models/vault/model_vault_secret_payload.py +106 -0
  187. omnibase_infra/handlers/models/vault/model_vault_write_payload.py +66 -0
  188. omnibase_infra/handlers/models/vault/registry_payload_vault.py +213 -0
  189. omnibase_infra/handlers/registration_storage/__init__.py +43 -0
  190. omnibase_infra/handlers/registration_storage/handler_registration_storage_mock.py +392 -0
  191. omnibase_infra/handlers/registration_storage/handler_registration_storage_postgres.py +915 -0
  192. omnibase_infra/handlers/registration_storage/models/__init__.py +23 -0
  193. omnibase_infra/handlers/registration_storage/models/model_delete_registration_request.py +58 -0
  194. omnibase_infra/handlers/registration_storage/models/model_update_registration_request.py +73 -0
  195. omnibase_infra/handlers/registration_storage/protocol_registration_persistence.py +191 -0
  196. omnibase_infra/handlers/service_discovery/__init__.py +43 -0
  197. omnibase_infra/handlers/service_discovery/handler_service_discovery_consul.py +747 -0
  198. omnibase_infra/handlers/service_discovery/handler_service_discovery_mock.py +258 -0
  199. omnibase_infra/handlers/service_discovery/models/__init__.py +22 -0
  200. omnibase_infra/handlers/service_discovery/models/model_discovery_result.py +64 -0
  201. omnibase_infra/handlers/service_discovery/models/model_registration_result.py +138 -0
  202. omnibase_infra/handlers/service_discovery/models/model_service_info.py +99 -0
  203. omnibase_infra/handlers/service_discovery/protocol_discovery_operations.py +170 -0
  204. omnibase_infra/idempotency/__init__.py +94 -0
  205. omnibase_infra/idempotency/models/__init__.py +43 -0
  206. omnibase_infra/idempotency/models/model_idempotency_check_result.py +85 -0
  207. omnibase_infra/idempotency/models/model_idempotency_guard_config.py +130 -0
  208. omnibase_infra/idempotency/models/model_idempotency_record.py +86 -0
  209. omnibase_infra/idempotency/models/model_idempotency_store_health_check_result.py +81 -0
  210. omnibase_infra/idempotency/models/model_idempotency_store_metrics.py +140 -0
  211. omnibase_infra/idempotency/models/model_postgres_idempotency_store_config.py +299 -0
  212. omnibase_infra/idempotency/protocol_idempotency_store.py +184 -0
  213. omnibase_infra/idempotency/store_inmemory.py +265 -0
  214. omnibase_infra/idempotency/store_postgres.py +923 -0
  215. omnibase_infra/infrastructure/__init__.py +0 -0
  216. omnibase_infra/mixins/__init__.py +71 -0
  217. omnibase_infra/mixins/mixin_async_circuit_breaker.py +655 -0
  218. omnibase_infra/mixins/mixin_dict_like_accessors.py +146 -0
  219. omnibase_infra/mixins/mixin_envelope_extraction.py +119 -0
  220. omnibase_infra/mixins/mixin_node_introspection.py +2465 -0
  221. omnibase_infra/mixins/mixin_retry_execution.py +386 -0
  222. omnibase_infra/mixins/protocol_circuit_breaker_aware.py +133 -0
  223. omnibase_infra/models/__init__.py +136 -0
  224. omnibase_infra/models/corpus/__init__.py +17 -0
  225. omnibase_infra/models/corpus/model_capture_config.py +133 -0
  226. omnibase_infra/models/corpus/model_capture_result.py +86 -0
  227. omnibase_infra/models/discovery/__init__.py +42 -0
  228. omnibase_infra/models/discovery/model_dependency_spec.py +319 -0
  229. omnibase_infra/models/discovery/model_discovered_capabilities.py +50 -0
  230. omnibase_infra/models/discovery/model_introspection_config.py +311 -0
  231. omnibase_infra/models/discovery/model_introspection_performance_metrics.py +169 -0
  232. omnibase_infra/models/discovery/model_introspection_task_config.py +116 -0
  233. omnibase_infra/models/dispatch/__init__.py +147 -0
  234. omnibase_infra/models/dispatch/model_dispatch_context.py +439 -0
  235. omnibase_infra/models/dispatch/model_dispatch_error.py +336 -0
  236. omnibase_infra/models/dispatch/model_dispatch_log_context.py +400 -0
  237. omnibase_infra/models/dispatch/model_dispatch_metadata.py +228 -0
  238. omnibase_infra/models/dispatch/model_dispatch_metrics.py +496 -0
  239. omnibase_infra/models/dispatch/model_dispatch_outcome.py +317 -0
  240. omnibase_infra/models/dispatch/model_dispatch_outputs.py +231 -0
  241. omnibase_infra/models/dispatch/model_dispatch_result.py +436 -0
  242. omnibase_infra/models/dispatch/model_dispatch_route.py +279 -0
  243. omnibase_infra/models/dispatch/model_dispatcher_metrics.py +275 -0
  244. omnibase_infra/models/dispatch/model_dispatcher_registration.py +352 -0
  245. omnibase_infra/models/dispatch/model_parsed_topic.py +135 -0
  246. omnibase_infra/models/dispatch/model_topic_parser.py +725 -0
  247. omnibase_infra/models/dispatch/model_tracing_context.py +285 -0
  248. omnibase_infra/models/errors/__init__.py +45 -0
  249. omnibase_infra/models/errors/model_handler_validation_error.py +594 -0
  250. omnibase_infra/models/errors/model_infra_error_context.py +99 -0
  251. omnibase_infra/models/errors/model_message_type_registry_error_context.py +71 -0
  252. omnibase_infra/models/errors/model_timeout_error_context.py +110 -0
  253. omnibase_infra/models/handlers/__init__.py +37 -0
  254. omnibase_infra/models/handlers/model_contract_discovery_result.py +80 -0
  255. omnibase_infra/models/handlers/model_handler_descriptor.py +185 -0
  256. omnibase_infra/models/handlers/model_handler_identifier.py +215 -0
  257. omnibase_infra/models/health/__init__.py +9 -0
  258. omnibase_infra/models/health/model_health_check_result.py +40 -0
  259. omnibase_infra/models/lifecycle/__init__.py +39 -0
  260. omnibase_infra/models/logging/__init__.py +51 -0
  261. omnibase_infra/models/logging/model_log_context.py +756 -0
  262. omnibase_infra/models/model_retry_error_classification.py +78 -0
  263. omnibase_infra/models/projection/__init__.py +43 -0
  264. omnibase_infra/models/projection/model_capability_fields.py +112 -0
  265. omnibase_infra/models/projection/model_registration_projection.py +434 -0
  266. omnibase_infra/models/projection/model_registration_snapshot.py +322 -0
  267. omnibase_infra/models/projection/model_sequence_info.py +182 -0
  268. omnibase_infra/models/projection/model_snapshot_topic_config.py +590 -0
  269. omnibase_infra/models/projectors/__init__.py +41 -0
  270. omnibase_infra/models/projectors/model_projector_column.py +289 -0
  271. omnibase_infra/models/projectors/model_projector_discovery_result.py +65 -0
  272. omnibase_infra/models/projectors/model_projector_index.py +270 -0
  273. omnibase_infra/models/projectors/model_projector_schema.py +415 -0
  274. omnibase_infra/models/projectors/model_projector_validation_error.py +63 -0
  275. omnibase_infra/models/projectors/util_sql_identifiers.py +115 -0
  276. omnibase_infra/models/registration/__init__.py +59 -0
  277. omnibase_infra/models/registration/commands/__init__.py +15 -0
  278. omnibase_infra/models/registration/commands/model_node_registration_acked.py +108 -0
  279. omnibase_infra/models/registration/events/__init__.py +56 -0
  280. omnibase_infra/models/registration/events/model_node_became_active.py +103 -0
  281. omnibase_infra/models/registration/events/model_node_liveness_expired.py +103 -0
  282. omnibase_infra/models/registration/events/model_node_registration_accepted.py +98 -0
  283. omnibase_infra/models/registration/events/model_node_registration_ack_received.py +98 -0
  284. omnibase_infra/models/registration/events/model_node_registration_ack_timed_out.py +112 -0
  285. omnibase_infra/models/registration/events/model_node_registration_initiated.py +107 -0
  286. omnibase_infra/models/registration/events/model_node_registration_rejected.py +104 -0
  287. omnibase_infra/models/registration/model_introspection_metrics.py +253 -0
  288. omnibase_infra/models/registration/model_node_capabilities.py +179 -0
  289. omnibase_infra/models/registration/model_node_heartbeat_event.py +126 -0
  290. omnibase_infra/models/registration/model_node_introspection_event.py +175 -0
  291. omnibase_infra/models/registration/model_node_metadata.py +79 -0
  292. omnibase_infra/models/registration/model_node_registration.py +162 -0
  293. omnibase_infra/models/registration/model_node_registration_record.py +162 -0
  294. omnibase_infra/models/registry/__init__.py +29 -0
  295. omnibase_infra/models/registry/model_domain_constraint.py +202 -0
  296. omnibase_infra/models/registry/model_message_type_entry.py +271 -0
  297. omnibase_infra/models/resilience/__init__.py +9 -0
  298. omnibase_infra/models/resilience/model_circuit_breaker_config.py +227 -0
  299. omnibase_infra/models/routing/__init__.py +25 -0
  300. omnibase_infra/models/routing/model_routing_entry.py +52 -0
  301. omnibase_infra/models/routing/model_routing_subcontract.py +70 -0
  302. omnibase_infra/models/runtime/__init__.py +40 -0
  303. omnibase_infra/models/runtime/model_contract_security_config.py +41 -0
  304. omnibase_infra/models/runtime/model_discovery_error.py +81 -0
  305. omnibase_infra/models/runtime/model_discovery_result.py +162 -0
  306. omnibase_infra/models/runtime/model_discovery_warning.py +74 -0
  307. omnibase_infra/models/runtime/model_failed_plugin_load.py +63 -0
  308. omnibase_infra/models/runtime/model_handler_contract.py +280 -0
  309. omnibase_infra/models/runtime/model_loaded_handler.py +120 -0
  310. omnibase_infra/models/runtime/model_plugin_load_context.py +93 -0
  311. omnibase_infra/models/runtime/model_plugin_load_summary.py +124 -0
  312. omnibase_infra/models/security/__init__.py +50 -0
  313. omnibase_infra/models/security/classification_levels.py +99 -0
  314. omnibase_infra/models/security/model_environment_policy.py +145 -0
  315. omnibase_infra/models/security/model_handler_security_policy.py +107 -0
  316. omnibase_infra/models/security/model_security_error.py +81 -0
  317. omnibase_infra/models/security/model_security_validation_result.py +328 -0
  318. omnibase_infra/models/security/model_security_warning.py +67 -0
  319. omnibase_infra/models/snapshot/__init__.py +27 -0
  320. omnibase_infra/models/snapshot/model_field_change.py +65 -0
  321. omnibase_infra/models/snapshot/model_snapshot.py +270 -0
  322. omnibase_infra/models/snapshot/model_snapshot_diff.py +203 -0
  323. omnibase_infra/models/snapshot/model_subject_ref.py +81 -0
  324. omnibase_infra/models/types/__init__.py +71 -0
  325. omnibase_infra/models/validation/__init__.py +89 -0
  326. omnibase_infra/models/validation/model_any_type_validation_result.py +118 -0
  327. omnibase_infra/models/validation/model_any_type_violation.py +141 -0
  328. omnibase_infra/models/validation/model_category_match_result.py +345 -0
  329. omnibase_infra/models/validation/model_chain_violation.py +166 -0
  330. omnibase_infra/models/validation/model_coverage_metrics.py +316 -0
  331. omnibase_infra/models/validation/model_execution_shape_rule.py +159 -0
  332. omnibase_infra/models/validation/model_execution_shape_validation.py +208 -0
  333. omnibase_infra/models/validation/model_execution_shape_validation_result.py +294 -0
  334. omnibase_infra/models/validation/model_execution_shape_violation.py +122 -0
  335. omnibase_infra/models/validation/model_localhandler_validation_result.py +139 -0
  336. omnibase_infra/models/validation/model_localhandler_violation.py +100 -0
  337. omnibase_infra/models/validation/model_output_validation_params.py +74 -0
  338. omnibase_infra/models/validation/model_validate_and_raise_params.py +84 -0
  339. omnibase_infra/models/validation/model_validation_error_params.py +84 -0
  340. omnibase_infra/models/validation/model_validation_outcome.py +287 -0
  341. omnibase_infra/nodes/__init__.py +48 -0
  342. omnibase_infra/nodes/architecture_validator/__init__.py +79 -0
  343. omnibase_infra/nodes/architecture_validator/contract.yaml +252 -0
  344. omnibase_infra/nodes/architecture_validator/contract_architecture_validator.yaml +208 -0
  345. omnibase_infra/nodes/architecture_validator/mixins/__init__.py +16 -0
  346. omnibase_infra/nodes/architecture_validator/mixins/mixin_file_path_rule.py +92 -0
  347. omnibase_infra/nodes/architecture_validator/models/__init__.py +36 -0
  348. omnibase_infra/nodes/architecture_validator/models/model_architecture_validation_request.py +56 -0
  349. omnibase_infra/nodes/architecture_validator/models/model_architecture_validation_result.py +311 -0
  350. omnibase_infra/nodes/architecture_validator/models/model_architecture_violation.py +163 -0
  351. omnibase_infra/nodes/architecture_validator/models/model_rule_check_result.py +265 -0
  352. omnibase_infra/nodes/architecture_validator/models/model_validation_request.py +105 -0
  353. omnibase_infra/nodes/architecture_validator/models/model_validation_result.py +314 -0
  354. omnibase_infra/nodes/architecture_validator/node.py +262 -0
  355. omnibase_infra/nodes/architecture_validator/node_architecture_validator.py +383 -0
  356. omnibase_infra/nodes/architecture_validator/protocols/__init__.py +9 -0
  357. omnibase_infra/nodes/architecture_validator/protocols/protocol_architecture_rule.py +225 -0
  358. omnibase_infra/nodes/architecture_validator/registry/__init__.py +28 -0
  359. omnibase_infra/nodes/architecture_validator/registry/registry_infra_architecture_validator.py +99 -0
  360. omnibase_infra/nodes/architecture_validator/validators/__init__.py +104 -0
  361. omnibase_infra/nodes/architecture_validator/validators/validator_no_direct_dispatch.py +422 -0
  362. omnibase_infra/nodes/architecture_validator/validators/validator_no_handler_publishing.py +481 -0
  363. omnibase_infra/nodes/architecture_validator/validators/validator_no_orchestrator_fsm.py +491 -0
  364. omnibase_infra/nodes/effects/README.md +358 -0
  365. omnibase_infra/nodes/effects/__init__.py +26 -0
  366. omnibase_infra/nodes/effects/contract.yaml +172 -0
  367. omnibase_infra/nodes/effects/models/__init__.py +32 -0
  368. omnibase_infra/nodes/effects/models/model_backend_result.py +190 -0
  369. omnibase_infra/nodes/effects/models/model_effect_idempotency_config.py +92 -0
  370. omnibase_infra/nodes/effects/models/model_registry_request.py +132 -0
  371. omnibase_infra/nodes/effects/models/model_registry_response.py +263 -0
  372. omnibase_infra/nodes/effects/protocol_consul_client.py +89 -0
  373. omnibase_infra/nodes/effects/protocol_effect_idempotency_store.py +143 -0
  374. omnibase_infra/nodes/effects/protocol_postgres_adapter.py +96 -0
  375. omnibase_infra/nodes/effects/registry_effect.py +525 -0
  376. omnibase_infra/nodes/effects/store_effect_idempotency_inmemory.py +425 -0
  377. omnibase_infra/nodes/node_registration_orchestrator/README.md +542 -0
  378. omnibase_infra/nodes/node_registration_orchestrator/__init__.py +120 -0
  379. omnibase_infra/nodes/node_registration_orchestrator/contract.yaml +475 -0
  380. omnibase_infra/nodes/node_registration_orchestrator/dispatchers/__init__.py +53 -0
  381. omnibase_infra/nodes/node_registration_orchestrator/dispatchers/dispatcher_node_introspected.py +376 -0
  382. omnibase_infra/nodes/node_registration_orchestrator/dispatchers/dispatcher_node_registration_acked.py +376 -0
  383. omnibase_infra/nodes/node_registration_orchestrator/dispatchers/dispatcher_runtime_tick.py +373 -0
  384. omnibase_infra/nodes/node_registration_orchestrator/handlers/__init__.py +62 -0
  385. omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_heartbeat.py +376 -0
  386. omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_introspected.py +609 -0
  387. omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_registration_acked.py +458 -0
  388. omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_runtime_tick.py +364 -0
  389. omnibase_infra/nodes/node_registration_orchestrator/introspection_event_router.py +544 -0
  390. omnibase_infra/nodes/node_registration_orchestrator/models/__init__.py +75 -0
  391. omnibase_infra/nodes/node_registration_orchestrator/models/model_consul_intent_payload.py +194 -0
  392. omnibase_infra/nodes/node_registration_orchestrator/models/model_consul_registration_intent.py +67 -0
  393. omnibase_infra/nodes/node_registration_orchestrator/models/model_intent_execution_result.py +50 -0
  394. omnibase_infra/nodes/node_registration_orchestrator/models/model_node_liveness_expired.py +107 -0
  395. omnibase_infra/nodes/node_registration_orchestrator/models/model_orchestrator_config.py +67 -0
  396. omnibase_infra/nodes/node_registration_orchestrator/models/model_orchestrator_input.py +41 -0
  397. omnibase_infra/nodes/node_registration_orchestrator/models/model_orchestrator_output.py +166 -0
  398. omnibase_infra/nodes/node_registration_orchestrator/models/model_postgres_intent_payload.py +235 -0
  399. omnibase_infra/nodes/node_registration_orchestrator/models/model_postgres_upsert_intent.py +68 -0
  400. omnibase_infra/nodes/node_registration_orchestrator/models/model_reducer_execution_result.py +384 -0
  401. omnibase_infra/nodes/node_registration_orchestrator/models/model_reducer_state.py +60 -0
  402. omnibase_infra/nodes/node_registration_orchestrator/models/model_registration_intent.py +177 -0
  403. omnibase_infra/nodes/node_registration_orchestrator/models/model_registry_intent.py +247 -0
  404. omnibase_infra/nodes/node_registration_orchestrator/node.py +195 -0
  405. omnibase_infra/nodes/node_registration_orchestrator/plugin.py +909 -0
  406. omnibase_infra/nodes/node_registration_orchestrator/protocols.py +439 -0
  407. omnibase_infra/nodes/node_registration_orchestrator/registry/__init__.py +41 -0
  408. omnibase_infra/nodes/node_registration_orchestrator/registry/registry_infra_node_registration_orchestrator.py +525 -0
  409. omnibase_infra/nodes/node_registration_orchestrator/timeout_coordinator.py +392 -0
  410. omnibase_infra/nodes/node_registration_orchestrator/wiring.py +742 -0
  411. omnibase_infra/nodes/node_registration_reducer/__init__.py +15 -0
  412. omnibase_infra/nodes/node_registration_reducer/contract.yaml +301 -0
  413. omnibase_infra/nodes/node_registration_reducer/models/__init__.py +38 -0
  414. omnibase_infra/nodes/node_registration_reducer/models/model_validation_result.py +113 -0
  415. omnibase_infra/nodes/node_registration_reducer/node.py +139 -0
  416. omnibase_infra/nodes/node_registration_reducer/registry/__init__.py +9 -0
  417. omnibase_infra/nodes/node_registration_reducer/registry/registry_infra_node_registration_reducer.py +79 -0
  418. omnibase_infra/nodes/node_registration_storage_effect/__init__.py +41 -0
  419. omnibase_infra/nodes/node_registration_storage_effect/contract.yaml +225 -0
  420. omnibase_infra/nodes/node_registration_storage_effect/models/__init__.py +44 -0
  421. omnibase_infra/nodes/node_registration_storage_effect/models/model_delete_result.py +132 -0
  422. omnibase_infra/nodes/node_registration_storage_effect/models/model_registration_record.py +199 -0
  423. omnibase_infra/nodes/node_registration_storage_effect/models/model_registration_update.py +155 -0
  424. omnibase_infra/nodes/node_registration_storage_effect/models/model_storage_health_check_details.py +123 -0
  425. omnibase_infra/nodes/node_registration_storage_effect/models/model_storage_health_check_result.py +117 -0
  426. omnibase_infra/nodes/node_registration_storage_effect/models/model_storage_query.py +100 -0
  427. omnibase_infra/nodes/node_registration_storage_effect/models/model_storage_result.py +136 -0
  428. omnibase_infra/nodes/node_registration_storage_effect/models/model_upsert_result.py +127 -0
  429. omnibase_infra/nodes/node_registration_storage_effect/node.py +109 -0
  430. omnibase_infra/nodes/node_registration_storage_effect/protocols/__init__.py +22 -0
  431. omnibase_infra/nodes/node_registration_storage_effect/protocols/protocol_registration_persistence.py +333 -0
  432. omnibase_infra/nodes/node_registration_storage_effect/registry/__init__.py +23 -0
  433. omnibase_infra/nodes/node_registration_storage_effect/registry/registry_infra_registration_storage.py +194 -0
  434. omnibase_infra/nodes/node_registry_effect/__init__.py +85 -0
  435. omnibase_infra/nodes/node_registry_effect/contract.yaml +682 -0
  436. omnibase_infra/nodes/node_registry_effect/handlers/__init__.py +70 -0
  437. omnibase_infra/nodes/node_registry_effect/handlers/handler_consul_deregister.py +211 -0
  438. omnibase_infra/nodes/node_registry_effect/handlers/handler_consul_register.py +212 -0
  439. omnibase_infra/nodes/node_registry_effect/handlers/handler_partial_retry.py +416 -0
  440. omnibase_infra/nodes/node_registry_effect/handlers/handler_postgres_deactivate.py +215 -0
  441. omnibase_infra/nodes/node_registry_effect/handlers/handler_postgres_upsert.py +208 -0
  442. omnibase_infra/nodes/node_registry_effect/models/__init__.py +43 -0
  443. omnibase_infra/nodes/node_registry_effect/models/model_partial_retry_request.py +92 -0
  444. omnibase_infra/nodes/node_registry_effect/node.py +165 -0
  445. omnibase_infra/nodes/node_registry_effect/registry/__init__.py +27 -0
  446. omnibase_infra/nodes/node_registry_effect/registry/registry_infra_registry_effect.py +196 -0
  447. omnibase_infra/nodes/node_service_discovery_effect/__init__.py +111 -0
  448. omnibase_infra/nodes/node_service_discovery_effect/contract.yaml +246 -0
  449. omnibase_infra/nodes/node_service_discovery_effect/models/__init__.py +67 -0
  450. omnibase_infra/nodes/node_service_discovery_effect/models/enum_health_status.py +72 -0
  451. omnibase_infra/nodes/node_service_discovery_effect/models/enum_service_discovery_operation.py +58 -0
  452. omnibase_infra/nodes/node_service_discovery_effect/models/model_discovery_query.py +99 -0
  453. omnibase_infra/nodes/node_service_discovery_effect/models/model_discovery_result.py +98 -0
  454. omnibase_infra/nodes/node_service_discovery_effect/models/model_health_check_config.py +121 -0
  455. omnibase_infra/nodes/node_service_discovery_effect/models/model_query_metadata.py +63 -0
  456. omnibase_infra/nodes/node_service_discovery_effect/models/model_registration_result.py +130 -0
  457. omnibase_infra/nodes/node_service_discovery_effect/models/model_service_discovery_health_check_details.py +111 -0
  458. omnibase_infra/nodes/node_service_discovery_effect/models/model_service_discovery_health_check_result.py +119 -0
  459. omnibase_infra/nodes/node_service_discovery_effect/models/model_service_info.py +106 -0
  460. omnibase_infra/nodes/node_service_discovery_effect/models/model_service_registration.py +121 -0
  461. omnibase_infra/nodes/node_service_discovery_effect/node.py +111 -0
  462. omnibase_infra/nodes/node_service_discovery_effect/protocols/__init__.py +14 -0
  463. omnibase_infra/nodes/node_service_discovery_effect/protocols/protocol_discovery_operations.py +279 -0
  464. omnibase_infra/nodes/node_service_discovery_effect/registry/__init__.py +13 -0
  465. omnibase_infra/nodes/node_service_discovery_effect/registry/registry_infra_service_discovery.py +214 -0
  466. omnibase_infra/nodes/reducers/__init__.py +30 -0
  467. omnibase_infra/nodes/reducers/models/__init__.py +32 -0
  468. omnibase_infra/nodes/reducers/models/model_payload_consul_register.py +76 -0
  469. omnibase_infra/nodes/reducers/models/model_payload_postgres_upsert_registration.py +60 -0
  470. omnibase_infra/nodes/reducers/models/model_registration_confirmation.py +166 -0
  471. omnibase_infra/nodes/reducers/models/model_registration_state.py +433 -0
  472. omnibase_infra/nodes/reducers/registration_reducer.py +1137 -0
  473. omnibase_infra/observability/__init__.py +143 -0
  474. omnibase_infra/observability/constants_metrics.py +91 -0
  475. omnibase_infra/observability/factory_observability_sink.py +525 -0
  476. omnibase_infra/observability/handlers/__init__.py +118 -0
  477. omnibase_infra/observability/handlers/handler_logging_structured.py +967 -0
  478. omnibase_infra/observability/handlers/handler_metrics_prometheus.py +1120 -0
  479. omnibase_infra/observability/handlers/model_logging_handler_config.py +71 -0
  480. omnibase_infra/observability/handlers/model_logging_handler_response.py +77 -0
  481. omnibase_infra/observability/handlers/model_metrics_handler_config.py +172 -0
  482. omnibase_infra/observability/handlers/model_metrics_handler_payload.py +135 -0
  483. omnibase_infra/observability/handlers/model_metrics_handler_response.py +101 -0
  484. omnibase_infra/observability/hooks/__init__.py +74 -0
  485. omnibase_infra/observability/hooks/hook_observability.py +1223 -0
  486. omnibase_infra/observability/models/__init__.py +30 -0
  487. omnibase_infra/observability/models/enum_required_log_context_key.py +77 -0
  488. omnibase_infra/observability/models/model_buffered_log_entry.py +117 -0
  489. omnibase_infra/observability/models/model_logging_sink_config.py +73 -0
  490. omnibase_infra/observability/models/model_metrics_sink_config.py +156 -0
  491. omnibase_infra/observability/sinks/__init__.py +69 -0
  492. omnibase_infra/observability/sinks/sink_logging_structured.py +809 -0
  493. omnibase_infra/observability/sinks/sink_metrics_prometheus.py +710 -0
  494. omnibase_infra/plugins/__init__.py +27 -0
  495. omnibase_infra/plugins/examples/__init__.py +28 -0
  496. omnibase_infra/plugins/examples/plugin_json_normalizer.py +271 -0
  497. omnibase_infra/plugins/examples/plugin_json_normalizer_error_handling.py +210 -0
  498. omnibase_infra/plugins/models/__init__.py +21 -0
  499. omnibase_infra/plugins/models/model_plugin_context.py +76 -0
  500. omnibase_infra/plugins/models/model_plugin_input_data.py +58 -0
  501. omnibase_infra/plugins/models/model_plugin_output_data.py +62 -0
  502. omnibase_infra/plugins/plugin_compute_base.py +435 -0
  503. omnibase_infra/projectors/__init__.py +30 -0
  504. omnibase_infra/projectors/contracts/__init__.py +63 -0
  505. omnibase_infra/projectors/contracts/registration_projector.yaml +370 -0
  506. omnibase_infra/projectors/projection_reader_registration.py +1559 -0
  507. omnibase_infra/projectors/snapshot_publisher_registration.py +1329 -0
  508. omnibase_infra/protocols/__init__.py +99 -0
  509. omnibase_infra/protocols/protocol_capability_projection.py +253 -0
  510. omnibase_infra/protocols/protocol_capability_query.py +251 -0
  511. omnibase_infra/protocols/protocol_event_bus_like.py +127 -0
  512. omnibase_infra/protocols/protocol_event_projector.py +96 -0
  513. omnibase_infra/protocols/protocol_idempotency_store.py +142 -0
  514. omnibase_infra/protocols/protocol_message_dispatcher.py +247 -0
  515. omnibase_infra/protocols/protocol_message_type_registry.py +306 -0
  516. omnibase_infra/protocols/protocol_plugin_compute.py +368 -0
  517. omnibase_infra/protocols/protocol_projector_schema_validator.py +82 -0
  518. omnibase_infra/protocols/protocol_registry_metrics.py +215 -0
  519. omnibase_infra/protocols/protocol_snapshot_publisher.py +396 -0
  520. omnibase_infra/protocols/protocol_snapshot_store.py +567 -0
  521. omnibase_infra/runtime/__init__.py +296 -0
  522. omnibase_infra/runtime/binding_config_resolver.py +2706 -0
  523. omnibase_infra/runtime/chain_aware_dispatch.py +467 -0
  524. omnibase_infra/runtime/contract_handler_discovery.py +582 -0
  525. omnibase_infra/runtime/contract_loaders/__init__.py +42 -0
  526. omnibase_infra/runtime/contract_loaders/handler_routing_loader.py +464 -0
  527. omnibase_infra/runtime/dispatch_context_enforcer.py +427 -0
  528. omnibase_infra/runtime/enums/__init__.py +18 -0
  529. omnibase_infra/runtime/enums/enum_config_ref_scheme.py +33 -0
  530. omnibase_infra/runtime/enums/enum_scheduler_status.py +170 -0
  531. omnibase_infra/runtime/envelope_validator.py +179 -0
  532. omnibase_infra/runtime/handler_contract_source.py +669 -0
  533. omnibase_infra/runtime/handler_plugin_loader.py +2029 -0
  534. omnibase_infra/runtime/handler_registry.py +321 -0
  535. omnibase_infra/runtime/invocation_security_enforcer.py +427 -0
  536. omnibase_infra/runtime/kernel.py +40 -0
  537. omnibase_infra/runtime/mixin_policy_validation.py +522 -0
  538. omnibase_infra/runtime/mixin_semver_cache.py +378 -0
  539. omnibase_infra/runtime/mixins/__init__.py +17 -0
  540. omnibase_infra/runtime/mixins/mixin_projector_sql_operations.py +757 -0
  541. omnibase_infra/runtime/models/__init__.py +192 -0
  542. omnibase_infra/runtime/models/model_batch_lifecycle_result.py +217 -0
  543. omnibase_infra/runtime/models/model_binding_config.py +168 -0
  544. omnibase_infra/runtime/models/model_binding_config_cache_stats.py +135 -0
  545. omnibase_infra/runtime/models/model_binding_config_resolver_config.py +329 -0
  546. omnibase_infra/runtime/models/model_cached_secret.py +138 -0
  547. omnibase_infra/runtime/models/model_compute_key.py +138 -0
  548. omnibase_infra/runtime/models/model_compute_registration.py +97 -0
  549. omnibase_infra/runtime/models/model_config_cache_entry.py +61 -0
  550. omnibase_infra/runtime/models/model_config_ref.py +331 -0
  551. omnibase_infra/runtime/models/model_config_ref_parse_result.py +125 -0
  552. omnibase_infra/runtime/models/model_domain_plugin_config.py +92 -0
  553. omnibase_infra/runtime/models/model_domain_plugin_result.py +270 -0
  554. omnibase_infra/runtime/models/model_duplicate_response.py +54 -0
  555. omnibase_infra/runtime/models/model_enabled_protocols_config.py +61 -0
  556. omnibase_infra/runtime/models/model_event_bus_config.py +54 -0
  557. omnibase_infra/runtime/models/model_failed_component.py +55 -0
  558. omnibase_infra/runtime/models/model_health_check_response.py +168 -0
  559. omnibase_infra/runtime/models/model_health_check_result.py +228 -0
  560. omnibase_infra/runtime/models/model_lifecycle_result.py +245 -0
  561. omnibase_infra/runtime/models/model_logging_config.py +42 -0
  562. omnibase_infra/runtime/models/model_optional_correlation_id.py +167 -0
  563. omnibase_infra/runtime/models/model_optional_string.py +94 -0
  564. omnibase_infra/runtime/models/model_optional_uuid.py +110 -0
  565. omnibase_infra/runtime/models/model_policy_context.py +100 -0
  566. omnibase_infra/runtime/models/model_policy_key.py +138 -0
  567. omnibase_infra/runtime/models/model_policy_registration.py +139 -0
  568. omnibase_infra/runtime/models/model_policy_result.py +103 -0
  569. omnibase_infra/runtime/models/model_policy_type_filter.py +157 -0
  570. omnibase_infra/runtime/models/model_projector_plugin_loader_config.py +47 -0
  571. omnibase_infra/runtime/models/model_protocol_registration_config.py +65 -0
  572. omnibase_infra/runtime/models/model_retry_policy.py +105 -0
  573. omnibase_infra/runtime/models/model_runtime_config.py +150 -0
  574. omnibase_infra/runtime/models/model_runtime_scheduler_config.py +624 -0
  575. omnibase_infra/runtime/models/model_runtime_scheduler_metrics.py +233 -0
  576. omnibase_infra/runtime/models/model_runtime_tick.py +193 -0
  577. omnibase_infra/runtime/models/model_secret_cache_stats.py +82 -0
  578. omnibase_infra/runtime/models/model_secret_mapping.py +63 -0
  579. omnibase_infra/runtime/models/model_secret_resolver_config.py +107 -0
  580. omnibase_infra/runtime/models/model_secret_resolver_metrics.py +111 -0
  581. omnibase_infra/runtime/models/model_secret_source_info.py +72 -0
  582. omnibase_infra/runtime/models/model_secret_source_spec.py +66 -0
  583. omnibase_infra/runtime/models/model_shutdown_batch_result.py +75 -0
  584. omnibase_infra/runtime/models/model_shutdown_config.py +94 -0
  585. omnibase_infra/runtime/projector_plugin_loader.py +1462 -0
  586. omnibase_infra/runtime/projector_schema_manager.py +565 -0
  587. omnibase_infra/runtime/projector_shell.py +1102 -0
  588. omnibase_infra/runtime/protocol_contract_descriptor.py +92 -0
  589. omnibase_infra/runtime/protocol_contract_source.py +92 -0
  590. omnibase_infra/runtime/protocol_domain_plugin.py +474 -0
  591. omnibase_infra/runtime/protocol_handler_discovery.py +221 -0
  592. omnibase_infra/runtime/protocol_handler_plugin_loader.py +327 -0
  593. omnibase_infra/runtime/protocol_lifecycle_executor.py +435 -0
  594. omnibase_infra/runtime/protocol_policy.py +366 -0
  595. omnibase_infra/runtime/protocols/__init__.py +27 -0
  596. omnibase_infra/runtime/protocols/protocol_runtime_scheduler.py +468 -0
  597. omnibase_infra/runtime/registry/__init__.py +93 -0
  598. omnibase_infra/runtime/registry/mixin_message_type_query.py +326 -0
  599. omnibase_infra/runtime/registry/mixin_message_type_registration.py +354 -0
  600. omnibase_infra/runtime/registry/registry_event_bus_binding.py +268 -0
  601. omnibase_infra/runtime/registry/registry_message_type.py +542 -0
  602. omnibase_infra/runtime/registry/registry_protocol_binding.py +444 -0
  603. omnibase_infra/runtime/registry_compute.py +1143 -0
  604. omnibase_infra/runtime/registry_dispatcher.py +678 -0
  605. omnibase_infra/runtime/registry_policy.py +1502 -0
  606. omnibase_infra/runtime/runtime_scheduler.py +1070 -0
  607. omnibase_infra/runtime/secret_resolver.py +2110 -0
  608. omnibase_infra/runtime/security_metadata_validator.py +776 -0
  609. omnibase_infra/runtime/service_kernel.py +1573 -0
  610. omnibase_infra/runtime/service_message_dispatch_engine.py +1805 -0
  611. omnibase_infra/runtime/service_runtime_host_process.py +2260 -0
  612. omnibase_infra/runtime/util_container_wiring.py +1123 -0
  613. omnibase_infra/runtime/util_validation.py +314 -0
  614. omnibase_infra/runtime/util_version.py +98 -0
  615. omnibase_infra/runtime/util_wiring.py +566 -0
  616. omnibase_infra/schemas/schema_registration_projection.sql +320 -0
  617. omnibase_infra/services/__init__.py +68 -0
  618. omnibase_infra/services/corpus_capture.py +678 -0
  619. omnibase_infra/services/service_capability_query.py +945 -0
  620. omnibase_infra/services/service_health.py +897 -0
  621. omnibase_infra/services/service_node_selector.py +530 -0
  622. omnibase_infra/services/service_timeout_emitter.py +682 -0
  623. omnibase_infra/services/service_timeout_scanner.py +390 -0
  624. omnibase_infra/services/snapshot/__init__.py +31 -0
  625. omnibase_infra/services/snapshot/service_snapshot.py +647 -0
  626. omnibase_infra/services/snapshot/store_inmemory.py +637 -0
  627. omnibase_infra/services/snapshot/store_postgres.py +1279 -0
  628. omnibase_infra/shared/__init__.py +8 -0
  629. omnibase_infra/testing/__init__.py +10 -0
  630. omnibase_infra/testing/utils.py +23 -0
  631. omnibase_infra/types/__init__.py +48 -0
  632. omnibase_infra/types/type_cache_info.py +49 -0
  633. omnibase_infra/types/type_dsn.py +173 -0
  634. omnibase_infra/types/type_infra_aliases.py +60 -0
  635. omnibase_infra/types/typed_dict/__init__.py +21 -0
  636. omnibase_infra/types/typed_dict/typed_dict_introspection_cache.py +128 -0
  637. omnibase_infra/types/typed_dict/typed_dict_performance_metrics_cache.py +140 -0
  638. omnibase_infra/types/typed_dict_capabilities.py +64 -0
  639. omnibase_infra/utils/__init__.py +89 -0
  640. omnibase_infra/utils/correlation.py +208 -0
  641. omnibase_infra/utils/util_datetime.py +372 -0
  642. omnibase_infra/utils/util_dsn_validation.py +333 -0
  643. omnibase_infra/utils/util_env_parsing.py +264 -0
  644. omnibase_infra/utils/util_error_sanitization.py +457 -0
  645. omnibase_infra/utils/util_pydantic_validators.py +477 -0
  646. omnibase_infra/utils/util_semver.py +233 -0
  647. omnibase_infra/validation/__init__.py +307 -0
  648. omnibase_infra/validation/enums/__init__.py +11 -0
  649. omnibase_infra/validation/enums/enum_contract_violation_severity.py +13 -0
  650. omnibase_infra/validation/infra_validators.py +1486 -0
  651. omnibase_infra/validation/linter_contract.py +907 -0
  652. omnibase_infra/validation/mixin_any_type_classification.py +120 -0
  653. omnibase_infra/validation/mixin_any_type_exemption.py +580 -0
  654. omnibase_infra/validation/mixin_any_type_reporting.py +106 -0
  655. omnibase_infra/validation/mixin_execution_shape_violation_checks.py +596 -0
  656. omnibase_infra/validation/mixin_node_archetype_detection.py +254 -0
  657. omnibase_infra/validation/models/__init__.py +15 -0
  658. omnibase_infra/validation/models/model_contract_lint_result.py +101 -0
  659. omnibase_infra/validation/models/model_contract_violation.py +41 -0
  660. omnibase_infra/validation/service_validation_aggregator.py +395 -0
  661. omnibase_infra/validation/validation_exemptions.yaml +1710 -0
  662. omnibase_infra/validation/validator_any_type.py +715 -0
  663. omnibase_infra/validation/validator_chain_propagation.py +839 -0
  664. omnibase_infra/validation/validator_execution_shape.py +465 -0
  665. omnibase_infra/validation/validator_localhandler.py +261 -0
  666. omnibase_infra/validation/validator_registration_security.py +410 -0
  667. omnibase_infra/validation/validator_routing_coverage.py +1020 -0
  668. omnibase_infra/validation/validator_runtime_shape.py +915 -0
  669. omnibase_infra/validation/validator_security.py +410 -0
  670. omnibase_infra/validation/validator_topic_category.py +1152 -0
  671. omnibase_infra-0.2.1.dist-info/METADATA +197 -0
  672. omnibase_infra-0.2.1.dist-info/RECORD +675 -0
  673. omnibase_infra-0.2.1.dist-info/WHEEL +4 -0
  674. omnibase_infra-0.2.1.dist-info/entry_points.txt +4 -0
  675. omnibase_infra-0.2.1.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,765 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2025 OmniNode Team
3
+ """Dead Letter Queue mixin for Kafka event bus.
4
+
5
+ This module provides DLQ functionality that can be mixed into EventBusKafka
6
+ to handle failed message processing. It supports metrics tracking, callback
7
+ hooks for custom alerting, and proper error sanitization.
8
+
9
+ Features:
10
+ - DLQ message publishing with comprehensive failure metadata
11
+ - Callback registration for custom alerting integration
12
+ - Metrics tracking for monitoring DLQ operations
13
+ - Error sanitization to prevent credential leakage
14
+ - Support for both processed and raw (deserialization failure) messages
15
+
16
+ Usage:
17
+ ```python
18
+ class EventBusKafka(MixinKafkaDlq, MixinAsyncCircuitBreaker):
19
+ def __init__(self, config):
20
+ # Initialize DLQ mixin
21
+ self._init_dlq()
22
+ # ... rest of init
23
+
24
+ # DLQ methods are now available:
25
+ # - register_dlq_callback()
26
+ # - dlq_metrics property
27
+ # - _publish_to_dlq()
28
+ # - _publish_raw_to_dlq()
29
+ ```
30
+
31
+ Design Note:
32
+ This mixin assumes the parent class has:
33
+ - self._config: ModelKafkaEventBusConfig with dead_letter_topic
34
+ - self._environment: str for environment context
35
+ - self._group: str for consumer group context
36
+ - self._producer: AIOKafkaProducer | None
37
+ - self._producer_lock: asyncio.Lock for producer access
38
+ - self._timeout_seconds: int for publish timeout
39
+ - self._model_headers_to_kafka(): Method to convert headers
40
+ """
41
+
42
+ from __future__ import annotations
43
+
44
+ import asyncio
45
+ import json
46
+ import logging
47
+ from collections.abc import Awaitable, Callable
48
+ from datetime import UTC, datetime
49
+ from typing import TYPE_CHECKING, Protocol, runtime_checkable
50
+ from uuid import UUID
51
+
52
+ from omnibase_infra.event_bus.models import (
53
+ ModelDlqEvent,
54
+ ModelDlqMetrics,
55
+ ModelEventHeaders,
56
+ ModelEventMessage,
57
+ )
58
+ from omnibase_infra.utils import sanitize_error_message
59
+
60
+ if TYPE_CHECKING:
61
+ from aiokafka import AIOKafkaProducer
62
+
63
+ from omnibase_infra.event_bus.models.config import ModelKafkaEventBusConfig
64
+
65
+
66
+ @runtime_checkable
67
+ class ProtocolKafkaDlqHost(Protocol):
68
+ """Protocol defining methods required by MixinKafkaDlq from its host class.
69
+
70
+ This protocol exists to satisfy mypy type checking for mixin classes that
71
+ call methods defined on the parent class (EventBusKafka). It also includes
72
+ attributes defined by the mixin itself that are accessed via self.
73
+ """
74
+
75
+ # Attributes from parent class (EventBusKafka)
76
+ _config: ModelKafkaEventBusConfig
77
+ _environment: str
78
+ _group: str
79
+ _producer: AIOKafkaProducer | None
80
+ _producer_lock: asyncio.Lock
81
+ _timeout_seconds: int
82
+
83
+ # Attributes defined by the mixin itself
84
+ _dlq_metrics: ModelDlqMetrics
85
+ _dlq_metrics_lock: asyncio.Lock
86
+
87
+ def _model_headers_to_kafka(
88
+ self, headers: ModelEventHeaders
89
+ ) -> list[tuple[str, bytes]]:
90
+ """Convert ModelEventHeaders to Kafka header format."""
91
+ ...
92
+
93
+ async def _invoke_dlq_callbacks(self, event: ModelDlqEvent) -> None:
94
+ """Invoke registered DLQ callbacks."""
95
+ ...
96
+
97
+
98
+ # Type alias for DLQ callback functions
99
+ DlqCallbackType = Callable[[ModelDlqEvent], Awaitable[None]]
100
+
101
+ logger = logging.getLogger(__name__)
102
+
103
+
104
+ class MixinKafkaDlq:
105
+ """Mixin providing Dead Letter Queue functionality for Kafka event bus.
106
+
107
+ This mixin adds DLQ message publishing, callback registration, and metrics
108
+ tracking capabilities to a Kafka event bus implementation.
109
+
110
+ Attributes provided by mixin:
111
+ dlq_metrics: Property returning current DLQ metrics (copy-on-write)
112
+
113
+ Methods provided by mixin:
114
+ register_dlq_callback: Register callback for DLQ events
115
+ _publish_to_dlq: Publish failed message to DLQ
116
+ _publish_raw_to_dlq: Publish raw message (deserialization failure) to DLQ
117
+ _invoke_dlq_callbacks: Invoke registered callbacks with error isolation
118
+
119
+ Required attributes from parent class:
120
+ _config: ModelKafkaEventBusConfig with dead_letter_topic
121
+ _environment: str for environment context
122
+ _group: str for consumer group context
123
+ _producer: AIOKafkaProducer | None
124
+ _producer_lock: asyncio.Lock for producer access
125
+ _timeout_seconds: int for publish timeout
126
+ _model_headers_to_kafka: Method to convert headers to Kafka format
127
+ """
128
+
129
+ # Type hints for attributes expected from parent class
130
+ _config: ModelKafkaEventBusConfig
131
+ _environment: str
132
+ _group: str
133
+ _producer: AIOKafkaProducer | None
134
+ _producer_lock: asyncio.Lock
135
+ _timeout_seconds: int
136
+
137
+ def _init_dlq(self) -> None:
138
+ """Initialize DLQ mixin state.
139
+
140
+ Must be called during __init__ of the parent class.
141
+ """
142
+ # DLQ metrics tracking (copy-on-write pattern)
143
+ self._dlq_metrics = ModelDlqMetrics.create_empty()
144
+ self._dlq_metrics_lock = asyncio.Lock()
145
+
146
+ # DLQ callback hooks for custom alerting integration
147
+ self._dlq_callbacks: list[DlqCallbackType] = []
148
+ self._dlq_callbacks_lock = asyncio.Lock()
149
+
150
+ @property
151
+ def dlq_metrics(self) -> ModelDlqMetrics:
152
+ """Get a deep copy of the current DLQ metrics.
153
+
154
+ Returns a deep copy of the metrics to prevent unintended mutation
155
+ from external code. Deep copy ensures nested dicts (topic_counts,
156
+ error_type_counts) are also copied. Thread-safe access to metrics data.
157
+
158
+ Returns:
159
+ Deep copy of the current DLQ metrics
160
+ """
161
+ return self._dlq_metrics.model_copy(deep=True)
162
+
163
+ async def register_dlq_callback(
164
+ self,
165
+ callback: DlqCallbackType,
166
+ ) -> Callable[[], Awaitable[None]]:
167
+ """Register a callback to be invoked when messages are sent to DLQ.
168
+
169
+ Callbacks receive a ModelDlqEvent containing comprehensive context
170
+ about the DLQ operation, including success/failure status, original
171
+ topic, error information, and correlation ID for tracing.
172
+
173
+ Callbacks are invoked asynchronously after DLQ publish completes.
174
+ If a callback raises an exception, it is logged but does not affect
175
+ other callbacks or the DLQ publish operation.
176
+
177
+ Args:
178
+ callback: Async function that receives ModelDlqEvent
179
+
180
+ Returns:
181
+ Async function to unregister the callback
182
+
183
+ Example:
184
+ ```python
185
+ async def alert_on_dlq(event: ModelDlqEvent) -> None:
186
+ if event.is_critical:
187
+ await pagerduty.trigger(
188
+ summary=f"DLQ publish failed: {event.dlq_error_type}",
189
+ severity="critical",
190
+ )
191
+ else:
192
+ logger.warning("Message sent to DLQ", extra=event.to_log_context())
193
+
194
+ unregister = await bus.register_dlq_callback(alert_on_dlq)
195
+ # Later, to unregister:
196
+ await unregister()
197
+ ```
198
+ """
199
+ async with self._dlq_callbacks_lock:
200
+ self._dlq_callbacks.append(callback)
201
+
202
+ async def unregister() -> None:
203
+ async with self._dlq_callbacks_lock:
204
+ if callback in self._dlq_callbacks:
205
+ self._dlq_callbacks.remove(callback)
206
+
207
+ return unregister
208
+
209
+ async def _publish_to_dlq(
210
+ self: ProtocolKafkaDlqHost,
211
+ original_topic: str,
212
+ failed_message: ModelEventMessage,
213
+ error: Exception,
214
+ correlation_id: UUID,
215
+ ) -> None:
216
+ """Publish failed message to dead letter queue with metrics and alerting.
217
+
218
+ This method publishes messages that failed processing to the configured
219
+ dead letter queue topic with comprehensive failure metadata for later
220
+ analysis and retry. If DLQ publishing fails, the error is logged but
221
+ does not crash the consumer.
222
+
223
+ Features:
224
+ - Structured logging with appropriate log levels (WARNING/ERROR)
225
+ - Metrics tracking (dlq.messages.published, dlq.messages.failed)
226
+ - Callback hooks for custom alerting integration
227
+ - Correlation ID included in all log entries for tracing
228
+
229
+ Args:
230
+ original_topic: Original topic where message was consumed from.
231
+ Must be a non-empty, non-whitespace string.
232
+ failed_message: The message that failed processing
233
+ error: The exception that caused the failure
234
+ correlation_id: Correlation ID for tracking
235
+
236
+ Note:
237
+ This method logs errors if DLQ publishing fails but does not raise
238
+ exceptions to prevent cascading failures in the consumer loop.
239
+ """
240
+ # Validate original_topic - reject whitespace-only values
241
+ if not original_topic or not original_topic.strip():
242
+ logger.error(
243
+ "DLQ publish rejected: original_topic is empty or whitespace-only",
244
+ extra={
245
+ "correlation_id": str(correlation_id),
246
+ "error_type": type(error).__name__,
247
+ },
248
+ )
249
+ return
250
+
251
+ # Track timing for metrics
252
+ start_time = datetime.now(UTC)
253
+ error_type = type(error).__name__
254
+
255
+ # Get DLQ topic using convention-based resolution
256
+ # This supports both explicit dead_letter_topic config and automatic
257
+ # topic generation following ONEX conventions: <env>.dlq.<category>.v1
258
+ dlq_topic = self._config.get_dlq_topic()
259
+
260
+ # Sanitize error message to prevent credential leakage in DLQ
261
+ sanitized_failure_reason = sanitize_error_message(error)
262
+
263
+ # Defensive decode for key and value to handle edge cases
264
+ # This matches the pattern in _publish_raw_to_dlq for consistency
265
+ try:
266
+ key_str = (
267
+ failed_message.key.decode("utf-8", errors="replace")
268
+ if failed_message.key
269
+ else None
270
+ )
271
+ except Exception:
272
+ key_str = "<decode_failed>"
273
+
274
+ try:
275
+ value_str = (
276
+ failed_message.value.decode("utf-8", errors="replace")
277
+ if failed_message.value
278
+ else "<no_value>"
279
+ )
280
+ except Exception:
281
+ value_str = "<decode_failed>"
282
+
283
+ # Build DLQ message with failure metadata
284
+ dlq_payload = {
285
+ "original_topic": original_topic,
286
+ "original_message": {
287
+ "key": key_str,
288
+ "value": value_str,
289
+ "offset": failed_message.offset,
290
+ "partition": failed_message.partition,
291
+ },
292
+ "failure_reason": sanitized_failure_reason,
293
+ "failure_timestamp": start_time.isoformat(),
294
+ "correlation_id": str(correlation_id),
295
+ "retry_count": failed_message.headers.retry_count,
296
+ "error_type": error_type,
297
+ }
298
+
299
+ # Create DLQ headers with failure metadata
300
+ dlq_headers = ModelEventHeaders(
301
+ source=f"{self._environment}.{self._group}",
302
+ event_type="dlq_message",
303
+ content_type="application/json",
304
+ correlation_id=correlation_id,
305
+ timestamp=datetime.now(UTC),
306
+ )
307
+
308
+ # Convert DLQ payload to JSON bytes with explicit error handling
309
+ # for non-serializable content
310
+ try:
311
+ dlq_value = json.dumps(dlq_payload).encode("utf-8")
312
+ except (TypeError, ValueError) as json_error:
313
+ # Handle non-serializable envelope content by falling back to repr
314
+ logger.warning(
315
+ "DLQ payload contains non-serializable data, using repr fallback",
316
+ extra={
317
+ "correlation_id": str(correlation_id),
318
+ "original_topic": original_topic,
319
+ "json_error": str(json_error),
320
+ },
321
+ )
322
+ # Create a safe fallback payload with repr of original values
323
+ fallback_payload = {
324
+ "original_topic": original_topic,
325
+ "original_message": {
326
+ "key": repr(key_str),
327
+ "value": "<non-serializable>",
328
+ "offset": failed_message.offset,
329
+ "partition": failed_message.partition,
330
+ },
331
+ "failure_reason": sanitized_failure_reason,
332
+ "failure_timestamp": start_time.isoformat(),
333
+ "correlation_id": str(correlation_id),
334
+ "retry_count": failed_message.headers.retry_count,
335
+ "error_type": error_type,
336
+ "serialization_fallback": True,
337
+ }
338
+ dlq_value = json.dumps(fallback_payload).encode("utf-8")
339
+
340
+ # Variables for event creation
341
+ success = False
342
+ dlq_error_type: str | None = None
343
+ dlq_error_message: str | None = None
344
+
345
+ # Publish to DLQ (without retry - best effort)
346
+ # Capture producer reference and headers under lock, then send outside lock
347
+ producer = None
348
+ kafka_headers: list[tuple[str, bytes]] | None = None
349
+ try:
350
+ async with self._producer_lock:
351
+ if self._producer is None:
352
+ dlq_error_type = "ProducerUnavailable"
353
+ dlq_error_message = "Producer not initialized or closed"
354
+ logger.error(
355
+ "DLQ publish failed: producer not available",
356
+ extra={
357
+ "original_topic": original_topic,
358
+ "dlq_topic": dlq_topic,
359
+ "correlation_id": str(correlation_id),
360
+ "error_type": error_type,
361
+ "retry_count": failed_message.headers.retry_count,
362
+ },
363
+ )
364
+ else:
365
+ kafka_headers = self._model_headers_to_kafka(dlq_headers)
366
+ kafka_headers.extend(
367
+ [
368
+ ("original_topic", original_topic.encode("utf-8")),
369
+ (
370
+ "failure_reason",
371
+ sanitized_failure_reason.encode("utf-8"),
372
+ ),
373
+ (
374
+ "failure_timestamp",
375
+ start_time.isoformat().encode("utf-8"),
376
+ ),
377
+ ]
378
+ )
379
+ producer = self._producer
380
+
381
+ # Send and wait for completion with timeout (outside producer lock)
382
+ # Using send_and_wait() wrapped in wait_for() for cleaner timeout handling
383
+ if producer is not None and kafka_headers is not None:
384
+ await asyncio.wait_for(
385
+ producer.send_and_wait(
386
+ dlq_topic,
387
+ value=dlq_value,
388
+ key=failed_message.key,
389
+ headers=kafka_headers,
390
+ ),
391
+ timeout=self._timeout_seconds,
392
+ )
393
+ success = True
394
+
395
+ except Exception as dlq_error:
396
+ dlq_error_type = type(dlq_error).__name__
397
+ dlq_error_message = sanitize_error_message(dlq_error)
398
+ logger.exception(
399
+ "DLQ publish failed: message may be lost",
400
+ extra={
401
+ "original_topic": original_topic,
402
+ "dlq_topic": dlq_topic,
403
+ "correlation_id": str(correlation_id),
404
+ "error_type": error_type,
405
+ "dlq_error_type": dlq_error_type,
406
+ "dlq_error_message": dlq_error_message,
407
+ "retry_count": failed_message.headers.retry_count,
408
+ "message_offset": failed_message.offset,
409
+ "message_partition": failed_message.partition,
410
+ },
411
+ )
412
+
413
+ # Calculate duration for metrics
414
+ end_time = datetime.now(UTC)
415
+ duration_ms = (end_time - start_time).total_seconds() * 1000
416
+
417
+ # Log successful DLQ publish at WARNING level
418
+ if success:
419
+ logger.warning(
420
+ "Message published to DLQ due to processing failure",
421
+ extra={
422
+ "original_topic": original_topic,
423
+ "dlq_topic": dlq_topic,
424
+ "correlation_id": str(correlation_id),
425
+ "error_type": error_type,
426
+ "error_message": sanitized_failure_reason,
427
+ "retry_count": failed_message.headers.retry_count,
428
+ "message_offset": failed_message.offset,
429
+ "message_partition": failed_message.partition,
430
+ "duration_ms": round(duration_ms, 2),
431
+ },
432
+ )
433
+
434
+ # Create DLQ event for metrics and callbacks
435
+ # Convert message_offset to string for type consistency with ModelDlqEvent
436
+ # (which expects str | None) and consistency with _publish_raw_to_dlq
437
+ message_offset_str = (
438
+ str(failed_message.offset) if failed_message.offset is not None else None
439
+ )
440
+ dlq_event = ModelDlqEvent(
441
+ original_topic=original_topic,
442
+ dlq_topic=dlq_topic,
443
+ correlation_id=correlation_id,
444
+ error_type=error_type,
445
+ error_message=sanitized_failure_reason,
446
+ retry_count=failed_message.headers.retry_count,
447
+ message_offset=message_offset_str,
448
+ message_partition=failed_message.partition,
449
+ success=success,
450
+ dlq_error_type=dlq_error_type,
451
+ dlq_error_message=dlq_error_message,
452
+ timestamp=end_time,
453
+ environment=self._environment,
454
+ consumer_group=self._group,
455
+ )
456
+
457
+ # Update DLQ metrics (copy-on-write pattern)
458
+ async with self._dlq_metrics_lock:
459
+ self._dlq_metrics = self._dlq_metrics.record_dlq_publish(
460
+ original_topic=original_topic,
461
+ error_type=error_type,
462
+ success=success,
463
+ duration_ms=duration_ms,
464
+ )
465
+
466
+ # Invoke DLQ callbacks for custom alerting
467
+ await self._invoke_dlq_callbacks(dlq_event)
468
+
469
+ async def _invoke_dlq_callbacks(self, event: ModelDlqEvent) -> None:
470
+ """Invoke registered DLQ callbacks with error isolation.
471
+
472
+ Callbacks are invoked sequentially. If a callback raises an exception,
473
+ it is logged but does not prevent other callbacks from executing.
474
+
475
+ Args:
476
+ event: The DLQ event to pass to callbacks
477
+ """
478
+ # Get a copy of callbacks under lock
479
+ async with self._dlq_callbacks_lock:
480
+ callbacks = list(self._dlq_callbacks)
481
+
482
+ for callback in callbacks:
483
+ try:
484
+ await callback(event)
485
+ except Exception as callback_error:
486
+ logger.warning(
487
+ "DLQ callback raised exception",
488
+ extra={
489
+ "callback": getattr(callback, "__name__", str(callback)),
490
+ "correlation_id": str(event.correlation_id),
491
+ "original_topic": event.original_topic,
492
+ "callback_error_type": type(callback_error).__name__,
493
+ "callback_error_message": sanitize_error_message(
494
+ callback_error
495
+ ),
496
+ },
497
+ exc_info=True,
498
+ )
499
+
500
+ async def _publish_raw_to_dlq(
501
+ self: ProtocolKafkaDlqHost,
502
+ original_topic: str,
503
+ raw_msg: object,
504
+ error: Exception,
505
+ correlation_id: UUID,
506
+ failure_type: str,
507
+ ) -> None:
508
+ """Publish raw Kafka message to DLQ when deserialization fails.
509
+
510
+ This method handles cases where message conversion fails before we have
511
+ a ModelEventMessage. It extracts raw data directly from the Kafka
512
+ ConsumerRecord for DLQ payload construction.
513
+
514
+ Args:
515
+ original_topic: Original topic where message was consumed from.
516
+ Must be a non-empty, non-whitespace string.
517
+ raw_msg: Raw Kafka ConsumerRecord that failed conversion
518
+ error: The exception that caused the failure
519
+ correlation_id: Correlation ID for tracking
520
+ failure_type: Type of failure (e.g., "deserialization_error")
521
+
522
+ Note:
523
+ This method logs errors if DLQ publishing fails but does not raise
524
+ exceptions to prevent cascading failures in the consumer loop.
525
+ """
526
+ # Validate original_topic - reject whitespace-only values
527
+ if not original_topic or not original_topic.strip():
528
+ logger.error(
529
+ "DLQ publish rejected: original_topic is empty or whitespace-only",
530
+ extra={
531
+ "correlation_id": str(correlation_id),
532
+ "error_type": type(error).__name__,
533
+ "failure_type": failure_type,
534
+ },
535
+ )
536
+ return
537
+
538
+ # Track timing for metrics
539
+ start_time = datetime.now(UTC)
540
+ error_type = type(error).__name__
541
+
542
+ # Get DLQ topic using convention-based resolution
543
+ # This supports both explicit dead_letter_topic config and automatic
544
+ # topic generation following ONEX conventions: <env>.dlq.<category>.v1
545
+ dlq_topic = self._config.get_dlq_topic()
546
+
547
+ # Sanitize error message
548
+ sanitized_failure_reason = sanitize_error_message(error)
549
+
550
+ # Extract raw data from Kafka message
551
+ raw_key = getattr(raw_msg, "key", None)
552
+ raw_value = getattr(raw_msg, "value", b"")
553
+ raw_offset = getattr(raw_msg, "offset", None)
554
+ raw_partition = getattr(raw_msg, "partition", None)
555
+
556
+ # Safe decode with error replacement
557
+ try:
558
+ key_str = (
559
+ raw_key.decode("utf-8", errors="replace")
560
+ if isinstance(raw_key, bytes)
561
+ else str(raw_key)
562
+ if raw_key is not None
563
+ else None
564
+ )
565
+ except Exception:
566
+ key_str = "<decode_failed>"
567
+
568
+ try:
569
+ value_str = (
570
+ raw_value.decode("utf-8", errors="replace")
571
+ if isinstance(raw_value, bytes)
572
+ else str(raw_value)
573
+ )
574
+ except Exception:
575
+ value_str = "<decode_failed>"
576
+
577
+ # Build DLQ message with failure metadata
578
+ dlq_payload = {
579
+ "original_topic": original_topic,
580
+ "original_message": {
581
+ "key": key_str,
582
+ "value": value_str,
583
+ "offset": raw_offset,
584
+ "partition": raw_partition,
585
+ },
586
+ "failure_reason": sanitized_failure_reason,
587
+ "failure_type": failure_type,
588
+ "failure_timestamp": start_time.isoformat(),
589
+ "correlation_id": str(correlation_id),
590
+ "retry_count": 0,
591
+ "error_type": error_type,
592
+ }
593
+
594
+ # Create DLQ headers
595
+ dlq_headers = ModelEventHeaders(
596
+ source=f"{self._environment}.{self._group}",
597
+ event_type="dlq_raw_message",
598
+ content_type="application/json",
599
+ correlation_id=correlation_id,
600
+ timestamp=start_time,
601
+ )
602
+
603
+ # Convert DLQ payload to JSON bytes with explicit error handling
604
+ # for non-serializable content
605
+ try:
606
+ dlq_value = json.dumps(dlq_payload).encode("utf-8")
607
+ except (TypeError, ValueError) as json_error:
608
+ # Handle non-serializable envelope content by falling back to repr
609
+ logger.warning(
610
+ "DLQ raw payload contains non-serializable data, using repr fallback",
611
+ extra={
612
+ "correlation_id": str(correlation_id),
613
+ "original_topic": original_topic,
614
+ "failure_type": failure_type,
615
+ "json_error": str(json_error),
616
+ },
617
+ )
618
+ # Create a safe fallback payload with repr of original values
619
+ fallback_payload = {
620
+ "original_topic": original_topic,
621
+ "original_message": {
622
+ "key": repr(key_str),
623
+ "value": "<non-serializable>",
624
+ "offset": raw_offset,
625
+ "partition": raw_partition,
626
+ },
627
+ "failure_reason": sanitized_failure_reason,
628
+ "failure_type": failure_type,
629
+ "failure_timestamp": start_time.isoformat(),
630
+ "correlation_id": str(correlation_id),
631
+ "retry_count": 0,
632
+ "error_type": error_type,
633
+ "serialization_fallback": True,
634
+ }
635
+ dlq_value = json.dumps(fallback_payload).encode("utf-8")
636
+ dlq_key = raw_key if isinstance(raw_key, bytes) else None
637
+
638
+ # Variables for event creation
639
+ success = False
640
+ dlq_error_type: str | None = None
641
+ dlq_error_message: str | None = None
642
+
643
+ # Publish to DLQ
644
+ # Capture producer reference and headers under lock, then send outside lock
645
+ producer = None
646
+ kafka_headers: list[tuple[str, bytes]] | None = None
647
+ try:
648
+ async with self._producer_lock:
649
+ if self._producer is None:
650
+ dlq_error_type = "ProducerUnavailable"
651
+ dlq_error_message = "Producer not initialized or closed"
652
+ logger.error(
653
+ "DLQ publish failed: producer not available for raw message",
654
+ extra={
655
+ "original_topic": original_topic,
656
+ "dlq_topic": dlq_topic,
657
+ "correlation_id": str(correlation_id),
658
+ "error_type": error_type,
659
+ "failure_type": failure_type,
660
+ },
661
+ )
662
+ else:
663
+ kafka_headers = self._model_headers_to_kafka(dlq_headers)
664
+ kafka_headers.extend(
665
+ [
666
+ ("original_topic", original_topic.encode("utf-8")),
667
+ ("failure_type", failure_type.encode("utf-8")),
668
+ (
669
+ "failure_reason",
670
+ sanitized_failure_reason.encode("utf-8"),
671
+ ),
672
+ (
673
+ "failure_timestamp",
674
+ start_time.isoformat().encode("utf-8"),
675
+ ),
676
+ ]
677
+ )
678
+ producer = self._producer
679
+
680
+ # Send and wait for completion with timeout (outside producer lock)
681
+ # Using send_and_wait() wrapped in wait_for() for cleaner timeout handling
682
+ if producer is not None and kafka_headers is not None:
683
+ await asyncio.wait_for(
684
+ producer.send_and_wait(
685
+ dlq_topic,
686
+ value=dlq_value,
687
+ key=dlq_key,
688
+ headers=kafka_headers,
689
+ ),
690
+ timeout=self._timeout_seconds,
691
+ )
692
+ success = True
693
+
694
+ except Exception as dlq_error:
695
+ dlq_error_type = type(dlq_error).__name__
696
+ dlq_error_message = sanitize_error_message(dlq_error)
697
+ logger.exception(
698
+ "DLQ publish failed for raw message: message may be lost",
699
+ extra={
700
+ "original_topic": original_topic,
701
+ "dlq_topic": dlq_topic,
702
+ "correlation_id": str(correlation_id),
703
+ "error_type": error_type,
704
+ "failure_type": failure_type,
705
+ "dlq_error_type": dlq_error_type,
706
+ "dlq_error_message": dlq_error_message,
707
+ "message_offset": raw_offset,
708
+ "message_partition": raw_partition,
709
+ },
710
+ )
711
+
712
+ # Calculate duration for metrics
713
+ end_time = datetime.now(UTC)
714
+ duration_ms = (end_time - start_time).total_seconds() * 1000
715
+
716
+ # Log successful DLQ publish
717
+ if success:
718
+ logger.warning(
719
+ "Raw message published to DLQ due to deserialization/validation failure",
720
+ extra={
721
+ "original_topic": original_topic,
722
+ "dlq_topic": dlq_topic,
723
+ "correlation_id": str(correlation_id),
724
+ "error_type": error_type,
725
+ "error_message": sanitized_failure_reason,
726
+ "failure_type": failure_type,
727
+ "message_offset": raw_offset,
728
+ "message_partition": raw_partition,
729
+ "duration_ms": round(duration_ms, 2),
730
+ },
731
+ )
732
+
733
+ # Create DLQ event for metrics and callbacks
734
+ message_offset_str = str(raw_offset) if raw_offset is not None else None
735
+ dlq_event = ModelDlqEvent(
736
+ original_topic=original_topic,
737
+ dlq_topic=dlq_topic,
738
+ correlation_id=correlation_id,
739
+ error_type=error_type,
740
+ error_message=sanitized_failure_reason,
741
+ retry_count=0,
742
+ message_offset=message_offset_str,
743
+ message_partition=raw_partition,
744
+ success=success,
745
+ dlq_error_type=dlq_error_type,
746
+ dlq_error_message=dlq_error_message,
747
+ timestamp=end_time,
748
+ environment=self._environment,
749
+ consumer_group=self._group,
750
+ )
751
+
752
+ # Update DLQ metrics
753
+ async with self._dlq_metrics_lock:
754
+ self._dlq_metrics = self._dlq_metrics.record_dlq_publish(
755
+ original_topic=original_topic,
756
+ error_type=error_type,
757
+ success=success,
758
+ duration_ms=duration_ms,
759
+ )
760
+
761
+ # Invoke DLQ callbacks
762
+ await self._invoke_dlq_callbacks(dlq_event)
763
+
764
+
765
+ __all__: list[str] = ["MixinKafkaDlq", "DlqCallbackType"]