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,1138 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2025 OmniNode Team
3
+ """Canonical Registration Reducer following ProtocolReducer pattern.
4
+
5
+ This reducer replaces the legacy NodeDualRegistrationReducer (887 lines)
6
+ with a pure function implementation (~80 lines) that follows the canonical
7
+ ONEX reducer pattern defined in DESIGN_TWO_WAY_REGISTRATION_ARCHITECTURE.md.
8
+
9
+ Performance Characteristics:
10
+ This reducer is designed for high-performance event processing with the
11
+ following targets:
12
+
13
+ - reduce() processing: <300ms per event (target)
14
+ - Intent building: <50ms per intent (includes Consul + PostgreSQL)
15
+ - Idempotency check: <1ms
16
+
17
+ Performance is logged when thresholds are exceeded. These thresholds are
18
+ configurable via module-level constants (PERF_THRESHOLD_*).
19
+
20
+ Typical performance on standard hardware:
21
+ - Simple introspection events: ~0.1-1ms
22
+ - Complex events with full metadata: ~1-5ms
23
+ - Hash-based event ID derivation: ~0.01ms
24
+
25
+ Circuit Breaker Considerations:
26
+ This reducer does NOT require a circuit breaker because:
27
+
28
+ 1. **Pure Function Pattern**: Reducers are pure functions - they perform
29
+ NO I/O operations. All external interactions are delegated to the
30
+ Effect layer via emitted intents.
31
+
32
+ 2. **No Transient Failures**: Without I/O, there are no transient failures
33
+ to recover from. Circuit breakers are designed for I/O resilience.
34
+
35
+ 3. **Deterministic Behavior**: Given the same state and event, the reducer
36
+ always produces the same output. There's no "retry" semantic.
37
+
38
+ 4. **Effect Layer Responsibility**: Circuit breakers should be implemented
39
+ in the Effect layer nodes (ConsulAdapter, PostgresAdapter) that actually
40
+ perform the external I/O operations.
41
+
42
+ See CLAUDE.md "Dispatcher Resilience Pattern" section for the general
43
+ principle: "Dispatchers own their own resilience."
44
+
45
+ Architecture:
46
+ - Pure function: reduce(state, event) -> ModelReducerOutput
47
+ - No internal state - state passed in and returned
48
+ - No I/O - emits intents for Effect layer
49
+ - Deterministic - same inputs produce same outputs
50
+
51
+ Key Differences from Legacy:
52
+ - No FSM machinery (FSM was for tracking async I/O, which pure reducers don't do)
53
+ - No initialize()/shutdown() lifecycle methods
54
+ - No internal metrics tracking (metrics are output-level concerns)
55
+ - State is external and immutable (ModelRegistrationState)
56
+ - Uses omnibase_core's ModelReducerOutput[T] for standard output format
57
+
58
+ State Persistence Strategy:
59
+ This reducer follows the ONEX pure reducer pattern where the reducer itself
60
+ performs NO I/O. State persistence is handled externally by the Runtime and
61
+ Projector components.
62
+
63
+ **HOW STATE IS STORED (PostgreSQL via Projector Layer):**
64
+
65
+ The reducer does NOT persist state directly. Instead:
66
+
67
+ 1. Reducer returns ModelReducerOutput containing the new state
68
+ 2. Runtime extracts the result (ModelRegistrationState) from the output
69
+ 3. Runtime invokes Projector.persist() to write state to PostgreSQL
70
+ 4. State is stored in the ``node_registrations`` table with fields matching
71
+ the ModelRegistrationState model plus tracking fields (last_event_offset)
72
+
73
+ PostgreSQL Schema (conceptual)::
74
+
75
+ node_registrations:
76
+ node_id UUID PRIMARY KEY
77
+ status VARCHAR(20) -- 'idle', 'pending', 'partial', 'complete', 'failed'
78
+ consul_confirmed BOOLEAN
79
+ postgres_confirmed BOOLEAN
80
+ last_processed_event_id UUID
81
+ failure_reason VARCHAR(50)
82
+ last_event_offset BIGINT -- For idempotent updates
83
+ updated_at TIMESTAMP
84
+
85
+ **HOW STATE IS RETRIEVED (Before reduce() is Called):**
86
+
87
+ Before calling reduce(), the orchestrator/runtime loads current state:
88
+
89
+ 1. Orchestrator receives NodeIntrospectionEvent from Kafka
90
+ 2. Orchestrator extracts entity_id (node_id) from event envelope
91
+ 3. Orchestrator queries projection via ProtocolProjectionReader::
92
+
93
+ state = await projection_reader.get_projection(
94
+ entity_type="registration",
95
+ entity_id=node_id
96
+ )
97
+ if state is None:
98
+ state = ModelRegistrationState() # Initial idle state
99
+
100
+ 4. Orchestrator invokes reducer: output = reducer.reduce(state, event)
101
+ 5. Orchestrator passes output to Runtime for persistence and publishing
102
+
103
+ **STATE FLOW (Complete Round-Trip):**
104
+
105
+ ::
106
+
107
+ +--------------+
108
+ | Kafka Event | NodeIntrospectionEvent
109
+ +------+-------+
110
+ |
111
+ v
112
+ +------------------+
113
+ | Orchestrator | 1. Receives event
114
+ | | 2. Loads state from PostgreSQL via ProtocolProjectionReader
115
+ +--------+---------+
116
+ | state + event
117
+ v
118
+ +------------------+
119
+ | Reducer | 3. reduce(state, event) -> ModelReducerOutput
120
+ | (THIS CLASS) | - Pure computation, no I/O
121
+ | | - Returns new state + intents
122
+ +--------+---------+
123
+ | ModelReducerOutput
124
+ v
125
+ +------------------+
126
+ | Runtime | 4. Extracts result (new state)
127
+ | | 5. Invokes Projector.persist() - SYNCHRONOUS
128
+ | | 6. Waits for persist acknowledgment
129
+ +--------+---------+
130
+ | persist()
131
+ v
132
+ +------------------+
133
+ | PostgreSQL | 7. State written to node_registrations table
134
+ | (Projection) | - Idempotent via last_event_offset check
135
+ +--------+---------+
136
+ | ack
137
+ v
138
+ +------------------+
139
+ | Runtime | 8. AFTER persist acks, publish intents to Kafka
140
+ | | - Ordering guarantee: persist BEFORE publish
141
+ +--------+---------+
142
+ | publish intents
143
+ v
144
+ +------------------+
145
+ | Kafka (intents) | 9. Intents available for Effect layer consumption
146
+ +------------------+
147
+
148
+ **ORDERING GUARANTEE (Critical for Consistency):**
149
+
150
+ Per ticket F0 (Projector Execution Model) in ONEX_RUNTIME_REGISTRATION_TICKET_PLAN.md:
151
+
152
+ - Projections are PERSISTED to PostgreSQL BEFORE intents are PUBLISHED to Kafka
153
+ - This ensures read models are consistent before downstream processing
154
+ - Effects can safely assume projection state is current when they execute
155
+ - No race conditions where effects execute before state is visible
156
+
157
+ **IDEMPOTENCY (Safe Replay via last_processed_event_id):**
158
+
159
+ The state model tracks ``last_processed_event_id`` to enable safe replay:
160
+
161
+ 1. Each event has a unique event_id (correlation_id or generated UUID)
162
+ 2. Before processing, reducer calls state.is_duplicate_event(event_id)
163
+ 3. If duplicate, reducer returns current state unchanged with no intents
164
+ 4. PostgreSQL projection also tracks last_event_offset for offset-based idempotency
165
+
166
+ This handles crash scenarios:
167
+
168
+ - If system crashes after persist but before Kafka ack, event is redelivered
169
+ - Reducer detects duplicate via last_processed_event_id match
170
+ - No duplicate intents are emitted
171
+ - System converges to correct state
172
+
173
+ See also: Ticket B3 (Idempotency Guard) for runtime-level idempotency.
174
+
175
+ Intent Emission:
176
+ The reducer emits ModelIntent objects (reducer-layer intents) that wrap
177
+ the typed infrastructure intents:
178
+ - consul.register: Consul service registration
179
+ - postgres.upsert_registration: PostgreSQL record upsert
180
+
181
+ The payload contains the serialized typed intent for Effect layer execution.
182
+
183
+ Confirmation Event Flow:
184
+ This section documents how confirmation events flow from Effect layer back to
185
+ this reducer, completing the registration workflow cycle.
186
+
187
+ 1. INITIAL FLOW (Introspection -> Intents):
188
+
189
+ +----------------+ +-----------+ +------------------+
190
+ | Node emits | --> | Reducer | --> | Intents emitted |
191
+ | Introspection | | processes | | to Kafka |
192
+ | Event | | event | | (consul.register,|
193
+ +----------------+ +-----------+ | postgres.upsert) |
194
+ +------------------+
195
+ |
196
+ v
197
+ +------------------------+
198
+ | Runtime routes intents |
199
+ | to Effect layer nodes |
200
+ +------------------------+
201
+
202
+ 2. EFFECT LAYER EXECUTION:
203
+
204
+ +-------------------+ +------------------+ +------------------+
205
+ | ConsulAdapter | --> | Execute intent | --> | Publish |
206
+ | (Effect Node) | | (register svc) | | confirmation |
207
+ +-------------------+ +------------------+ | event to Kafka |
208
+ +------------------+
209
+ |
210
+ +-------------------+ +------------------+ |
211
+ | PostgresAdapter | --> | Execute intent | ------------+
212
+ | (Effect Node) | | (upsert record) | |
213
+ +-------------------+ +------------------+ v
214
+ +------------------+
215
+ | Confirmation |
216
+ | events on Kafka |
217
+ +------------------+
218
+
219
+ 3. CONFIRMATION EVENT FLOW (Back to Reducer):
220
+
221
+ +-------------------+ +------------------+ +-------------------+
222
+ | Kafka topic: | --> | Runtime routes | --> | Reducer processes |
223
+ | onex.registration.| | confirmation | | confirmation via |
224
+ | events | | to reducer | | reduce_confirm() |
225
+ +-------------------+ +------------------+ +-------------------+
226
+ |
227
+ v
228
+ +-------------------+
229
+ | State transitions:|
230
+ | pending -> partial|
231
+ | partial -> complete|
232
+ +-------------------+
233
+
234
+ 4. CONFIRMATION EVENT TYPES:
235
+
236
+ - consul.registered: Confirmation from ConsulAdapter that service
237
+ was successfully registered in Consul. Published to:
238
+ onex.registration.events (or onex.<domain>.events)
239
+
240
+ Payload includes:
241
+ - correlation_id: Links back to original introspection event
242
+ - service_id: The registered Consul service ID
243
+ - success: bool indicating registration outcome
244
+ - error: Optional error message if failed
245
+
246
+ - postgres.registration_upserted: Confirmation from PostgresAdapter
247
+ that registration record was successfully upserted. Published to:
248
+ onex.registration.events
249
+
250
+ Payload includes:
251
+ - correlation_id: Links back to original introspection event
252
+ - node_id: The registered node ID
253
+ - success: bool indicating upsert outcome
254
+ - error: Optional error message if failed
255
+
256
+ 5. STATE TRANSITION DIAGRAM:
257
+
258
+ +-------+ introspection +---------+
259
+ | idle | ----------------> | pending |
260
+ +-------+ +---------+
261
+ ^ | |
262
+ | consul confirmed | | postgres confirmed
263
+ | (first) v v (first)
264
+ | +---------+
265
+ | | partial |
266
+ | +---------+
267
+ | | |
268
+ | remaining | | error received
269
+ | confirmed v v
270
+ | +---------+ +---------+
271
+ +---reset------| complete| | failed |---reset---+
272
+ +---------+ +---------+ |
273
+ v
274
+ +-------+
275
+ | idle |
276
+ +-------+
277
+
278
+ Transitions:
279
+ - idle -> pending: On introspection event (emits intents)
280
+ - pending -> partial: First confirmation received (consul OR postgres)
281
+ - pending -> failed: Error confirmation received
282
+ - partial -> complete: Second confirmation received (both confirmed)
283
+ - partial -> failed: Error confirmation for remaining backend
284
+ - any -> failed: Validation or backend error
285
+ - failed -> idle: Reset event (allows retry after failure)
286
+ - complete -> idle: Reset event (allows re-registration)
287
+
288
+ 6. IMPLEMENTATION NOTE - reduce_confirmation():
289
+
290
+ The reduce_confirmation() method (to be implemented) will handle
291
+ confirmation events. It uses the same pure reducer pattern:
292
+
293
+ def reduce_confirmation(
294
+ self,
295
+ state: ModelRegistrationState,
296
+ confirmation: ModelRegistrationConfirmation,
297
+ ) -> ModelReducerOutput[ModelRegistrationState]:
298
+ '''Process confirmation event from Effect layer.'''
299
+ # Validate confirmation matches current node_id
300
+ # Transition state based on confirmation type:
301
+ # - consul.registered -> with_consul_confirmed()
302
+ # - postgres.registration_upserted -> with_postgres_confirmed()
303
+ # - error -> with_failure()
304
+ # Return new state with no intents (confirmations don't emit new intents)
305
+
306
+ The confirmation event model should include:
307
+ - event_type: "consul.registered" | "postgres.registration_upserted"
308
+ - correlation_id: UUID linking to original introspection
309
+ - node_id: UUID of the registered node
310
+ - success: bool
311
+ - error_message: str | None
312
+ - timestamp: datetime
313
+
314
+ 7. IDEMPOTENCY:
315
+
316
+ Confirmation events are also subject to idempotency:
317
+ - Duplicate confirmations (same event_id) are skipped
318
+ - Confirmations for wrong node_id are rejected
319
+ - Re-confirmations after complete/failed are no-ops
320
+
321
+ 8. TIMEOUT HANDLING:
322
+
323
+ Per DESIGN_TWO_WAY_REGISTRATION_ARCHITECTURE.md, timeouts are owned
324
+ by the Orchestrator layer, not the Reducer:
325
+
326
+ - Orchestrator tracks pending registrations with deadlines
327
+ - Orchestrator consumes RuntimeTick events for timeout evaluation
328
+ - Orchestrator emits RegistrationTimedOut events when deadline passes
329
+ - Reducer folds RegistrationTimedOut as a failure confirmation
330
+
331
+ Related:
332
+ - NodeDualRegistrationReducer: Legacy 887-line implementation (deprecated)
333
+ - DESIGN_TWO_WAY_REGISTRATION_ARCHITECTURE.md: Architecture design
334
+ - MESSAGE_DISPATCH_ENGINE.md: How runtime routes events to reducers
335
+ - OMN-889: Infrastructure MVP - ModelNodeIntrospectionEvent
336
+ - OMN-912: ModelIntent typed payloads
337
+ """
338
+
339
+ from __future__ import annotations
340
+
341
+ import hashlib
342
+ import logging
343
+ import os
344
+ import time
345
+ from datetime import UTC, datetime
346
+ from typing import Literal
347
+ from uuid import UUID, uuid4
348
+
349
+ from pydantic import BaseModel, ConfigDict, field_validator
350
+
351
+ from omnibase_core.enums import EnumNodeKind, EnumReductionType, EnumStreamingMode
352
+ from omnibase_core.models.reducer.model_intent import ModelIntent
353
+ from omnibase_core.nodes import ModelReducerOutput
354
+ from omnibase_infra.enums import EnumConfirmationEventType
355
+ from omnibase_infra.models.registration import (
356
+ ModelNodeIntrospectionEvent,
357
+ ModelNodeRegistrationRecord,
358
+ )
359
+ from omnibase_infra.nodes.reducers.models.model_payload_consul_register import (
360
+ ModelPayloadConsulRegister,
361
+ )
362
+ from omnibase_infra.nodes.reducers.models.model_payload_postgres_upsert_registration import (
363
+ ModelPayloadPostgresUpsertRegistration,
364
+ )
365
+ from omnibase_infra.nodes.reducers.models.model_registration_confirmation import (
366
+ ModelRegistrationConfirmation,
367
+ )
368
+ from omnibase_infra.nodes.reducers.models.model_registration_state import (
369
+ ModelRegistrationState,
370
+ )
371
+
372
+ # =============================================================================
373
+ # Performance Threshold Constants (in milliseconds)
374
+ #
375
+ # These constants define the performance targets for the RegistrationReducer.
376
+ # When processing time exceeds these thresholds, a warning is logged to help
377
+ # identify performance regressions or unusually complex events.
378
+ #
379
+ # These are intentionally generous for production use (300ms target) because:
380
+ # 1. Pure reducers should be fast (no I/O)
381
+ # 2. Most events complete in <5ms
382
+ # 3. Threshold alerts indicate something unusual (test environment, GC pause, etc.)
383
+ #
384
+ # Environment Variable Configuration:
385
+ # ONEX_PERF_THRESHOLD_REDUCE_MS - reduce() processing threshold (default: 300.0)
386
+ # ONEX_PERF_THRESHOLD_INTENT_BUILD_MS - intent building threshold (default: 50.0)
387
+ # ONEX_PERF_THRESHOLD_IDEMPOTENCY_CHECK_MS - idempotency check threshold (default: 1.0)
388
+ #
389
+ # Example usage:
390
+ # export ONEX_PERF_THRESHOLD_REDUCE_MS=100.0 # Stricter threshold for production
391
+ # export ONEX_PERF_THRESHOLD_REDUCE_MS=1000.0 # Relaxed threshold for dev/CI
392
+ # =============================================================================
393
+
394
+ # Target processing time for reduce() method (<300ms per event)
395
+ # This is the primary performance metric for the reducer.
396
+ PERF_THRESHOLD_REDUCE_MS: float = float(
397
+ os.getenv("ONEX_PERF_THRESHOLD_REDUCE_MS", "300.0")
398
+ )
399
+
400
+ # Target processing time for intent building (<50ms per intent)
401
+ # Consul and PostgreSQL intent construction should be fast.
402
+ PERF_THRESHOLD_INTENT_BUILD_MS: float = float(
403
+ os.getenv("ONEX_PERF_THRESHOLD_INTENT_BUILD_MS", "50.0")
404
+ )
405
+
406
+ # Target processing time for idempotency check (<1ms)
407
+ # Simple UUID comparison should be nearly instant.
408
+ PERF_THRESHOLD_IDEMPOTENCY_CHECK_MS: float = float(
409
+ os.getenv("ONEX_PERF_THRESHOLD_IDEMPOTENCY_CHECK_MS", "1.0")
410
+ )
411
+
412
+ # Logger for performance warnings and validation errors
413
+ _logger = logging.getLogger(__name__)
414
+
415
+
416
+ # =============================================================================
417
+ # Validation Error Types
418
+ # =============================================================================
419
+
420
+ ValidationErrorCode = Literal[
421
+ "missing_node_id",
422
+ "missing_node_type",
423
+ "invalid_node_type",
424
+ ]
425
+
426
+ # Sentinel value for "not set" state
427
+ _SENTINEL_STR: str = ""
428
+
429
+
430
+ class ModelValidationResult(BaseModel):
431
+ """Result of event validation with detailed error information.
432
+
433
+ This Pydantic model replaces the previous dataclass implementation
434
+ to comply with ONEX requirements for Pydantic-based data structures.
435
+
436
+ This model uses sentinel values (empty string) instead of nullable unions
437
+ to minimize union count in the codebase (OMN-1004).
438
+
439
+ Sentinel Values:
440
+ - Empty string ("") for field_name and error_message means "not set"
441
+ - None for error_code (unavoidable for Literal type safety)
442
+ - Use ``has_field_name``, ``has_error_message`` to check
443
+
444
+ Constructor API:
445
+ Constructors accept ``None`` for string fields and convert to sentinel.
446
+
447
+ Attributes:
448
+ is_valid: Whether the event passed validation.
449
+ error_code: Distinct code identifying the validation failure (if any).
450
+ field_name: Name of the field that failed validation. Empty string if not set.
451
+ error_message: Human-readable error message for logging. Empty string if not set.
452
+
453
+ .. versionchanged:: 0.7.0
454
+ Refactored to use sentinel values for string fields (OMN-1004).
455
+ """
456
+
457
+ model_config = ConfigDict(frozen=True, extra="forbid", from_attributes=True)
458
+
459
+ is_valid: bool
460
+ error_code: ValidationErrorCode | None = None
461
+ field_name: str = _SENTINEL_STR
462
+ error_message: str = _SENTINEL_STR
463
+
464
+ # ---- Validators for None-to-Sentinel Conversion ----
465
+ @field_validator("field_name", "error_message", mode="before")
466
+ @classmethod
467
+ def _convert_none_to_str_sentinel(cls, v: object) -> str:
468
+ """Convert None to empty string sentinel for API convenience."""
469
+ if v is None:
470
+ return _SENTINEL_STR
471
+ if isinstance(v, str):
472
+ return v
473
+ return str(v)
474
+
475
+ # ---- Sentinel Check Properties ----
476
+ @property
477
+ def has_field_name(self) -> bool:
478
+ """Check if field_name is set (not empty string)."""
479
+ return self.field_name != _SENTINEL_STR
480
+
481
+ @property
482
+ def has_error_message(self) -> bool:
483
+ """Check if error_message is set (not empty string)."""
484
+ return self.error_message != _SENTINEL_STR
485
+
486
+ @classmethod
487
+ def success(cls) -> ModelValidationResult:
488
+ """Create a successful validation result."""
489
+ return cls(is_valid=True)
490
+
491
+ @classmethod
492
+ def failure(
493
+ cls,
494
+ error_code: ValidationErrorCode,
495
+ field_name: str,
496
+ error_message: str,
497
+ ) -> ModelValidationResult:
498
+ """Create a failed validation result with error details."""
499
+ return cls(
500
+ is_valid=False,
501
+ error_code=error_code,
502
+ field_name=field_name,
503
+ error_message=error_message,
504
+ )
505
+
506
+
507
+ # TODO(OMN-889): Complete pure reducer implementation - add reduce_confirmation() method
508
+ class RegistrationReducer:
509
+ """Pure reducer for node registration workflow.
510
+
511
+ Follows ProtocolReducer pattern:
512
+ - reduce(state, event) -> ModelReducerOutput
513
+ - Pure function, no side effects
514
+ - Emits intents for Consul and PostgreSQL registration
515
+
516
+ This is a stateless class - all state is passed in and returned via
517
+ ModelRegistrationState. The class exists to group related pure functions.
518
+
519
+ Event Processing Methods:
520
+ This reducer handles two categories of events:
521
+
522
+ 1. reduce(state, introspection_event) -> Processes initial node introspection,
523
+ emits registration intents for Effect layer execution.
524
+
525
+ 2. reduce_confirmation(state, confirmation_event) -> Processes confirmation
526
+ events from Effect layer, updates state to partial/complete/failed.
527
+ (See module docstring section 6 for implementation details.)
528
+
529
+ Complete Event Cycle:
530
+ 1. Node publishes introspection event to Kafka
531
+ 2. Runtime routes introspection to this reducer via reduce()
532
+ 3. Reducer emits intents (consul.register, postgres.upsert_registration)
533
+ 4. Runtime publishes intents to Kafka intent topics
534
+ 5. Effect layer nodes (ConsulAdapter, PostgresAdapter) consume intents
535
+ 6. Effect nodes execute I/O and publish confirmation events to Kafka
536
+ 7. Runtime routes confirmation events back to this reducer
537
+ 8. Reducer updates state: pending -> partial -> complete
538
+
539
+ Topic Subscriptions:
540
+ The reducer node subscribes to:
541
+ - onex.registration.events (or onex.<domain>.events)
542
+
543
+ This includes both introspection events and confirmation events.
544
+ The reduce() method dispatches to the appropriate handler based on
545
+ event type.
546
+
547
+ Example:
548
+ >>> from uuid import uuid4
549
+ >>> from omnibase_infra.models.registration import ModelNodeIntrospectionEvent
550
+ >>> from omnibase_infra.nodes.reducers import RegistrationReducer
551
+ >>> from omnibase_infra.nodes.reducers.models import ModelRegistrationState
552
+ >>>
553
+ >>> reducer = RegistrationReducer()
554
+ >>> state = ModelRegistrationState() # Initial idle state
555
+ >>> event = ModelNodeIntrospectionEvent(
556
+ ... node_id=uuid4(),
557
+ ... node_type="effect",
558
+ ... node_version="1.0.0",
559
+ ... endpoints={"health": "http://localhost:8080/health"},
560
+ ... )
561
+ >>> output = reducer.reduce(state, event)
562
+ >>> print(output.result.status) # "pending"
563
+ >>> print(len(output.intents)) # 2 (Consul + PostgreSQL)
564
+ """
565
+
566
+ def reduce(
567
+ self,
568
+ state: ModelRegistrationState,
569
+ event: ModelNodeIntrospectionEvent,
570
+ ) -> ModelReducerOutput[ModelRegistrationState]:
571
+ """Pure reduce function: state + event -> new_state + intents.
572
+
573
+ Processes a node introspection event and emits registration intents
574
+ for both Consul and PostgreSQL backends. The returned output contains
575
+ the new state and any intents to be executed by the Effect layer.
576
+
577
+ This is PHASE 1 of the confirmation event flow:
578
+ 1. Node publishes introspection event -> Runtime routes here
579
+ 2. This method processes event -> Emits intents
580
+ 3. Runtime publishes intents to Kafka -> Effect layer executes
581
+ 4. Effect layer publishes confirmations -> reduce_confirmation() handles
582
+
583
+ Idempotency:
584
+ If the event has already been processed (based on event_id), the
585
+ reducer returns immediately with the current state and no intents.
586
+
587
+ Validation:
588
+ If the event fails validation (e.g., missing node_id), the reducer
589
+ transitions to failed state with no intents.
590
+
591
+ Args:
592
+ state: Current registration state (immutable).
593
+ event: Node introspection event to process.
594
+
595
+ Returns:
596
+ ModelReducerOutput containing new_state and intents tuple.
597
+ The result field contains the new ModelRegistrationState.
598
+ The intents field contains registration intents for Effect layer.
599
+ """
600
+ start_time = time.perf_counter()
601
+
602
+ # =====================================================================
603
+ # CONFIRMATION FLOW STEP 1: Receive introspection event from Kafka
604
+ # This event was published by a node during startup/discovery.
605
+ # The Runtime (MessageDispatchEngine) routed it here based on:
606
+ # - Topic: onex.registration.events (or similar)
607
+ # - Message type: ModelNodeIntrospectionEvent
608
+ # =====================================================================
609
+
610
+ # Resolve event ID for idempotency.
611
+ # CRITICAL: We use a deterministic derivation when correlation_id is absent.
612
+ # Using uuid4() here would break idempotency because replayed events would
613
+ # get different IDs each time, making duplicate detection impossible.
614
+ # Instead, we derive a UUID from the event's content hash (node_id + node_type
615
+ # + timestamp), ensuring the same event always produces the same ID.
616
+ event_id = event.correlation_id or self._derive_deterministic_event_id(event)
617
+
618
+ # Idempotency guard - skip if we've already processed this event
619
+ if state.is_duplicate_event(event_id):
620
+ return self._build_output(
621
+ state=state,
622
+ intents=(),
623
+ processing_time_ms=0.0,
624
+ items_processed=0,
625
+ )
626
+
627
+ # Validate event - failures transition to failed state with no intents
628
+ # Note: Validation errors are logged with sanitized context (no PII/secrets)
629
+ # but the output intentionally uses a generic failure_reason to avoid
630
+ # exposing internal validation logic to external consumers.
631
+ validation_result = self._validate_event(event)
632
+ if not validation_result.is_valid:
633
+ # Log validation failure with sanitized context for diagnostics
634
+ # SECURITY: Only field presence booleans and error codes are logged
635
+ _logger.warning(
636
+ "Event validation failed",
637
+ extra={
638
+ "error_code": validation_result.error_code,
639
+ "field_name": validation_result.field_name,
640
+ "error_message": validation_result.error_message,
641
+ "correlation_id": str(event_id),
642
+ "has_node_id": event.node_id is not None,
643
+ "has_node_type": hasattr(event, "node_type")
644
+ and event.node_type is not None,
645
+ },
646
+ )
647
+ new_state = state.with_failure("validation_failed", event_id)
648
+ return self._build_output(
649
+ state=new_state,
650
+ intents=(),
651
+ processing_time_ms=(time.perf_counter() - start_time) * 1000,
652
+ items_processed=0,
653
+ )
654
+
655
+ # =====================================================================
656
+ # CONFIRMATION FLOW STEP 2: Build intents for Effect layer
657
+ # These intents describe the desired I/O operations:
658
+ # - consul.register: Register service in Consul
659
+ # - postgres.upsert_registration: Upsert record in PostgreSQL
660
+ #
661
+ # The correlation_id is propagated to enable confirmation tracking.
662
+ # When Effect nodes complete, they publish confirmation events with
663
+ # this correlation_id, allowing this reducer to match confirmations
664
+ # to the original introspection event.
665
+ # =====================================================================
666
+
667
+ correlation_id = event.correlation_id or event_id
668
+ consul_intent = self._build_consul_intent(event, correlation_id)
669
+ postgres_intent = self._build_postgres_intent(event, correlation_id)
670
+
671
+ # Collect non-None intents
672
+ intents: tuple[ModelIntent, ...] = tuple(
673
+ intent for intent in [consul_intent, postgres_intent] if intent is not None
674
+ )
675
+
676
+ # =====================================================================
677
+ # CONFIRMATION FLOW STEP 3: Transition to pending state
678
+ # State: idle -> pending
679
+ #
680
+ # After this method returns:
681
+ # - Runtime publishes intents to Kafka (onex.registration.intents)
682
+ # - Effect nodes (ConsulAdapter, PostgresAdapter) consume intents
683
+ # - Effect nodes execute I/O and publish confirmation events
684
+ # - Runtime routes confirmation events to reduce_confirmation()
685
+ # - reduce_confirmation() transitions: pending -> partial -> complete
686
+ # =====================================================================
687
+
688
+ new_state = state.with_pending_registration(event.node_id, event_id)
689
+
690
+ processing_time_ms = (time.perf_counter() - start_time) * 1000
691
+
692
+ # Performance logging: warn if processing exceeds threshold
693
+ if processing_time_ms > PERF_THRESHOLD_REDUCE_MS:
694
+ _logger.warning(
695
+ "Reducer processing time exceeded threshold",
696
+ extra={
697
+ "processing_time_ms": processing_time_ms,
698
+ "threshold_ms": PERF_THRESHOLD_REDUCE_MS,
699
+ "node_type": event.node_type.value,
700
+ "intent_count": len(intents),
701
+ "correlation_id": str(correlation_id),
702
+ },
703
+ )
704
+
705
+ return self._build_output(
706
+ state=new_state,
707
+ intents=intents,
708
+ processing_time_ms=processing_time_ms,
709
+ items_processed=1,
710
+ )
711
+
712
+ def _is_valid(self, event: ModelNodeIntrospectionEvent) -> bool:
713
+ """Validate introspection event for processing.
714
+
715
+ Convenience wrapper around _validate_event() that returns a simple bool.
716
+ Use _validate_event() when detailed error information is needed.
717
+
718
+ Args:
719
+ event: Introspection event to validate.
720
+
721
+ Returns:
722
+ True if the event is valid for processing, False otherwise.
723
+ """
724
+ return self._validate_event(event).is_valid
725
+
726
+ def _validate_event(
727
+ self, event: ModelNodeIntrospectionEvent
728
+ ) -> ModelValidationResult:
729
+ """Validate introspection event with detailed error information.
730
+
731
+ Validates that required fields are present for registration workflow.
732
+ Returns a ValidationResult with distinct error codes for each failure
733
+ scenario, enabling proper logging and diagnostics.
734
+
735
+ **Validation Rules:**
736
+ - node_id: Must be present (required for registration identity)
737
+ - node_type: Must be present and valid (required for service categorization)
738
+
739
+ **Error Codes:**
740
+ - missing_node_id: node_id is None
741
+ - missing_node_type: node_type attribute is missing or None
742
+ - invalid_node_type: node_type is not a valid ONEX node type
743
+
744
+ **Security Note:**
745
+ Error messages are logged server-side but the reducer's output uses
746
+ a generic "validation_failed" reason to avoid exposing internal
747
+ validation logic to external consumers.
748
+
749
+ Args:
750
+ event: Introspection event to validate.
751
+
752
+ Returns:
753
+ ValidationResult with is_valid=True if valid, or detailed error
754
+ information if validation failed.
755
+ """
756
+ # Validate node_id: required for registration identity
757
+ if event.node_id is None:
758
+ return ModelValidationResult.failure(
759
+ error_code="missing_node_id",
760
+ field_name="node_id",
761
+ error_message="node_id is required for registration identity",
762
+ )
763
+
764
+ # Validate node_type: must be present
765
+ if not hasattr(event, "node_type") or event.node_type is None:
766
+ return ModelValidationResult.failure(
767
+ error_code="missing_node_type",
768
+ field_name="node_type",
769
+ error_message="node_type is required for service categorization",
770
+ )
771
+
772
+ # Validate node_type value is valid ONEX type
773
+ # Use EnumNodeKind values (excluding RUNTIME_HOST which is not a registration type)
774
+ valid_node_types = {
775
+ EnumNodeKind.EFFECT.value,
776
+ EnumNodeKind.COMPUTE.value,
777
+ EnumNodeKind.REDUCER.value,
778
+ EnumNodeKind.ORCHESTRATOR.value,
779
+ }
780
+ if event.node_type.value not in valid_node_types:
781
+ return ModelValidationResult.failure(
782
+ error_code="invalid_node_type",
783
+ field_name="node_type",
784
+ error_message=(
785
+ f"node_type must be one of: {', '.join(sorted(valid_node_types))}"
786
+ ),
787
+ )
788
+
789
+ return ModelValidationResult.success()
790
+
791
+ def _derive_deterministic_event_id(
792
+ self, event: ModelNodeIntrospectionEvent
793
+ ) -> UUID:
794
+ """Derive a deterministic event ID from event content.
795
+
796
+ When an event lacks a correlation_id, we must derive a stable identifier
797
+ from its content to preserve idempotency guarantees. Using uuid4() would
798
+ break idempotency because replayed events would get different IDs.
799
+
800
+ The derived ID uses a SHA-256 hash of the event's identifying fields:
801
+ - node_id: Unique node identifier
802
+ - node_type: Node archetype (effect, compute, reducer, orchestrator)
803
+ - timestamp: Event creation timestamp (ISO format for stability)
804
+
805
+ This ensures:
806
+ 1. Same event content always produces the same ID
807
+ 2. Different events produce different IDs (collision-resistant)
808
+ 3. ID format is compatible with existing UUID-based tracking
809
+
810
+ Args:
811
+ event: The introspection event to derive an ID from.
812
+
813
+ Returns:
814
+ A deterministic UUID derived from the event's content.
815
+ """
816
+ # Build a canonical string from the event's identifying fields.
817
+ # Using ISO format for timestamp ensures string stability across serialization.
818
+ # The pipe delimiter prevents ambiguity between field values.
819
+ canonical_content = (
820
+ f"{event.node_id}|{event.node_type.value}|{event.timestamp.isoformat()}"
821
+ )
822
+
823
+ # Compute SHA-256 hash and convert to UUID format.
824
+ # SHA-256 provides strong collision resistance for content-derived IDs.
825
+ content_hash = hashlib.sha256(canonical_content.encode("utf-8")).hexdigest()
826
+
827
+ # Take first 32 hex chars (128 bits) and format as UUID.
828
+ # Insert hyphens in standard UUID format: 8-4-4-4-12
829
+ uuid_hex = content_hash[:32]
830
+ uuid_str = (
831
+ f"{uuid_hex[:8]}-{uuid_hex[8:12]}-{uuid_hex[12:16]}-"
832
+ f"{uuid_hex[16:20]}-{uuid_hex[20:32]}"
833
+ )
834
+
835
+ return UUID(uuid_str)
836
+
837
+ def _build_consul_intent(
838
+ self,
839
+ event: ModelNodeIntrospectionEvent,
840
+ correlation_id: UUID,
841
+ ) -> ModelIntent | None:
842
+ """Build Consul registration intent (pure, no I/O).
843
+
844
+ Creates a ModelIntent that describes the desired Consul service
845
+ registration. The Effect layer is responsible for executing this intent.
846
+
847
+ Args:
848
+ event: Introspection event containing node data.
849
+ correlation_id: Correlation ID for tracing.
850
+
851
+ Returns:
852
+ ModelIntent with intent_type="extension" (dual-layer routing).
853
+ The routing key "consul.register" is in payload.intent_type.
854
+ """
855
+ service_id = f"onex-{event.node_type.value}-{event.node_id}"
856
+ service_name = f"onex-{event.node_type.value}"
857
+ tags = [
858
+ f"node_type:{event.node_type.value}",
859
+ f"node_version:{event.node_version}",
860
+ ]
861
+
862
+ # Build health check configuration if health endpoint is provided
863
+ health_endpoint = event.endpoints.get("health") if event.endpoints else None
864
+ health_check: dict[str, str] | None = None
865
+ if health_endpoint:
866
+ health_check = {
867
+ "HTTP": health_endpoint,
868
+ "Interval": "10s",
869
+ "Timeout": "5s",
870
+ }
871
+
872
+ # Build typed Consul registration payload (implements ProtocolIntentPayload)
873
+ consul_payload = ModelPayloadConsulRegister(
874
+ correlation_id=correlation_id,
875
+ service_id=service_id,
876
+ service_name=service_name,
877
+ tags=tags,
878
+ health_check=health_check,
879
+ event_bus_config=event.event_bus, # Pass through from introspection event
880
+ )
881
+
882
+ # ModelIntent.payload expects ProtocolIntentPayload, which our model implements
883
+ return ModelIntent(
884
+ intent_type="extension",
885
+ target=f"consul://service/{service_name}",
886
+ payload=consul_payload,
887
+ )
888
+
889
+ def _build_postgres_intent(
890
+ self,
891
+ event: ModelNodeIntrospectionEvent,
892
+ correlation_id: UUID,
893
+ ) -> ModelIntent | None:
894
+ """Build PostgreSQL upsert intent (pure, no I/O).
895
+
896
+ Creates a ModelIntent that describes the desired PostgreSQL record
897
+ upsert. The Effect layer is responsible for executing this intent.
898
+
899
+ Args:
900
+ event: Introspection event containing node data.
901
+ correlation_id: Correlation ID for tracing.
902
+
903
+ Returns:
904
+ ModelIntent with intent_type="extension" (dual-layer routing).
905
+ The routing key "postgres.upsert_registration" is in payload.intent_type.
906
+ """
907
+ now = datetime.now(UTC)
908
+
909
+ # Build the registration record using strongly-typed models
910
+ # event.declared_capabilities and event.metadata are already typed as
911
+ # ModelNodeCapabilities and ModelNodeMetadata respectively
912
+ record = ModelNodeRegistrationRecord(
913
+ node_id=event.node_id,
914
+ node_type=event.node_type,
915
+ node_version=event.node_version,
916
+ capabilities=event.declared_capabilities,
917
+ endpoints=dict(event.endpoints) if event.endpoints else {},
918
+ metadata=event.metadata,
919
+ health_endpoint=(
920
+ event.endpoints.get("health") if event.endpoints else None
921
+ ),
922
+ registered_at=now,
923
+ updated_at=now,
924
+ )
925
+
926
+ # Build typed PostgreSQL upsert payload (implements ProtocolIntentPayload)
927
+ postgres_payload = ModelPayloadPostgresUpsertRegistration(
928
+ correlation_id=correlation_id,
929
+ record=record,
930
+ )
931
+
932
+ # ModelIntent.payload expects ProtocolIntentPayload, which our model implements
933
+ return ModelIntent(
934
+ intent_type="extension",
935
+ target=f"postgres://node_registrations/{event.node_id}",
936
+ payload=postgres_payload,
937
+ )
938
+
939
+ # =========================================================================
940
+ # CONFIRMATION EVENT HANDLING (PHASE 2 of the event flow)
941
+ #
942
+ # The following method will handle confirmation events from Effect layer.
943
+ # It is documented here as a stub to show the complete event flow.
944
+ #
945
+ # Follow-up Ticket: OMN-996 (Implement Confirmation Event Handling)
946
+ # https://linear.app/omninode/issue/OMN-996
947
+ #
948
+ # Prerequisites:
949
+ # - [DONE] ModelRegistrationConfirmation model defined
950
+ # See: omnibase_infra.nodes.reducers.models.model_registration_confirmation
951
+ # - Effect layer confirmation event publishing implemented
952
+ # - Tests added for confirmation event handling
953
+ #
954
+ # See module docstring section 6 for detailed implementation notes.
955
+ # =========================================================================
956
+
957
+ def reduce_confirmation(
958
+ self,
959
+ state: ModelRegistrationState,
960
+ confirmation: ModelRegistrationConfirmation,
961
+ ) -> ModelReducerOutput[ModelRegistrationState]:
962
+ """Process confirmation event from Effect layer.
963
+
964
+ Not yet implemented. See OMN-996 for tracking.
965
+
966
+ Args:
967
+ state: Current registration state (immutable).
968
+ confirmation: Confirmation event from Effect layer.
969
+
970
+ Returns:
971
+ ModelReducerOutput with new state and no intents.
972
+
973
+ Raises:
974
+ NotImplementedError: Always raised until implementation is complete.
975
+ """
976
+ raise NotImplementedError(
977
+ "reduce_confirmation() is not yet implemented. "
978
+ "See ticket OMN-996: https://linear.app/omninode/issue/OMN-996"
979
+ )
980
+
981
+ # TODO(OMN-996): Implement reduce_confirmation() using ModelRegistrationConfirmation
982
+ # Ticket: https://linear.app/omninode/issue/OMN-996
983
+ # Status: Backlog - Phase 2 of dual registration event flow
984
+ #
985
+ # Scope: Process confirmation events from Effect layer (Consul/PostgreSQL)
986
+ # to complete state transitions: pending -> partial -> complete
987
+ #
988
+ def reduce_reset(
989
+ self,
990
+ state: ModelRegistrationState,
991
+ reset_event_id: UUID,
992
+ ) -> ModelReducerOutput[ModelRegistrationState]:
993
+ """Process a reset event to recover from failed or complete states.
994
+
995
+ This method allows the FSM to recover from terminal states (failed, complete)
996
+ and return to idle, enabling retry workflows after failures.
997
+
998
+ State Validation:
999
+ Reset is ONLY allowed from terminal states (failed, complete). Attempting
1000
+ to reset from in-flight states (pending, partial) or idle will result in
1001
+ a failed state with failure_reason="invalid_reset_state".
1002
+
1003
+ This validation prevents accidental loss of in-flight registration state.
1004
+ If a reset is attempted while registration is in progress (pending/partial),
1005
+ the Consul or PostgreSQL confirmations could be lost, leaving the system
1006
+ in an inconsistent state.
1007
+
1008
+ Use Cases:
1009
+ - Retry after registration failure (consul_failed, postgres_failed)
1010
+ - Re-register a node after deregistration
1011
+ - Manual recovery triggered by operator
1012
+
1013
+ State Transitions:
1014
+ - failed -> idle: Clears failure, enables retry
1015
+ - complete -> idle: Enables re-registration
1016
+ - idle -> failed: Invalid reset (already idle)
1017
+ - pending -> failed: Invalid reset (would lose in-flight state)
1018
+ - partial -> failed: Invalid reset (would lose in-flight state)
1019
+
1020
+ Idempotency:
1021
+ Reset events are subject to the same idempotency checks as other events.
1022
+ If the reset_event_id matches last_processed_event_id, no transition occurs.
1023
+
1024
+ Args:
1025
+ state: Current registration state (immutable).
1026
+ reset_event_id: UUID of the reset event triggering this transition.
1027
+
1028
+ Returns:
1029
+ ModelReducerOutput with new state and no intents.
1030
+ - If reset allowed: new state is idle
1031
+ - If reset not allowed: new state is failed with
1032
+ failure_reason="invalid_reset_state"
1033
+
1034
+ Example:
1035
+ >>> from uuid import uuid4
1036
+ >>> from omnibase_infra.nodes.reducers import RegistrationReducer
1037
+ >>> from omnibase_infra.nodes.reducers.models import ModelRegistrationState
1038
+ >>>
1039
+ >>> reducer = RegistrationReducer()
1040
+ >>> # Reset from failed state succeeds
1041
+ >>> failed_state = ModelRegistrationState(
1042
+ ... status="failed",
1043
+ ... failure_reason="consul_failed"
1044
+ ... )
1045
+ >>> output = reducer.reduce_reset(failed_state, uuid4())
1046
+ >>> output.result.status
1047
+ 'idle'
1048
+ >>>
1049
+ >>> # Reset from pending state fails (would lose in-flight state)
1050
+ >>> pending_state = ModelRegistrationState(status="pending")
1051
+ >>> output = reducer.reduce_reset(pending_state, uuid4())
1052
+ >>> output.result.status
1053
+ 'failed'
1054
+ >>> output.result.failure_reason
1055
+ 'invalid_reset_state'
1056
+ """
1057
+ start_time = time.perf_counter()
1058
+
1059
+ # Idempotency guard
1060
+ if state.is_duplicate_event(reset_event_id):
1061
+ return self._build_output(
1062
+ state=state,
1063
+ intents=(),
1064
+ processing_time_ms=0.0,
1065
+ items_processed=0,
1066
+ )
1067
+
1068
+ # Validate state allows reset - only terminal states (failed, complete)
1069
+ # can be reset. Resetting from pending or partial would lose in-flight
1070
+ # registration state, potentially causing inconsistency between Consul
1071
+ # and PostgreSQL.
1072
+ if not state.can_reset():
1073
+ # Not in a resettable state - transition to failed with clear error
1074
+ # This prevents accidental loss of in-flight registration state.
1075
+ new_state = state.with_failure("invalid_reset_state", reset_event_id)
1076
+ return self._build_output(
1077
+ state=new_state,
1078
+ intents=(),
1079
+ processing_time_ms=(time.perf_counter() - start_time) * 1000,
1080
+ items_processed=1, # We processed the event (it caused a state change)
1081
+ )
1082
+
1083
+ # Perform the reset transition
1084
+ new_state = state.with_reset(reset_event_id)
1085
+
1086
+ processing_time_ms = (time.perf_counter() - start_time) * 1000
1087
+
1088
+ return self._build_output(
1089
+ state=new_state,
1090
+ intents=(), # Reset emits no intents
1091
+ processing_time_ms=processing_time_ms,
1092
+ items_processed=1,
1093
+ )
1094
+
1095
+ def _build_output(
1096
+ self,
1097
+ state: ModelRegistrationState,
1098
+ intents: tuple[ModelIntent, ...],
1099
+ processing_time_ms: float,
1100
+ items_processed: int,
1101
+ ) -> ModelReducerOutput[ModelRegistrationState]:
1102
+ """Build standardized ModelReducerOutput.
1103
+
1104
+ Creates the output model with all required fields for the
1105
+ omnibase_core reducer output contract.
1106
+
1107
+ Args:
1108
+ state: New registration state to return.
1109
+ intents: Tuple of ModelIntent objects to emit.
1110
+ processing_time_ms: Time taken to process the event.
1111
+ items_processed: Number of events processed (0 or 1).
1112
+
1113
+ Returns:
1114
+ ModelReducerOutput containing the state and intents.
1115
+ """
1116
+ return ModelReducerOutput(
1117
+ result=state,
1118
+ operation_id=uuid4(),
1119
+ reduction_type=EnumReductionType.MERGE,
1120
+ processing_time_ms=processing_time_ms,
1121
+ items_processed=items_processed,
1122
+ conflicts_resolved=0,
1123
+ streaming_mode=EnumStreamingMode.BATCH,
1124
+ batches_processed=1,
1125
+ intents=intents,
1126
+ )
1127
+
1128
+
1129
+ __all__ = [
1130
+ "PERF_THRESHOLD_IDEMPOTENCY_CHECK_MS",
1131
+ "PERF_THRESHOLD_INTENT_BUILD_MS",
1132
+ # Performance threshold constants (for tests and monitoring)
1133
+ "PERF_THRESHOLD_REDUCE_MS",
1134
+ # Validation types (for tests and custom validators)
1135
+ "ModelValidationResult",
1136
+ "RegistrationReducer",
1137
+ "ValidationErrorCode",
1138
+ ]