omnibase_infra 0.2.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (675) hide show
  1. omnibase_infra/__init__.py +101 -0
  2. omnibase_infra/cli/__init__.py +1 -0
  3. omnibase_infra/cli/commands.py +216 -0
  4. omnibase_infra/clients/__init__.py +0 -0
  5. omnibase_infra/contracts/handlers/filesystem/handler_contract.yaml +261 -0
  6. omnibase_infra/contracts/handlers/mcp/handler_contract.yaml +138 -0
  7. omnibase_infra/decorators/__init__.py +29 -0
  8. omnibase_infra/decorators/allow_any.py +109 -0
  9. omnibase_infra/dlq/__init__.py +90 -0
  10. omnibase_infra/dlq/constants_dlq.py +57 -0
  11. omnibase_infra/dlq/models/__init__.py +26 -0
  12. omnibase_infra/dlq/models/enum_replay_status.py +37 -0
  13. omnibase_infra/dlq/models/model_dlq_replay_record.py +135 -0
  14. omnibase_infra/dlq/models/model_dlq_tracking_config.py +184 -0
  15. omnibase_infra/dlq/service_dlq_tracking.py +611 -0
  16. omnibase_infra/enums/__init__.py +123 -0
  17. omnibase_infra/enums/enum_any_type_violation.py +104 -0
  18. omnibase_infra/enums/enum_backend_type.py +27 -0
  19. omnibase_infra/enums/enum_capture_outcome.py +42 -0
  20. omnibase_infra/enums/enum_capture_state.py +88 -0
  21. omnibase_infra/enums/enum_chain_violation_type.py +119 -0
  22. omnibase_infra/enums/enum_circuit_state.py +51 -0
  23. omnibase_infra/enums/enum_confirmation_event_type.py +27 -0
  24. omnibase_infra/enums/enum_contract_type.py +84 -0
  25. omnibase_infra/enums/enum_dedupe_strategy.py +46 -0
  26. omnibase_infra/enums/enum_dispatch_status.py +191 -0
  27. omnibase_infra/enums/enum_environment.py +46 -0
  28. omnibase_infra/enums/enum_execution_shape_violation.py +103 -0
  29. omnibase_infra/enums/enum_handler_error_type.py +101 -0
  30. omnibase_infra/enums/enum_handler_loader_error.py +178 -0
  31. omnibase_infra/enums/enum_handler_source_type.py +87 -0
  32. omnibase_infra/enums/enum_handler_type.py +77 -0
  33. omnibase_infra/enums/enum_handler_type_category.py +61 -0
  34. omnibase_infra/enums/enum_infra_transport_type.py +73 -0
  35. omnibase_infra/enums/enum_introspection_reason.py +154 -0
  36. omnibase_infra/enums/enum_message_category.py +213 -0
  37. omnibase_infra/enums/enum_node_archetype.py +74 -0
  38. omnibase_infra/enums/enum_node_output_type.py +185 -0
  39. omnibase_infra/enums/enum_non_retryable_error_category.py +224 -0
  40. omnibase_infra/enums/enum_policy_type.py +32 -0
  41. omnibase_infra/enums/enum_registration_state.py +261 -0
  42. omnibase_infra/enums/enum_registration_status.py +33 -0
  43. omnibase_infra/enums/enum_registry_response_status.py +28 -0
  44. omnibase_infra/enums/enum_response_status.py +26 -0
  45. omnibase_infra/enums/enum_retry_error_category.py +98 -0
  46. omnibase_infra/enums/enum_security_rule_id.py +103 -0
  47. omnibase_infra/enums/enum_selection_strategy.py +91 -0
  48. omnibase_infra/enums/enum_topic_standard.py +42 -0
  49. omnibase_infra/enums/enum_validation_severity.py +78 -0
  50. omnibase_infra/errors/__init__.py +156 -0
  51. omnibase_infra/errors/error_architecture_violation.py +152 -0
  52. omnibase_infra/errors/error_chain_propagation.py +188 -0
  53. omnibase_infra/errors/error_compute_registry.py +92 -0
  54. omnibase_infra/errors/error_consul.py +132 -0
  55. omnibase_infra/errors/error_container_wiring.py +243 -0
  56. omnibase_infra/errors/error_event_bus_registry.py +102 -0
  57. omnibase_infra/errors/error_infra.py +608 -0
  58. omnibase_infra/errors/error_message_type_registry.py +101 -0
  59. omnibase_infra/errors/error_policy_registry.py +112 -0
  60. omnibase_infra/errors/error_vault.py +123 -0
  61. omnibase_infra/event_bus/__init__.py +72 -0
  62. omnibase_infra/event_bus/configs/kafka_event_bus_config.yaml +86 -0
  63. omnibase_infra/event_bus/event_bus_inmemory.py +743 -0
  64. omnibase_infra/event_bus/event_bus_kafka.py +1658 -0
  65. omnibase_infra/event_bus/mixin_kafka_broadcast.py +184 -0
  66. omnibase_infra/event_bus/mixin_kafka_dlq.py +765 -0
  67. omnibase_infra/event_bus/models/__init__.py +29 -0
  68. omnibase_infra/event_bus/models/config/__init__.py +20 -0
  69. omnibase_infra/event_bus/models/config/model_kafka_event_bus_config.py +725 -0
  70. omnibase_infra/event_bus/models/model_dlq_event.py +206 -0
  71. omnibase_infra/event_bus/models/model_dlq_metrics.py +304 -0
  72. omnibase_infra/event_bus/models/model_event_headers.py +115 -0
  73. omnibase_infra/event_bus/models/model_event_message.py +60 -0
  74. omnibase_infra/event_bus/topic_constants.py +376 -0
  75. omnibase_infra/handlers/__init__.py +75 -0
  76. omnibase_infra/handlers/filesystem/__init__.py +48 -0
  77. omnibase_infra/handlers/filesystem/enum_file_system_operation.py +35 -0
  78. omnibase_infra/handlers/filesystem/model_file_system_request.py +298 -0
  79. omnibase_infra/handlers/filesystem/model_file_system_result.py +166 -0
  80. omnibase_infra/handlers/handler_consul.py +787 -0
  81. omnibase_infra/handlers/handler_db.py +1039 -0
  82. omnibase_infra/handlers/handler_filesystem.py +1478 -0
  83. omnibase_infra/handlers/handler_graph.py +1154 -0
  84. omnibase_infra/handlers/handler_http.py +920 -0
  85. omnibase_infra/handlers/handler_manifest_persistence.contract.yaml +184 -0
  86. omnibase_infra/handlers/handler_manifest_persistence.py +1539 -0
  87. omnibase_infra/handlers/handler_mcp.py +748 -0
  88. omnibase_infra/handlers/handler_qdrant.py +1076 -0
  89. omnibase_infra/handlers/handler_vault.py +422 -0
  90. omnibase_infra/handlers/mcp/__init__.py +19 -0
  91. omnibase_infra/handlers/mcp/adapter_onex_to_mcp.py +446 -0
  92. omnibase_infra/handlers/mcp/protocols.py +178 -0
  93. omnibase_infra/handlers/mcp/transport_streamable_http.py +352 -0
  94. omnibase_infra/handlers/mixins/__init__.py +42 -0
  95. omnibase_infra/handlers/mixins/mixin_consul_initialization.py +349 -0
  96. omnibase_infra/handlers/mixins/mixin_consul_kv.py +337 -0
  97. omnibase_infra/handlers/mixins/mixin_consul_service.py +277 -0
  98. omnibase_infra/handlers/mixins/mixin_vault_initialization.py +338 -0
  99. omnibase_infra/handlers/mixins/mixin_vault_retry.py +412 -0
  100. omnibase_infra/handlers/mixins/mixin_vault_secrets.py +450 -0
  101. omnibase_infra/handlers/mixins/mixin_vault_token.py +365 -0
  102. omnibase_infra/handlers/models/__init__.py +286 -0
  103. omnibase_infra/handlers/models/consul/__init__.py +81 -0
  104. omnibase_infra/handlers/models/consul/enum_consul_operation_type.py +57 -0
  105. omnibase_infra/handlers/models/consul/model_consul_deregister_payload.py +51 -0
  106. omnibase_infra/handlers/models/consul/model_consul_handler_config.py +153 -0
  107. omnibase_infra/handlers/models/consul/model_consul_handler_payload.py +89 -0
  108. omnibase_infra/handlers/models/consul/model_consul_kv_get_found_payload.py +55 -0
  109. omnibase_infra/handlers/models/consul/model_consul_kv_get_not_found_payload.py +49 -0
  110. omnibase_infra/handlers/models/consul/model_consul_kv_get_recurse_payload.py +50 -0
  111. omnibase_infra/handlers/models/consul/model_consul_kv_item.py +33 -0
  112. omnibase_infra/handlers/models/consul/model_consul_kv_put_payload.py +41 -0
  113. omnibase_infra/handlers/models/consul/model_consul_register_payload.py +53 -0
  114. omnibase_infra/handlers/models/consul/model_consul_retry_config.py +66 -0
  115. omnibase_infra/handlers/models/consul/model_payload_consul.py +66 -0
  116. omnibase_infra/handlers/models/consul/registry_payload_consul.py +214 -0
  117. omnibase_infra/handlers/models/graph/__init__.py +35 -0
  118. omnibase_infra/handlers/models/graph/enum_graph_operation_type.py +20 -0
  119. omnibase_infra/handlers/models/graph/model_graph_execute_payload.py +38 -0
  120. omnibase_infra/handlers/models/graph/model_graph_handler_config.py +54 -0
  121. omnibase_infra/handlers/models/graph/model_graph_handler_payload.py +44 -0
  122. omnibase_infra/handlers/models/graph/model_graph_query_payload.py +40 -0
  123. omnibase_infra/handlers/models/graph/model_graph_record.py +22 -0
  124. omnibase_infra/handlers/models/http/__init__.py +50 -0
  125. omnibase_infra/handlers/models/http/enum_http_operation_type.py +29 -0
  126. omnibase_infra/handlers/models/http/model_http_body_content.py +45 -0
  127. omnibase_infra/handlers/models/http/model_http_get_payload.py +88 -0
  128. omnibase_infra/handlers/models/http/model_http_handler_payload.py +90 -0
  129. omnibase_infra/handlers/models/http/model_http_post_payload.py +88 -0
  130. omnibase_infra/handlers/models/http/model_payload_http.py +66 -0
  131. omnibase_infra/handlers/models/http/registry_payload_http.py +212 -0
  132. omnibase_infra/handlers/models/mcp/__init__.py +23 -0
  133. omnibase_infra/handlers/models/mcp/enum_mcp_operation_type.py +24 -0
  134. omnibase_infra/handlers/models/mcp/model_mcp_handler_config.py +40 -0
  135. omnibase_infra/handlers/models/mcp/model_mcp_tool_call.py +32 -0
  136. omnibase_infra/handlers/models/mcp/model_mcp_tool_result.py +45 -0
  137. omnibase_infra/handlers/models/model_consul_handler_response.py +96 -0
  138. omnibase_infra/handlers/models/model_db_describe_response.py +83 -0
  139. omnibase_infra/handlers/models/model_db_query_payload.py +95 -0
  140. omnibase_infra/handlers/models/model_db_query_response.py +60 -0
  141. omnibase_infra/handlers/models/model_filesystem_config.py +98 -0
  142. omnibase_infra/handlers/models/model_filesystem_delete_payload.py +54 -0
  143. omnibase_infra/handlers/models/model_filesystem_delete_result.py +77 -0
  144. omnibase_infra/handlers/models/model_filesystem_directory_entry.py +75 -0
  145. omnibase_infra/handlers/models/model_filesystem_ensure_directory_payload.py +54 -0
  146. omnibase_infra/handlers/models/model_filesystem_ensure_directory_result.py +60 -0
  147. omnibase_infra/handlers/models/model_filesystem_list_directory_payload.py +60 -0
  148. omnibase_infra/handlers/models/model_filesystem_list_directory_result.py +68 -0
  149. omnibase_infra/handlers/models/model_filesystem_read_payload.py +62 -0
  150. omnibase_infra/handlers/models/model_filesystem_read_result.py +61 -0
  151. omnibase_infra/handlers/models/model_filesystem_write_payload.py +70 -0
  152. omnibase_infra/handlers/models/model_filesystem_write_result.py +55 -0
  153. omnibase_infra/handlers/models/model_graph_handler_response.py +98 -0
  154. omnibase_infra/handlers/models/model_handler_response.py +103 -0
  155. omnibase_infra/handlers/models/model_http_handler_response.py +101 -0
  156. omnibase_infra/handlers/models/model_manifest_metadata.py +75 -0
  157. omnibase_infra/handlers/models/model_manifest_persistence_config.py +62 -0
  158. omnibase_infra/handlers/models/model_manifest_query_payload.py +90 -0
  159. omnibase_infra/handlers/models/model_manifest_query_result.py +97 -0
  160. omnibase_infra/handlers/models/model_manifest_retrieve_payload.py +44 -0
  161. omnibase_infra/handlers/models/model_manifest_retrieve_result.py +98 -0
  162. omnibase_infra/handlers/models/model_manifest_store_payload.py +47 -0
  163. omnibase_infra/handlers/models/model_manifest_store_result.py +67 -0
  164. omnibase_infra/handlers/models/model_operation_context.py +187 -0
  165. omnibase_infra/handlers/models/model_qdrant_handler_response.py +98 -0
  166. omnibase_infra/handlers/models/model_retry_state.py +162 -0
  167. omnibase_infra/handlers/models/model_vault_handler_response.py +98 -0
  168. omnibase_infra/handlers/models/qdrant/__init__.py +44 -0
  169. omnibase_infra/handlers/models/qdrant/enum_qdrant_operation_type.py +26 -0
  170. omnibase_infra/handlers/models/qdrant/model_qdrant_collection_payload.py +42 -0
  171. omnibase_infra/handlers/models/qdrant/model_qdrant_delete_payload.py +36 -0
  172. omnibase_infra/handlers/models/qdrant/model_qdrant_handler_config.py +42 -0
  173. omnibase_infra/handlers/models/qdrant/model_qdrant_handler_payload.py +54 -0
  174. omnibase_infra/handlers/models/qdrant/model_qdrant_search_payload.py +42 -0
  175. omnibase_infra/handlers/models/qdrant/model_qdrant_search_result.py +30 -0
  176. omnibase_infra/handlers/models/qdrant/model_qdrant_upsert_payload.py +36 -0
  177. omnibase_infra/handlers/models/vault/__init__.py +69 -0
  178. omnibase_infra/handlers/models/vault/enum_vault_operation_type.py +35 -0
  179. omnibase_infra/handlers/models/vault/model_payload_vault.py +66 -0
  180. omnibase_infra/handlers/models/vault/model_vault_delete_payload.py +57 -0
  181. omnibase_infra/handlers/models/vault/model_vault_handler_config.py +148 -0
  182. omnibase_infra/handlers/models/vault/model_vault_handler_payload.py +101 -0
  183. omnibase_infra/handlers/models/vault/model_vault_list_payload.py +58 -0
  184. omnibase_infra/handlers/models/vault/model_vault_renew_token_payload.py +67 -0
  185. omnibase_infra/handlers/models/vault/model_vault_retry_config.py +66 -0
  186. omnibase_infra/handlers/models/vault/model_vault_secret_payload.py +106 -0
  187. omnibase_infra/handlers/models/vault/model_vault_write_payload.py +66 -0
  188. omnibase_infra/handlers/models/vault/registry_payload_vault.py +213 -0
  189. omnibase_infra/handlers/registration_storage/__init__.py +43 -0
  190. omnibase_infra/handlers/registration_storage/handler_registration_storage_mock.py +392 -0
  191. omnibase_infra/handlers/registration_storage/handler_registration_storage_postgres.py +915 -0
  192. omnibase_infra/handlers/registration_storage/models/__init__.py +23 -0
  193. omnibase_infra/handlers/registration_storage/models/model_delete_registration_request.py +58 -0
  194. omnibase_infra/handlers/registration_storage/models/model_update_registration_request.py +73 -0
  195. omnibase_infra/handlers/registration_storage/protocol_registration_persistence.py +191 -0
  196. omnibase_infra/handlers/service_discovery/__init__.py +43 -0
  197. omnibase_infra/handlers/service_discovery/handler_service_discovery_consul.py +747 -0
  198. omnibase_infra/handlers/service_discovery/handler_service_discovery_mock.py +258 -0
  199. omnibase_infra/handlers/service_discovery/models/__init__.py +22 -0
  200. omnibase_infra/handlers/service_discovery/models/model_discovery_result.py +64 -0
  201. omnibase_infra/handlers/service_discovery/models/model_registration_result.py +138 -0
  202. omnibase_infra/handlers/service_discovery/models/model_service_info.py +99 -0
  203. omnibase_infra/handlers/service_discovery/protocol_discovery_operations.py +170 -0
  204. omnibase_infra/idempotency/__init__.py +94 -0
  205. omnibase_infra/idempotency/models/__init__.py +43 -0
  206. omnibase_infra/idempotency/models/model_idempotency_check_result.py +85 -0
  207. omnibase_infra/idempotency/models/model_idempotency_guard_config.py +130 -0
  208. omnibase_infra/idempotency/models/model_idempotency_record.py +86 -0
  209. omnibase_infra/idempotency/models/model_idempotency_store_health_check_result.py +81 -0
  210. omnibase_infra/idempotency/models/model_idempotency_store_metrics.py +140 -0
  211. omnibase_infra/idempotency/models/model_postgres_idempotency_store_config.py +299 -0
  212. omnibase_infra/idempotency/protocol_idempotency_store.py +184 -0
  213. omnibase_infra/idempotency/store_inmemory.py +265 -0
  214. omnibase_infra/idempotency/store_postgres.py +923 -0
  215. omnibase_infra/infrastructure/__init__.py +0 -0
  216. omnibase_infra/mixins/__init__.py +71 -0
  217. omnibase_infra/mixins/mixin_async_circuit_breaker.py +655 -0
  218. omnibase_infra/mixins/mixin_dict_like_accessors.py +146 -0
  219. omnibase_infra/mixins/mixin_envelope_extraction.py +119 -0
  220. omnibase_infra/mixins/mixin_node_introspection.py +2465 -0
  221. omnibase_infra/mixins/mixin_retry_execution.py +386 -0
  222. omnibase_infra/mixins/protocol_circuit_breaker_aware.py +133 -0
  223. omnibase_infra/models/__init__.py +136 -0
  224. omnibase_infra/models/corpus/__init__.py +17 -0
  225. omnibase_infra/models/corpus/model_capture_config.py +133 -0
  226. omnibase_infra/models/corpus/model_capture_result.py +86 -0
  227. omnibase_infra/models/discovery/__init__.py +42 -0
  228. omnibase_infra/models/discovery/model_dependency_spec.py +319 -0
  229. omnibase_infra/models/discovery/model_discovered_capabilities.py +50 -0
  230. omnibase_infra/models/discovery/model_introspection_config.py +311 -0
  231. omnibase_infra/models/discovery/model_introspection_performance_metrics.py +169 -0
  232. omnibase_infra/models/discovery/model_introspection_task_config.py +116 -0
  233. omnibase_infra/models/dispatch/__init__.py +147 -0
  234. omnibase_infra/models/dispatch/model_dispatch_context.py +439 -0
  235. omnibase_infra/models/dispatch/model_dispatch_error.py +336 -0
  236. omnibase_infra/models/dispatch/model_dispatch_log_context.py +400 -0
  237. omnibase_infra/models/dispatch/model_dispatch_metadata.py +228 -0
  238. omnibase_infra/models/dispatch/model_dispatch_metrics.py +496 -0
  239. omnibase_infra/models/dispatch/model_dispatch_outcome.py +317 -0
  240. omnibase_infra/models/dispatch/model_dispatch_outputs.py +231 -0
  241. omnibase_infra/models/dispatch/model_dispatch_result.py +436 -0
  242. omnibase_infra/models/dispatch/model_dispatch_route.py +279 -0
  243. omnibase_infra/models/dispatch/model_dispatcher_metrics.py +275 -0
  244. omnibase_infra/models/dispatch/model_dispatcher_registration.py +352 -0
  245. omnibase_infra/models/dispatch/model_parsed_topic.py +135 -0
  246. omnibase_infra/models/dispatch/model_topic_parser.py +725 -0
  247. omnibase_infra/models/dispatch/model_tracing_context.py +285 -0
  248. omnibase_infra/models/errors/__init__.py +45 -0
  249. omnibase_infra/models/errors/model_handler_validation_error.py +594 -0
  250. omnibase_infra/models/errors/model_infra_error_context.py +99 -0
  251. omnibase_infra/models/errors/model_message_type_registry_error_context.py +71 -0
  252. omnibase_infra/models/errors/model_timeout_error_context.py +110 -0
  253. omnibase_infra/models/handlers/__init__.py +37 -0
  254. omnibase_infra/models/handlers/model_contract_discovery_result.py +80 -0
  255. omnibase_infra/models/handlers/model_handler_descriptor.py +185 -0
  256. omnibase_infra/models/handlers/model_handler_identifier.py +215 -0
  257. omnibase_infra/models/health/__init__.py +9 -0
  258. omnibase_infra/models/health/model_health_check_result.py +40 -0
  259. omnibase_infra/models/lifecycle/__init__.py +39 -0
  260. omnibase_infra/models/logging/__init__.py +51 -0
  261. omnibase_infra/models/logging/model_log_context.py +756 -0
  262. omnibase_infra/models/model_retry_error_classification.py +78 -0
  263. omnibase_infra/models/projection/__init__.py +43 -0
  264. omnibase_infra/models/projection/model_capability_fields.py +112 -0
  265. omnibase_infra/models/projection/model_registration_projection.py +434 -0
  266. omnibase_infra/models/projection/model_registration_snapshot.py +322 -0
  267. omnibase_infra/models/projection/model_sequence_info.py +182 -0
  268. omnibase_infra/models/projection/model_snapshot_topic_config.py +590 -0
  269. omnibase_infra/models/projectors/__init__.py +41 -0
  270. omnibase_infra/models/projectors/model_projector_column.py +289 -0
  271. omnibase_infra/models/projectors/model_projector_discovery_result.py +65 -0
  272. omnibase_infra/models/projectors/model_projector_index.py +270 -0
  273. omnibase_infra/models/projectors/model_projector_schema.py +415 -0
  274. omnibase_infra/models/projectors/model_projector_validation_error.py +63 -0
  275. omnibase_infra/models/projectors/util_sql_identifiers.py +115 -0
  276. omnibase_infra/models/registration/__init__.py +59 -0
  277. omnibase_infra/models/registration/commands/__init__.py +15 -0
  278. omnibase_infra/models/registration/commands/model_node_registration_acked.py +108 -0
  279. omnibase_infra/models/registration/events/__init__.py +56 -0
  280. omnibase_infra/models/registration/events/model_node_became_active.py +103 -0
  281. omnibase_infra/models/registration/events/model_node_liveness_expired.py +103 -0
  282. omnibase_infra/models/registration/events/model_node_registration_accepted.py +98 -0
  283. omnibase_infra/models/registration/events/model_node_registration_ack_received.py +98 -0
  284. omnibase_infra/models/registration/events/model_node_registration_ack_timed_out.py +112 -0
  285. omnibase_infra/models/registration/events/model_node_registration_initiated.py +107 -0
  286. omnibase_infra/models/registration/events/model_node_registration_rejected.py +104 -0
  287. omnibase_infra/models/registration/model_introspection_metrics.py +253 -0
  288. omnibase_infra/models/registration/model_node_capabilities.py +179 -0
  289. omnibase_infra/models/registration/model_node_heartbeat_event.py +126 -0
  290. omnibase_infra/models/registration/model_node_introspection_event.py +175 -0
  291. omnibase_infra/models/registration/model_node_metadata.py +79 -0
  292. omnibase_infra/models/registration/model_node_registration.py +162 -0
  293. omnibase_infra/models/registration/model_node_registration_record.py +162 -0
  294. omnibase_infra/models/registry/__init__.py +29 -0
  295. omnibase_infra/models/registry/model_domain_constraint.py +202 -0
  296. omnibase_infra/models/registry/model_message_type_entry.py +271 -0
  297. omnibase_infra/models/resilience/__init__.py +9 -0
  298. omnibase_infra/models/resilience/model_circuit_breaker_config.py +227 -0
  299. omnibase_infra/models/routing/__init__.py +25 -0
  300. omnibase_infra/models/routing/model_routing_entry.py +52 -0
  301. omnibase_infra/models/routing/model_routing_subcontract.py +70 -0
  302. omnibase_infra/models/runtime/__init__.py +40 -0
  303. omnibase_infra/models/runtime/model_contract_security_config.py +41 -0
  304. omnibase_infra/models/runtime/model_discovery_error.py +81 -0
  305. omnibase_infra/models/runtime/model_discovery_result.py +162 -0
  306. omnibase_infra/models/runtime/model_discovery_warning.py +74 -0
  307. omnibase_infra/models/runtime/model_failed_plugin_load.py +63 -0
  308. omnibase_infra/models/runtime/model_handler_contract.py +280 -0
  309. omnibase_infra/models/runtime/model_loaded_handler.py +120 -0
  310. omnibase_infra/models/runtime/model_plugin_load_context.py +93 -0
  311. omnibase_infra/models/runtime/model_plugin_load_summary.py +124 -0
  312. omnibase_infra/models/security/__init__.py +50 -0
  313. omnibase_infra/models/security/classification_levels.py +99 -0
  314. omnibase_infra/models/security/model_environment_policy.py +145 -0
  315. omnibase_infra/models/security/model_handler_security_policy.py +107 -0
  316. omnibase_infra/models/security/model_security_error.py +81 -0
  317. omnibase_infra/models/security/model_security_validation_result.py +328 -0
  318. omnibase_infra/models/security/model_security_warning.py +67 -0
  319. omnibase_infra/models/snapshot/__init__.py +27 -0
  320. omnibase_infra/models/snapshot/model_field_change.py +65 -0
  321. omnibase_infra/models/snapshot/model_snapshot.py +270 -0
  322. omnibase_infra/models/snapshot/model_snapshot_diff.py +203 -0
  323. omnibase_infra/models/snapshot/model_subject_ref.py +81 -0
  324. omnibase_infra/models/types/__init__.py +71 -0
  325. omnibase_infra/models/validation/__init__.py +89 -0
  326. omnibase_infra/models/validation/model_any_type_validation_result.py +118 -0
  327. omnibase_infra/models/validation/model_any_type_violation.py +141 -0
  328. omnibase_infra/models/validation/model_category_match_result.py +345 -0
  329. omnibase_infra/models/validation/model_chain_violation.py +166 -0
  330. omnibase_infra/models/validation/model_coverage_metrics.py +316 -0
  331. omnibase_infra/models/validation/model_execution_shape_rule.py +159 -0
  332. omnibase_infra/models/validation/model_execution_shape_validation.py +208 -0
  333. omnibase_infra/models/validation/model_execution_shape_validation_result.py +294 -0
  334. omnibase_infra/models/validation/model_execution_shape_violation.py +122 -0
  335. omnibase_infra/models/validation/model_localhandler_validation_result.py +139 -0
  336. omnibase_infra/models/validation/model_localhandler_violation.py +100 -0
  337. omnibase_infra/models/validation/model_output_validation_params.py +74 -0
  338. omnibase_infra/models/validation/model_validate_and_raise_params.py +84 -0
  339. omnibase_infra/models/validation/model_validation_error_params.py +84 -0
  340. omnibase_infra/models/validation/model_validation_outcome.py +287 -0
  341. omnibase_infra/nodes/__init__.py +48 -0
  342. omnibase_infra/nodes/architecture_validator/__init__.py +79 -0
  343. omnibase_infra/nodes/architecture_validator/contract.yaml +252 -0
  344. omnibase_infra/nodes/architecture_validator/contract_architecture_validator.yaml +208 -0
  345. omnibase_infra/nodes/architecture_validator/mixins/__init__.py +16 -0
  346. omnibase_infra/nodes/architecture_validator/mixins/mixin_file_path_rule.py +92 -0
  347. omnibase_infra/nodes/architecture_validator/models/__init__.py +36 -0
  348. omnibase_infra/nodes/architecture_validator/models/model_architecture_validation_request.py +56 -0
  349. omnibase_infra/nodes/architecture_validator/models/model_architecture_validation_result.py +311 -0
  350. omnibase_infra/nodes/architecture_validator/models/model_architecture_violation.py +163 -0
  351. omnibase_infra/nodes/architecture_validator/models/model_rule_check_result.py +265 -0
  352. omnibase_infra/nodes/architecture_validator/models/model_validation_request.py +105 -0
  353. omnibase_infra/nodes/architecture_validator/models/model_validation_result.py +314 -0
  354. omnibase_infra/nodes/architecture_validator/node.py +262 -0
  355. omnibase_infra/nodes/architecture_validator/node_architecture_validator.py +383 -0
  356. omnibase_infra/nodes/architecture_validator/protocols/__init__.py +9 -0
  357. omnibase_infra/nodes/architecture_validator/protocols/protocol_architecture_rule.py +225 -0
  358. omnibase_infra/nodes/architecture_validator/registry/__init__.py +28 -0
  359. omnibase_infra/nodes/architecture_validator/registry/registry_infra_architecture_validator.py +99 -0
  360. omnibase_infra/nodes/architecture_validator/validators/__init__.py +104 -0
  361. omnibase_infra/nodes/architecture_validator/validators/validator_no_direct_dispatch.py +422 -0
  362. omnibase_infra/nodes/architecture_validator/validators/validator_no_handler_publishing.py +481 -0
  363. omnibase_infra/nodes/architecture_validator/validators/validator_no_orchestrator_fsm.py +491 -0
  364. omnibase_infra/nodes/effects/README.md +358 -0
  365. omnibase_infra/nodes/effects/__init__.py +26 -0
  366. omnibase_infra/nodes/effects/contract.yaml +172 -0
  367. omnibase_infra/nodes/effects/models/__init__.py +32 -0
  368. omnibase_infra/nodes/effects/models/model_backend_result.py +190 -0
  369. omnibase_infra/nodes/effects/models/model_effect_idempotency_config.py +92 -0
  370. omnibase_infra/nodes/effects/models/model_registry_request.py +132 -0
  371. omnibase_infra/nodes/effects/models/model_registry_response.py +263 -0
  372. omnibase_infra/nodes/effects/protocol_consul_client.py +89 -0
  373. omnibase_infra/nodes/effects/protocol_effect_idempotency_store.py +143 -0
  374. omnibase_infra/nodes/effects/protocol_postgres_adapter.py +96 -0
  375. omnibase_infra/nodes/effects/registry_effect.py +525 -0
  376. omnibase_infra/nodes/effects/store_effect_idempotency_inmemory.py +425 -0
  377. omnibase_infra/nodes/node_registration_orchestrator/README.md +542 -0
  378. omnibase_infra/nodes/node_registration_orchestrator/__init__.py +120 -0
  379. omnibase_infra/nodes/node_registration_orchestrator/contract.yaml +475 -0
  380. omnibase_infra/nodes/node_registration_orchestrator/dispatchers/__init__.py +53 -0
  381. omnibase_infra/nodes/node_registration_orchestrator/dispatchers/dispatcher_node_introspected.py +376 -0
  382. omnibase_infra/nodes/node_registration_orchestrator/dispatchers/dispatcher_node_registration_acked.py +376 -0
  383. omnibase_infra/nodes/node_registration_orchestrator/dispatchers/dispatcher_runtime_tick.py +373 -0
  384. omnibase_infra/nodes/node_registration_orchestrator/handlers/__init__.py +62 -0
  385. omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_heartbeat.py +376 -0
  386. omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_introspected.py +609 -0
  387. omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_registration_acked.py +458 -0
  388. omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_runtime_tick.py +364 -0
  389. omnibase_infra/nodes/node_registration_orchestrator/introspection_event_router.py +544 -0
  390. omnibase_infra/nodes/node_registration_orchestrator/models/__init__.py +75 -0
  391. omnibase_infra/nodes/node_registration_orchestrator/models/model_consul_intent_payload.py +194 -0
  392. omnibase_infra/nodes/node_registration_orchestrator/models/model_consul_registration_intent.py +67 -0
  393. omnibase_infra/nodes/node_registration_orchestrator/models/model_intent_execution_result.py +50 -0
  394. omnibase_infra/nodes/node_registration_orchestrator/models/model_node_liveness_expired.py +107 -0
  395. omnibase_infra/nodes/node_registration_orchestrator/models/model_orchestrator_config.py +67 -0
  396. omnibase_infra/nodes/node_registration_orchestrator/models/model_orchestrator_input.py +41 -0
  397. omnibase_infra/nodes/node_registration_orchestrator/models/model_orchestrator_output.py +166 -0
  398. omnibase_infra/nodes/node_registration_orchestrator/models/model_postgres_intent_payload.py +235 -0
  399. omnibase_infra/nodes/node_registration_orchestrator/models/model_postgres_upsert_intent.py +68 -0
  400. omnibase_infra/nodes/node_registration_orchestrator/models/model_reducer_execution_result.py +384 -0
  401. omnibase_infra/nodes/node_registration_orchestrator/models/model_reducer_state.py +60 -0
  402. omnibase_infra/nodes/node_registration_orchestrator/models/model_registration_intent.py +177 -0
  403. omnibase_infra/nodes/node_registration_orchestrator/models/model_registry_intent.py +247 -0
  404. omnibase_infra/nodes/node_registration_orchestrator/node.py +195 -0
  405. omnibase_infra/nodes/node_registration_orchestrator/plugin.py +909 -0
  406. omnibase_infra/nodes/node_registration_orchestrator/protocols.py +439 -0
  407. omnibase_infra/nodes/node_registration_orchestrator/registry/__init__.py +41 -0
  408. omnibase_infra/nodes/node_registration_orchestrator/registry/registry_infra_node_registration_orchestrator.py +525 -0
  409. omnibase_infra/nodes/node_registration_orchestrator/timeout_coordinator.py +392 -0
  410. omnibase_infra/nodes/node_registration_orchestrator/wiring.py +742 -0
  411. omnibase_infra/nodes/node_registration_reducer/__init__.py +15 -0
  412. omnibase_infra/nodes/node_registration_reducer/contract.yaml +301 -0
  413. omnibase_infra/nodes/node_registration_reducer/models/__init__.py +38 -0
  414. omnibase_infra/nodes/node_registration_reducer/models/model_validation_result.py +113 -0
  415. omnibase_infra/nodes/node_registration_reducer/node.py +139 -0
  416. omnibase_infra/nodes/node_registration_reducer/registry/__init__.py +9 -0
  417. omnibase_infra/nodes/node_registration_reducer/registry/registry_infra_node_registration_reducer.py +79 -0
  418. omnibase_infra/nodes/node_registration_storage_effect/__init__.py +41 -0
  419. omnibase_infra/nodes/node_registration_storage_effect/contract.yaml +225 -0
  420. omnibase_infra/nodes/node_registration_storage_effect/models/__init__.py +44 -0
  421. omnibase_infra/nodes/node_registration_storage_effect/models/model_delete_result.py +132 -0
  422. omnibase_infra/nodes/node_registration_storage_effect/models/model_registration_record.py +199 -0
  423. omnibase_infra/nodes/node_registration_storage_effect/models/model_registration_update.py +155 -0
  424. omnibase_infra/nodes/node_registration_storage_effect/models/model_storage_health_check_details.py +123 -0
  425. omnibase_infra/nodes/node_registration_storage_effect/models/model_storage_health_check_result.py +117 -0
  426. omnibase_infra/nodes/node_registration_storage_effect/models/model_storage_query.py +100 -0
  427. omnibase_infra/nodes/node_registration_storage_effect/models/model_storage_result.py +136 -0
  428. omnibase_infra/nodes/node_registration_storage_effect/models/model_upsert_result.py +127 -0
  429. omnibase_infra/nodes/node_registration_storage_effect/node.py +109 -0
  430. omnibase_infra/nodes/node_registration_storage_effect/protocols/__init__.py +22 -0
  431. omnibase_infra/nodes/node_registration_storage_effect/protocols/protocol_registration_persistence.py +333 -0
  432. omnibase_infra/nodes/node_registration_storage_effect/registry/__init__.py +23 -0
  433. omnibase_infra/nodes/node_registration_storage_effect/registry/registry_infra_registration_storage.py +194 -0
  434. omnibase_infra/nodes/node_registry_effect/__init__.py +85 -0
  435. omnibase_infra/nodes/node_registry_effect/contract.yaml +682 -0
  436. omnibase_infra/nodes/node_registry_effect/handlers/__init__.py +70 -0
  437. omnibase_infra/nodes/node_registry_effect/handlers/handler_consul_deregister.py +211 -0
  438. omnibase_infra/nodes/node_registry_effect/handlers/handler_consul_register.py +212 -0
  439. omnibase_infra/nodes/node_registry_effect/handlers/handler_partial_retry.py +416 -0
  440. omnibase_infra/nodes/node_registry_effect/handlers/handler_postgres_deactivate.py +215 -0
  441. omnibase_infra/nodes/node_registry_effect/handlers/handler_postgres_upsert.py +208 -0
  442. omnibase_infra/nodes/node_registry_effect/models/__init__.py +43 -0
  443. omnibase_infra/nodes/node_registry_effect/models/model_partial_retry_request.py +92 -0
  444. omnibase_infra/nodes/node_registry_effect/node.py +165 -0
  445. omnibase_infra/nodes/node_registry_effect/registry/__init__.py +27 -0
  446. omnibase_infra/nodes/node_registry_effect/registry/registry_infra_registry_effect.py +196 -0
  447. omnibase_infra/nodes/node_service_discovery_effect/__init__.py +111 -0
  448. omnibase_infra/nodes/node_service_discovery_effect/contract.yaml +246 -0
  449. omnibase_infra/nodes/node_service_discovery_effect/models/__init__.py +67 -0
  450. omnibase_infra/nodes/node_service_discovery_effect/models/enum_health_status.py +72 -0
  451. omnibase_infra/nodes/node_service_discovery_effect/models/enum_service_discovery_operation.py +58 -0
  452. omnibase_infra/nodes/node_service_discovery_effect/models/model_discovery_query.py +99 -0
  453. omnibase_infra/nodes/node_service_discovery_effect/models/model_discovery_result.py +98 -0
  454. omnibase_infra/nodes/node_service_discovery_effect/models/model_health_check_config.py +121 -0
  455. omnibase_infra/nodes/node_service_discovery_effect/models/model_query_metadata.py +63 -0
  456. omnibase_infra/nodes/node_service_discovery_effect/models/model_registration_result.py +130 -0
  457. omnibase_infra/nodes/node_service_discovery_effect/models/model_service_discovery_health_check_details.py +111 -0
  458. omnibase_infra/nodes/node_service_discovery_effect/models/model_service_discovery_health_check_result.py +119 -0
  459. omnibase_infra/nodes/node_service_discovery_effect/models/model_service_info.py +106 -0
  460. omnibase_infra/nodes/node_service_discovery_effect/models/model_service_registration.py +121 -0
  461. omnibase_infra/nodes/node_service_discovery_effect/node.py +111 -0
  462. omnibase_infra/nodes/node_service_discovery_effect/protocols/__init__.py +14 -0
  463. omnibase_infra/nodes/node_service_discovery_effect/protocols/protocol_discovery_operations.py +279 -0
  464. omnibase_infra/nodes/node_service_discovery_effect/registry/__init__.py +13 -0
  465. omnibase_infra/nodes/node_service_discovery_effect/registry/registry_infra_service_discovery.py +214 -0
  466. omnibase_infra/nodes/reducers/__init__.py +30 -0
  467. omnibase_infra/nodes/reducers/models/__init__.py +32 -0
  468. omnibase_infra/nodes/reducers/models/model_payload_consul_register.py +76 -0
  469. omnibase_infra/nodes/reducers/models/model_payload_postgres_upsert_registration.py +60 -0
  470. omnibase_infra/nodes/reducers/models/model_registration_confirmation.py +166 -0
  471. omnibase_infra/nodes/reducers/models/model_registration_state.py +433 -0
  472. omnibase_infra/nodes/reducers/registration_reducer.py +1137 -0
  473. omnibase_infra/observability/__init__.py +143 -0
  474. omnibase_infra/observability/constants_metrics.py +91 -0
  475. omnibase_infra/observability/factory_observability_sink.py +525 -0
  476. omnibase_infra/observability/handlers/__init__.py +118 -0
  477. omnibase_infra/observability/handlers/handler_logging_structured.py +967 -0
  478. omnibase_infra/observability/handlers/handler_metrics_prometheus.py +1120 -0
  479. omnibase_infra/observability/handlers/model_logging_handler_config.py +71 -0
  480. omnibase_infra/observability/handlers/model_logging_handler_response.py +77 -0
  481. omnibase_infra/observability/handlers/model_metrics_handler_config.py +172 -0
  482. omnibase_infra/observability/handlers/model_metrics_handler_payload.py +135 -0
  483. omnibase_infra/observability/handlers/model_metrics_handler_response.py +101 -0
  484. omnibase_infra/observability/hooks/__init__.py +74 -0
  485. omnibase_infra/observability/hooks/hook_observability.py +1223 -0
  486. omnibase_infra/observability/models/__init__.py +30 -0
  487. omnibase_infra/observability/models/enum_required_log_context_key.py +77 -0
  488. omnibase_infra/observability/models/model_buffered_log_entry.py +117 -0
  489. omnibase_infra/observability/models/model_logging_sink_config.py +73 -0
  490. omnibase_infra/observability/models/model_metrics_sink_config.py +156 -0
  491. omnibase_infra/observability/sinks/__init__.py +69 -0
  492. omnibase_infra/observability/sinks/sink_logging_structured.py +809 -0
  493. omnibase_infra/observability/sinks/sink_metrics_prometheus.py +710 -0
  494. omnibase_infra/plugins/__init__.py +27 -0
  495. omnibase_infra/plugins/examples/__init__.py +28 -0
  496. omnibase_infra/plugins/examples/plugin_json_normalizer.py +271 -0
  497. omnibase_infra/plugins/examples/plugin_json_normalizer_error_handling.py +210 -0
  498. omnibase_infra/plugins/models/__init__.py +21 -0
  499. omnibase_infra/plugins/models/model_plugin_context.py +76 -0
  500. omnibase_infra/plugins/models/model_plugin_input_data.py +58 -0
  501. omnibase_infra/plugins/models/model_plugin_output_data.py +62 -0
  502. omnibase_infra/plugins/plugin_compute_base.py +435 -0
  503. omnibase_infra/projectors/__init__.py +30 -0
  504. omnibase_infra/projectors/contracts/__init__.py +63 -0
  505. omnibase_infra/projectors/contracts/registration_projector.yaml +370 -0
  506. omnibase_infra/projectors/projection_reader_registration.py +1559 -0
  507. omnibase_infra/projectors/snapshot_publisher_registration.py +1329 -0
  508. omnibase_infra/protocols/__init__.py +99 -0
  509. omnibase_infra/protocols/protocol_capability_projection.py +253 -0
  510. omnibase_infra/protocols/protocol_capability_query.py +251 -0
  511. omnibase_infra/protocols/protocol_event_bus_like.py +127 -0
  512. omnibase_infra/protocols/protocol_event_projector.py +96 -0
  513. omnibase_infra/protocols/protocol_idempotency_store.py +142 -0
  514. omnibase_infra/protocols/protocol_message_dispatcher.py +247 -0
  515. omnibase_infra/protocols/protocol_message_type_registry.py +306 -0
  516. omnibase_infra/protocols/protocol_plugin_compute.py +368 -0
  517. omnibase_infra/protocols/protocol_projector_schema_validator.py +82 -0
  518. omnibase_infra/protocols/protocol_registry_metrics.py +215 -0
  519. omnibase_infra/protocols/protocol_snapshot_publisher.py +396 -0
  520. omnibase_infra/protocols/protocol_snapshot_store.py +567 -0
  521. omnibase_infra/runtime/__init__.py +296 -0
  522. omnibase_infra/runtime/binding_config_resolver.py +2706 -0
  523. omnibase_infra/runtime/chain_aware_dispatch.py +467 -0
  524. omnibase_infra/runtime/contract_handler_discovery.py +582 -0
  525. omnibase_infra/runtime/contract_loaders/__init__.py +42 -0
  526. omnibase_infra/runtime/contract_loaders/handler_routing_loader.py +464 -0
  527. omnibase_infra/runtime/dispatch_context_enforcer.py +427 -0
  528. omnibase_infra/runtime/enums/__init__.py +18 -0
  529. omnibase_infra/runtime/enums/enum_config_ref_scheme.py +33 -0
  530. omnibase_infra/runtime/enums/enum_scheduler_status.py +170 -0
  531. omnibase_infra/runtime/envelope_validator.py +179 -0
  532. omnibase_infra/runtime/handler_contract_source.py +669 -0
  533. omnibase_infra/runtime/handler_plugin_loader.py +2029 -0
  534. omnibase_infra/runtime/handler_registry.py +321 -0
  535. omnibase_infra/runtime/invocation_security_enforcer.py +427 -0
  536. omnibase_infra/runtime/kernel.py +40 -0
  537. omnibase_infra/runtime/mixin_policy_validation.py +522 -0
  538. omnibase_infra/runtime/mixin_semver_cache.py +378 -0
  539. omnibase_infra/runtime/mixins/__init__.py +17 -0
  540. omnibase_infra/runtime/mixins/mixin_projector_sql_operations.py +757 -0
  541. omnibase_infra/runtime/models/__init__.py +192 -0
  542. omnibase_infra/runtime/models/model_batch_lifecycle_result.py +217 -0
  543. omnibase_infra/runtime/models/model_binding_config.py +168 -0
  544. omnibase_infra/runtime/models/model_binding_config_cache_stats.py +135 -0
  545. omnibase_infra/runtime/models/model_binding_config_resolver_config.py +329 -0
  546. omnibase_infra/runtime/models/model_cached_secret.py +138 -0
  547. omnibase_infra/runtime/models/model_compute_key.py +138 -0
  548. omnibase_infra/runtime/models/model_compute_registration.py +97 -0
  549. omnibase_infra/runtime/models/model_config_cache_entry.py +61 -0
  550. omnibase_infra/runtime/models/model_config_ref.py +331 -0
  551. omnibase_infra/runtime/models/model_config_ref_parse_result.py +125 -0
  552. omnibase_infra/runtime/models/model_domain_plugin_config.py +92 -0
  553. omnibase_infra/runtime/models/model_domain_plugin_result.py +270 -0
  554. omnibase_infra/runtime/models/model_duplicate_response.py +54 -0
  555. omnibase_infra/runtime/models/model_enabled_protocols_config.py +61 -0
  556. omnibase_infra/runtime/models/model_event_bus_config.py +54 -0
  557. omnibase_infra/runtime/models/model_failed_component.py +55 -0
  558. omnibase_infra/runtime/models/model_health_check_response.py +168 -0
  559. omnibase_infra/runtime/models/model_health_check_result.py +228 -0
  560. omnibase_infra/runtime/models/model_lifecycle_result.py +245 -0
  561. omnibase_infra/runtime/models/model_logging_config.py +42 -0
  562. omnibase_infra/runtime/models/model_optional_correlation_id.py +167 -0
  563. omnibase_infra/runtime/models/model_optional_string.py +94 -0
  564. omnibase_infra/runtime/models/model_optional_uuid.py +110 -0
  565. omnibase_infra/runtime/models/model_policy_context.py +100 -0
  566. omnibase_infra/runtime/models/model_policy_key.py +138 -0
  567. omnibase_infra/runtime/models/model_policy_registration.py +139 -0
  568. omnibase_infra/runtime/models/model_policy_result.py +103 -0
  569. omnibase_infra/runtime/models/model_policy_type_filter.py +157 -0
  570. omnibase_infra/runtime/models/model_projector_plugin_loader_config.py +47 -0
  571. omnibase_infra/runtime/models/model_protocol_registration_config.py +65 -0
  572. omnibase_infra/runtime/models/model_retry_policy.py +105 -0
  573. omnibase_infra/runtime/models/model_runtime_config.py +150 -0
  574. omnibase_infra/runtime/models/model_runtime_scheduler_config.py +624 -0
  575. omnibase_infra/runtime/models/model_runtime_scheduler_metrics.py +233 -0
  576. omnibase_infra/runtime/models/model_runtime_tick.py +193 -0
  577. omnibase_infra/runtime/models/model_secret_cache_stats.py +82 -0
  578. omnibase_infra/runtime/models/model_secret_mapping.py +63 -0
  579. omnibase_infra/runtime/models/model_secret_resolver_config.py +107 -0
  580. omnibase_infra/runtime/models/model_secret_resolver_metrics.py +111 -0
  581. omnibase_infra/runtime/models/model_secret_source_info.py +72 -0
  582. omnibase_infra/runtime/models/model_secret_source_spec.py +66 -0
  583. omnibase_infra/runtime/models/model_shutdown_batch_result.py +75 -0
  584. omnibase_infra/runtime/models/model_shutdown_config.py +94 -0
  585. omnibase_infra/runtime/projector_plugin_loader.py +1462 -0
  586. omnibase_infra/runtime/projector_schema_manager.py +565 -0
  587. omnibase_infra/runtime/projector_shell.py +1102 -0
  588. omnibase_infra/runtime/protocol_contract_descriptor.py +92 -0
  589. omnibase_infra/runtime/protocol_contract_source.py +92 -0
  590. omnibase_infra/runtime/protocol_domain_plugin.py +474 -0
  591. omnibase_infra/runtime/protocol_handler_discovery.py +221 -0
  592. omnibase_infra/runtime/protocol_handler_plugin_loader.py +327 -0
  593. omnibase_infra/runtime/protocol_lifecycle_executor.py +435 -0
  594. omnibase_infra/runtime/protocol_policy.py +366 -0
  595. omnibase_infra/runtime/protocols/__init__.py +27 -0
  596. omnibase_infra/runtime/protocols/protocol_runtime_scheduler.py +468 -0
  597. omnibase_infra/runtime/registry/__init__.py +93 -0
  598. omnibase_infra/runtime/registry/mixin_message_type_query.py +326 -0
  599. omnibase_infra/runtime/registry/mixin_message_type_registration.py +354 -0
  600. omnibase_infra/runtime/registry/registry_event_bus_binding.py +268 -0
  601. omnibase_infra/runtime/registry/registry_message_type.py +542 -0
  602. omnibase_infra/runtime/registry/registry_protocol_binding.py +444 -0
  603. omnibase_infra/runtime/registry_compute.py +1143 -0
  604. omnibase_infra/runtime/registry_dispatcher.py +678 -0
  605. omnibase_infra/runtime/registry_policy.py +1502 -0
  606. omnibase_infra/runtime/runtime_scheduler.py +1070 -0
  607. omnibase_infra/runtime/secret_resolver.py +2110 -0
  608. omnibase_infra/runtime/security_metadata_validator.py +776 -0
  609. omnibase_infra/runtime/service_kernel.py +1573 -0
  610. omnibase_infra/runtime/service_message_dispatch_engine.py +1805 -0
  611. omnibase_infra/runtime/service_runtime_host_process.py +2260 -0
  612. omnibase_infra/runtime/util_container_wiring.py +1123 -0
  613. omnibase_infra/runtime/util_validation.py +314 -0
  614. omnibase_infra/runtime/util_version.py +98 -0
  615. omnibase_infra/runtime/util_wiring.py +566 -0
  616. omnibase_infra/schemas/schema_registration_projection.sql +320 -0
  617. omnibase_infra/services/__init__.py +68 -0
  618. omnibase_infra/services/corpus_capture.py +678 -0
  619. omnibase_infra/services/service_capability_query.py +945 -0
  620. omnibase_infra/services/service_health.py +897 -0
  621. omnibase_infra/services/service_node_selector.py +530 -0
  622. omnibase_infra/services/service_timeout_emitter.py +682 -0
  623. omnibase_infra/services/service_timeout_scanner.py +390 -0
  624. omnibase_infra/services/snapshot/__init__.py +31 -0
  625. omnibase_infra/services/snapshot/service_snapshot.py +647 -0
  626. omnibase_infra/services/snapshot/store_inmemory.py +637 -0
  627. omnibase_infra/services/snapshot/store_postgres.py +1279 -0
  628. omnibase_infra/shared/__init__.py +8 -0
  629. omnibase_infra/testing/__init__.py +10 -0
  630. omnibase_infra/testing/utils.py +23 -0
  631. omnibase_infra/types/__init__.py +48 -0
  632. omnibase_infra/types/type_cache_info.py +49 -0
  633. omnibase_infra/types/type_dsn.py +173 -0
  634. omnibase_infra/types/type_infra_aliases.py +60 -0
  635. omnibase_infra/types/typed_dict/__init__.py +21 -0
  636. omnibase_infra/types/typed_dict/typed_dict_introspection_cache.py +128 -0
  637. omnibase_infra/types/typed_dict/typed_dict_performance_metrics_cache.py +140 -0
  638. omnibase_infra/types/typed_dict_capabilities.py +64 -0
  639. omnibase_infra/utils/__init__.py +89 -0
  640. omnibase_infra/utils/correlation.py +208 -0
  641. omnibase_infra/utils/util_datetime.py +372 -0
  642. omnibase_infra/utils/util_dsn_validation.py +333 -0
  643. omnibase_infra/utils/util_env_parsing.py +264 -0
  644. omnibase_infra/utils/util_error_sanitization.py +457 -0
  645. omnibase_infra/utils/util_pydantic_validators.py +477 -0
  646. omnibase_infra/utils/util_semver.py +233 -0
  647. omnibase_infra/validation/__init__.py +307 -0
  648. omnibase_infra/validation/enums/__init__.py +11 -0
  649. omnibase_infra/validation/enums/enum_contract_violation_severity.py +13 -0
  650. omnibase_infra/validation/infra_validators.py +1486 -0
  651. omnibase_infra/validation/linter_contract.py +907 -0
  652. omnibase_infra/validation/mixin_any_type_classification.py +120 -0
  653. omnibase_infra/validation/mixin_any_type_exemption.py +580 -0
  654. omnibase_infra/validation/mixin_any_type_reporting.py +106 -0
  655. omnibase_infra/validation/mixin_execution_shape_violation_checks.py +596 -0
  656. omnibase_infra/validation/mixin_node_archetype_detection.py +254 -0
  657. omnibase_infra/validation/models/__init__.py +15 -0
  658. omnibase_infra/validation/models/model_contract_lint_result.py +101 -0
  659. omnibase_infra/validation/models/model_contract_violation.py +41 -0
  660. omnibase_infra/validation/service_validation_aggregator.py +395 -0
  661. omnibase_infra/validation/validation_exemptions.yaml +1710 -0
  662. omnibase_infra/validation/validator_any_type.py +715 -0
  663. omnibase_infra/validation/validator_chain_propagation.py +839 -0
  664. omnibase_infra/validation/validator_execution_shape.py +465 -0
  665. omnibase_infra/validation/validator_localhandler.py +261 -0
  666. omnibase_infra/validation/validator_registration_security.py +410 -0
  667. omnibase_infra/validation/validator_routing_coverage.py +1020 -0
  668. omnibase_infra/validation/validator_runtime_shape.py +915 -0
  669. omnibase_infra/validation/validator_security.py +410 -0
  670. omnibase_infra/validation/validator_topic_category.py +1152 -0
  671. omnibase_infra-0.2.1.dist-info/METADATA +197 -0
  672. omnibase_infra-0.2.1.dist-info/RECORD +675 -0
  673. omnibase_infra-0.2.1.dist-info/WHEEL +4 -0
  674. omnibase_infra-0.2.1.dist-info/entry_points.txt +4 -0
  675. omnibase_infra-0.2.1.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,1143 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2025 OmniNode Team
3
+ """Compute Registry - SINGLE SOURCE OF TRUTH for compute plugin registration.
4
+
5
+ This module provides the RegistryCompute class for registering and resolving
6
+ deterministic compute plugins in the ONEX infrastructure layer.
7
+
8
+ Compute plugins:
9
+ - Perform deterministic, in-process computation with NO external I/O
10
+ - Examples: JSON normalization, ranking/scoring, policy evaluation, diffing, AST transforms
11
+ - MUST be synchronous by default (async requires explicit deterministic_async=True flag)
12
+
13
+ Design Principles:
14
+ - Single source of truth: All compute plugin registrations go through this registry
15
+ - Sync enforcement: Async plugins must be explicitly flagged
16
+ - Type-safe: Full typing for plugin registrations (no Any types)
17
+ - Thread-safe: Registration operations protected by lock
18
+ - Testable: Easy to mock and test plugin configurations
19
+
20
+ CRITICAL: Compute plugins are PURE computation logic only.
21
+
22
+ Compute plugins MUST NOT:
23
+ - Perform I/O operations (file, network, database)
24
+ - Have side effects (state mutation outside return values)
25
+ - Make external service calls
26
+ - Log at runtime
27
+ - Depend on mutable global state
28
+ - Access current time (unless explicitly provided as input)
29
+ - Use random number generation (unless deterministic with provided seed)
30
+
31
+ Example Usage:
32
+ ```python
33
+ from omnibase_core.container import ModelONEXContainer
34
+ from omnibase_infra.runtime.registry_compute import RegistryCompute
35
+ from omnibase_infra.runtime.models import ModelComputeRegistration
36
+
37
+ # Container-based DI (preferred)
38
+ container = ModelONEXContainer()
39
+ await wire_infrastructure_services(container)
40
+ registry = await container.service_registry.resolve_service(RegistryCompute)
41
+
42
+ # Register a synchronous plugin using the model (preferred)
43
+ registration = ModelComputeRegistration(
44
+ plugin_id="json_normalizer",
45
+ plugin_class=JsonNormalizerPlugin,
46
+ version="1.0.0",
47
+ description="Normalizes JSON for deterministic comparison",
48
+ )
49
+ registry.register(registration)
50
+
51
+ # Register using convenience method
52
+ registry.register_plugin(
53
+ plugin_id="async_transformer",
54
+ plugin_class=AsyncTransformerPlugin,
55
+ version="1.0.0",
56
+ deterministic_async=True, # MUST be explicit for async plugins
57
+ )
58
+
59
+ # Retrieve a plugin
60
+ plugin_cls = registry.get("json_normalizer")
61
+ plugin = plugin_cls()
62
+ result = plugin.execute(input_data, context)
63
+
64
+ # List all plugins
65
+ plugins = registry.list_keys() # [(plugin_id, version), ...]
66
+ ```
67
+
68
+ Integration Points:
69
+ - RuntimeHostProcess uses this registry to discover and instantiate compute plugins
70
+ - Plugins are loaded based on contract definitions
71
+ - Supports hot-reload patterns for development
72
+ """
73
+
74
+ from __future__ import annotations
75
+
76
+ import asyncio
77
+ import functools
78
+ import inspect
79
+ import logging
80
+ import os
81
+ import threading
82
+ import time
83
+ import warnings
84
+ from collections.abc import Callable
85
+ from typing import TYPE_CHECKING
86
+
87
+ from omnibase_infra.errors import (
88
+ ComputeRegistryError,
89
+ ModelInfraErrorContext,
90
+ ProtocolConfigurationError,
91
+ )
92
+ from omnibase_infra.runtime.models import ModelComputeRegistration
93
+ from omnibase_infra.runtime.models.model_compute_key import ModelComputeKey
94
+
95
+ if TYPE_CHECKING:
96
+ from omnibase_infra.protocols import ProtocolPluginCompute, ProtocolRegistryMetrics
97
+
98
+ # Module-level logger for metrics and registry operations
99
+ logger = logging.getLogger(__name__)
100
+
101
+
102
+ # =============================================================================
103
+ # Metrics Timer Utility
104
+ # =============================================================================
105
+
106
+
107
+ class _MetricsTimer:
108
+ """Context manager for timing operations.
109
+
110
+ Provides high-precision timing using time.perf_counter() for accurate
111
+ latency measurements in the registry metrics system.
112
+
113
+ Attributes:
114
+ elapsed_ms: Time elapsed in milliseconds after exiting the context.
115
+
116
+ Example:
117
+ >>> timer = _MetricsTimer()
118
+ >>> with timer:
119
+ ... # perform operation
120
+ ... result = expensive_operation()
121
+ >>> print(f"Operation took {timer.elapsed_ms:.2f}ms")
122
+ """
123
+
124
+ def __init__(self) -> None:
125
+ """Initialize timer with zero elapsed time."""
126
+ self.elapsed_ms: float = 0.0
127
+ self._start: float = 0.0
128
+
129
+ def __enter__(self) -> _MetricsTimer:
130
+ """Start timing on context entry."""
131
+ self._start = time.perf_counter()
132
+ return self
133
+
134
+ def __exit__(self, *args: object) -> None:
135
+ """Calculate elapsed time on context exit."""
136
+ self.elapsed_ms = (time.perf_counter() - self._start) * 1000
137
+
138
+
139
+ # =============================================================================
140
+ # Compute Registry
141
+ # =============================================================================
142
+
143
+ # Semver sorting sentinel value (chr(127) = DEL character, ASCII 127)
144
+ # WHY chr(127): In semantic versioning, releases sort AFTER prereleases:
145
+ # - "1.0.0-alpha" < "1.0.0" (prerelease comes before release)
146
+ # - "1.0.0-beta" < "1.0.0"
147
+ #
148
+ # For string comparison to work correctly:
149
+ # - Prerelease strings (e.g., "alpha", "beta") are compared lexicographically
150
+ # - Empty prerelease (release version) needs to sort AFTER any prerelease string
151
+ # - chr(127) is the highest printable ASCII value (DEL character)
152
+ # - Any prerelease string ("alpha", "rc", "beta") < chr(127)
153
+ # - Therefore: ("1.0.0-alpha") < ("1.0.0") because "alpha" < chr(127)
154
+ _SEMVER_SORT_SENTINEL = chr(127)
155
+
156
+ # Environment variable for configuring the semver LRU cache size
157
+ # Set ONEX_COMPUTE_REGISTRY_CACHE_SIZE to tune cache size for large deployments
158
+ ENV_COMPUTE_REGISTRY_CACHE_SIZE = "ONEX_COMPUTE_REGISTRY_CACHE_SIZE"
159
+
160
+ # Default cache size when environment variable is not set
161
+ _DEFAULT_SEMVER_CACHE_SIZE = 128
162
+
163
+
164
+ def _get_compute_registry_cache_size() -> int:
165
+ """Get compute registry cache size from environment.
166
+
167
+ Reads the ONEX_COMPUTE_REGISTRY_CACHE_SIZE environment variable.
168
+ If not set, returns the default cache size.
169
+
170
+ Range validation: Cache size must be between 1 and 10000.
171
+ - Below 1: Uses default (logged as warning)
172
+ - Above 10000: Uses default (logged as warning)
173
+
174
+ Returns:
175
+ Cache size as an integer.
176
+
177
+ Raises:
178
+ ProtocolConfigurationError: If the environment variable contains
179
+ a non-integer value.
180
+ """
181
+ from omnibase_infra.enums import EnumInfraTransportType
182
+ from omnibase_infra.utils.util_env_parsing import parse_env_int
183
+
184
+ if os.environ.get(ENV_COMPUTE_REGISTRY_CACHE_SIZE) is not None:
185
+ return parse_env_int(
186
+ ENV_COMPUTE_REGISTRY_CACHE_SIZE,
187
+ _DEFAULT_SEMVER_CACHE_SIZE,
188
+ min_value=1,
189
+ max_value=10000,
190
+ transport_type=EnumInfraTransportType.HTTP,
191
+ service_name="compute_registry",
192
+ )
193
+
194
+ return _DEFAULT_SEMVER_CACHE_SIZE
195
+
196
+
197
+ class RegistryCompute:
198
+ """SINGLE SOURCE OF TRUTH for compute plugin registration in omnibase_infra.
199
+
200
+ Thread-safe registry for compute plugins. Manages deterministic computation plugins
201
+ that perform pure data transformations without side effects.
202
+
203
+ The registry maintains a mapping from ModelComputeKey instances to plugin classes
204
+ that implement the ProtocolPluginCompute protocol. ModelComputeKey provides strong
205
+ typing and replaces the legacy tuple[str, str] pattern.
206
+
207
+ Container Integration:
208
+ RegistryCompute is designed to be managed by ModelONEXContainer from omnibase_core.
209
+ Use container_wiring.wire_infrastructure_services() to register RegistryCompute
210
+ in the container, then resolve it via:
211
+
212
+ ```python
213
+ from omnibase_core.container import ModelONEXContainer
214
+ from omnibase_infra.runtime.registry_compute import RegistryCompute
215
+
216
+ # Resolve from container (preferred)
217
+ registry = await container.service_registry.resolve_service(RegistryCompute)
218
+ ```
219
+
220
+ Thread Safety:
221
+ All registration operations are protected by a threading.Lock to ensure
222
+ thread-safe access in concurrent environments.
223
+
224
+ Sync Enforcement:
225
+ By default, plugins must be synchronous. If a plugin has async methods
226
+ (execute or any public method), registration will fail unless
227
+ deterministic_async=True is explicitly specified.
228
+
229
+ Scale and Performance Characteristics:
230
+
231
+ Expected Registry Scale:
232
+ - Typical ONEX system: 10-30 unique compute plugins across 2-5 versions each
233
+ - Medium deployment: 30-50 plugins across 3-8 versions each
234
+ - Large deployment: 50-100 plugins across 5-10 versions each
235
+ - Stress tested: 500+ total registrations (100 plugins x 5 versions)
236
+
237
+ Performance Characteristics:
238
+
239
+ Primary Operations:
240
+ - register(): O(1) - Direct dictionary insert with secondary index update
241
+ - get(plugin_id): O(1) best case, O(k) average
242
+ where k = number of matching versions
243
+ - Uses secondary index (_plugin_id_index) for O(1) plugin_id lookup
244
+ - Fast path (single version): O(1) direct lookup
245
+ - Multi-version: O(k) to find max version via comparison
246
+ - Cached semver parsing: LRU cache (128 entries) avoids re-parsing
247
+
248
+ - is_registered(): O(k) where k = versions for plugin_id
249
+ - list_keys(): O(n*log n) where n = total registrations (full scan + sort)
250
+ - list_versions(): O(k) where k = versions for plugin_id
251
+ - unregister(): O(k) where k = versions for plugin_id
252
+
253
+ Benchmark Targets (match RegistryPolicy):
254
+ - 1000 sequential get() calls: < 100ms (< 0.1ms per lookup)
255
+ - 1000 concurrent get() calls (10 threads): < 500ms
256
+ - 100 failed lookups (missing plugin_id): < 500ms (early exit optimization)
257
+
258
+ Lock Contention:
259
+ - Read operations (get, is_registered): Hold lock during lookup only
260
+ - Write operations (register, unregister): Hold lock for full operation
261
+ - Critical sections minimized to reduce contention
262
+ - Expected concurrent throughput: > 2000 reads/sec under 10-thread load
263
+
264
+ Memory Footprint:
265
+
266
+ Per Plugin Registration:
267
+ - ModelComputeKey: ~160 bytes (2 strings: plugin_id, version)
268
+ - Plugin class reference: 8 bytes (Python object pointer)
269
+ - Secondary index entry: ~50 bytes (list entry + key reference)
270
+ - Total per registration: ~220 bytes
271
+
272
+ Estimated Registry Memory:
273
+ - 50 registrations: ~11 KB
274
+ - 100 registrations: ~22 KB
275
+ - 500 registrations: ~110 KB
276
+
277
+ Cache Overhead:
278
+ - Semver LRU cache: Configurable via ONEX_COMPUTE_REGISTRY_CACHE_SIZE env var
279
+ (default: 128 entries x ~100 bytes = ~12.8 KB)
280
+ - Total with cache: Registry memory + cache overhead
281
+
282
+ Environment Variables:
283
+ ONEX_COMPUTE_REGISTRY_CACHE_SIZE: Configure the semver LRU cache size for large
284
+ deployments. Set to a higher value (e.g., 256, 512) if you have many
285
+ unique version strings. Default: 128.
286
+
287
+ Attributes:
288
+ _registry: Internal dictionary mapping ModelComputeKey instances to plugin classes
289
+ _lock: Threading lock for thread-safe registration operations
290
+ _plugin_id_index: Secondary index for O(1) plugin_id lookup
291
+ SEMVER_CACHE_SIZE: Class variable for LRU cache size, read from
292
+ ONEX_COMPUTE_REGISTRY_CACHE_SIZE environment variable (default: 128)
293
+
294
+ Example:
295
+ >>> from omnibase_infra.runtime.models import ModelComputeRegistration
296
+ >>> from omnibase_infra.runtime.models.model_compute_key import ModelComputeKey
297
+ >>> registry = RegistryCompute()
298
+ >>> registration = ModelComputeRegistration(
299
+ ... plugin_id="json_normalizer",
300
+ ... plugin_class=JsonNormalizerPlugin,
301
+ ... )
302
+ >>> registry.register(registration)
303
+ >>> plugin_cls = registry.get("json_normalizer")
304
+ >>> print(registry.list_keys())
305
+ [('json_normalizer', '1.0.0')]
306
+ """
307
+
308
+ # ==========================================================================
309
+ # Class-level semver cache configuration
310
+ # ==========================================================================
311
+
312
+ # Semver cache size - configurable via ONEX_COMPUTE_REGISTRY_CACHE_SIZE env var
313
+ # Read at class definition time; can be overridden via class attribute before first parse
314
+ SEMVER_CACHE_SIZE: int = _get_compute_registry_cache_size()
315
+
316
+ # Cached semver parser function (lazily initialized)
317
+ _semver_cache: Callable[[str], tuple[int, int, int, str]] | None = None
318
+
319
+ # Lock for thread-safe cache initialization
320
+ _semver_cache_lock: threading.Lock = threading.Lock()
321
+
322
+ def __init__(
323
+ self, metrics_collector: ProtocolRegistryMetrics | None = None
324
+ ) -> None:
325
+ """Initialize an empty compute registry with thread lock.
326
+
327
+ Args:
328
+ metrics_collector: Optional metrics collector for production monitoring.
329
+ If provided, registry operations will record latency, cache hits/misses,
330
+ registry size changes, and errors to the collector.
331
+ See ProtocolRegistryMetrics for the expected interface.
332
+ """
333
+ # Key: ModelComputeKey -> plugin_class (strong typing replaces tuple pattern)
334
+ self._registry: dict[ModelComputeKey, type[ProtocolPluginCompute]] = {}
335
+ self._lock: threading.Lock = threading.Lock()
336
+
337
+ # Performance optimization: Secondary indexes for O(1) lookups
338
+ # Maps plugin_id -> list of ModelComputeKey instances
339
+ self._plugin_id_index: dict[str, list[ModelComputeKey]] = {}
340
+
341
+ # Optional metrics collector for production monitoring
342
+ self._metrics: ProtocolRegistryMetrics | None = metrics_collector
343
+
344
+ def set_metrics_collector(self, collector: ProtocolRegistryMetrics | None) -> None:
345
+ """Set the metrics collector for production monitoring.
346
+
347
+ This method allows setting or changing the metrics collector after
348
+ initialization. Pass None to disable metrics collection.
349
+
350
+ Args:
351
+ collector: Metrics collector implementing ProtocolRegistryMetrics,
352
+ or None to disable metrics collection.
353
+
354
+ Example:
355
+ >>> from omnibase_infra.runtime.registry_compute import RegistryCompute
356
+ >>> registry = RegistryCompute()
357
+ >>> # Later, enable metrics
358
+ >>> registry.set_metrics_collector(my_metrics)
359
+ >>> # Or disable
360
+ >>> registry.set_metrics_collector(None)
361
+ """
362
+ self._metrics = collector
363
+
364
+ def _validate_sync_enforcement(
365
+ self,
366
+ plugin_id: str,
367
+ plugin_class: type,
368
+ deterministic_async: bool,
369
+ ) -> None:
370
+ """Validate that plugin is synchronous unless explicitly flagged.
371
+
372
+ CRITICAL: This validation inspects ALL public methods, not just execute().
373
+ This ensures that compute plugins with any async methods are flagged properly.
374
+
375
+ This validation enforces the synchronous-by-default plugin execution model.
376
+ Compute plugins are expected to be pure computation logic without I/O or async
377
+ operations. If a plugin needs async methods (e.g., for deterministic async
378
+ computation), it must be explicitly flagged with deterministic_async=True
379
+ during registration.
380
+
381
+ Validation Process:
382
+ 1. Check if execute() method exists and is async
383
+ 2. Iterate through ALL public methods (not prefixed with _)
384
+ 3. Check if any method is a coroutine function
385
+ 4. If async methods found and deterministic_async=False, raise error
386
+ 5. If async methods found and deterministic_async=True, allow registration
387
+
388
+ Args:
389
+ plugin_id: Unique identifier for the plugin being validated
390
+ plugin_class: The plugin class to validate for async methods
391
+ deterministic_async: If True, allows async interface; if False, enforces sync
392
+
393
+ Raises:
394
+ ComputeRegistryError: If plugin has async methods and deterministic_async=False.
395
+ Error includes the plugin_id and the name of the async
396
+ method that caused validation failure.
397
+
398
+ Example:
399
+ >>> # This will fail - async plugin without explicit flag
400
+ >>> class AsyncPlugin:
401
+ ... async def execute(self, input_data, context):
402
+ ... return {"result": True}
403
+ >>> registry._validate_sync_enforcement("async_plugin", AsyncPlugin, False)
404
+ ComputeRegistryError: Plugin 'async_plugin' has async execute() but
405
+ deterministic_async=True not specified.
406
+
407
+ >>> # This will succeed - async explicitly flagged
408
+ >>> registry._validate_sync_enforcement("async_plugin", AsyncPlugin, True)
409
+ """
410
+ # First check execute() method specifically for clear error message
411
+ if hasattr(plugin_class, "execute"):
412
+ if asyncio.iscoroutinefunction(plugin_class.execute):
413
+ if not deterministic_async:
414
+ raise ComputeRegistryError(
415
+ f"Plugin {plugin_id!r} has async execute() but "
416
+ f"deterministic_async=True not specified. "
417
+ f"Compute plugins must be synchronous by default.",
418
+ plugin_id=plugin_id,
419
+ context=ModelInfraErrorContext.with_correlation(
420
+ operation="validate_sync_enforcement",
421
+ ),
422
+ async_method="execute",
423
+ )
424
+
425
+ # Check ALL public methods for async (comprehensive validation)
426
+ for name, method in inspect.getmembers(
427
+ plugin_class, predicate=inspect.isfunction
428
+ ):
429
+ # Skip private methods (prefixed with _)
430
+ if name.startswith("_"):
431
+ continue
432
+
433
+ # Check if method is async
434
+ if asyncio.iscoroutinefunction(method):
435
+ if not deterministic_async:
436
+ raise ComputeRegistryError(
437
+ f"Plugin {plugin_id!r} has async method {name}() but "
438
+ f"deterministic_async=True not specified. "
439
+ f"Compute plugins must be synchronous by default.",
440
+ plugin_id=plugin_id,
441
+ context=ModelInfraErrorContext.with_correlation(
442
+ operation="validate_sync_enforcement",
443
+ ),
444
+ async_method=name,
445
+ )
446
+
447
+ def register(self, registration: ModelComputeRegistration) -> None:
448
+ """Register a compute plugin using a registration model.
449
+
450
+ Associates a (plugin_id, version) tuple with a plugin class.
451
+ If the combination is already registered, the existing registration is
452
+ overwritten.
453
+
454
+ Args:
455
+ registration: ModelComputeRegistration containing all registration parameters:
456
+ - plugin_id: Unique identifier for the plugin
457
+ - plugin_class: The plugin class to register (must implement ProtocolPluginCompute)
458
+ - version: Semantic version string (default: "1.0.0")
459
+ - description: Human-readable description
460
+ - deterministic_async: If True, allows async interface
461
+
462
+ Raises:
463
+ ComputeRegistryError: If plugin has async methods and
464
+ deterministic_async=False, or if plugin_class
465
+ does not implement ProtocolPluginCompute
466
+ ProtocolConfigurationError: If version format is invalid
467
+
468
+ Example:
469
+ >>> from omnibase_infra.runtime.models import ModelComputeRegistration
470
+ >>> registry = RegistryCompute()
471
+ >>> registration = ModelComputeRegistration(
472
+ ... plugin_id="json_normalizer",
473
+ ... plugin_class=JsonNormalizerPlugin,
474
+ ... version="1.0.0",
475
+ ... )
476
+ >>> registry.register(registration)
477
+ """
478
+ # Extract fields from model
479
+ plugin_id = registration.plugin_id
480
+ plugin_class = registration.plugin_class
481
+ version = registration.version
482
+ deterministic_async = registration.deterministic_async
483
+
484
+ # Runtime type validation: Ensure plugin_class implements ProtocolPluginCompute protocol
485
+ # Check if execute() method exists and is callable
486
+ execute_attr = getattr(plugin_class, "execute", None)
487
+
488
+ if execute_attr is None:
489
+ raise ComputeRegistryError(
490
+ f"Plugin class {plugin_class.__name__!r} does not implement "
491
+ f"ProtocolPluginCompute protocol: missing 'execute()' method",
492
+ plugin_id=plugin_id,
493
+ context=ModelInfraErrorContext.with_correlation(
494
+ operation="register",
495
+ ),
496
+ plugin_class=plugin_class.__name__,
497
+ )
498
+
499
+ if not callable(execute_attr):
500
+ raise ComputeRegistryError(
501
+ f"Plugin class {plugin_class.__name__!r} does not implement "
502
+ f"ProtocolPluginCompute protocol: 'execute' attribute is not callable",
503
+ plugin_id=plugin_id,
504
+ context=ModelInfraErrorContext.with_correlation(
505
+ operation="register",
506
+ ),
507
+ plugin_class=plugin_class.__name__,
508
+ )
509
+
510
+ # Validate sync enforcement
511
+ self._validate_sync_enforcement(plugin_id, plugin_class, deterministic_async)
512
+
513
+ # Validate version format (ensures semantic versioning compliance)
514
+ # This calls _parse_semver which will raise ProtocolConfigurationError if invalid
515
+ self._parse_semver(version)
516
+
517
+ # Register the plugin using ModelComputeKey
518
+ key = ModelComputeKey(plugin_id=plugin_id, version=version)
519
+ with self._lock:
520
+ self._registry[key] = plugin_class
521
+ # Update secondary index for performance optimization
522
+ if plugin_id not in self._plugin_id_index:
523
+ self._plugin_id_index[plugin_id] = []
524
+ if key not in self._plugin_id_index[plugin_id]:
525
+ self._plugin_id_index[plugin_id].append(key)
526
+ registry_size = len(self._registry)
527
+
528
+ # Record registry size if metrics collector is set
529
+ if self._metrics is not None:
530
+ try:
531
+ self._metrics.record_registry_size(registry_size)
532
+ except Exception:
533
+ # Metrics recording should never break registry operations
534
+ # WARNING level for development visibility (change to DEBUG for production)
535
+ logger.warning(
536
+ "Metrics error suppressed during register()",
537
+ exc_info=True,
538
+ extra={"plugin_id": plugin_id, "version": version},
539
+ )
540
+
541
+ def register_plugin(
542
+ self,
543
+ plugin_id: str,
544
+ plugin_class: type,
545
+ version: str = "1.0.0",
546
+ deterministic_async: bool = False,
547
+ description: str = "",
548
+ ) -> None:
549
+ """Convenience method to register a plugin with individual parameters.
550
+
551
+ Wraps parameters in ModelComputeRegistration and calls register().
552
+
553
+ Args:
554
+ plugin_id: Unique identifier for the plugin (e.g., 'json_normalizer')
555
+ plugin_class: The plugin class to register. Must implement ProtocolPluginCompute.
556
+ version: Semantic version string (default: "1.0.0")
557
+ deterministic_async: If True, allows async interface. MUST be explicitly
558
+ flagged for plugins with async methods.
559
+ description: Human-readable description of the plugin
560
+
561
+ Raises:
562
+ ComputeRegistryError: If plugin has async methods and
563
+ deterministic_async=False
564
+ ProtocolConfigurationError: If version format is invalid
565
+
566
+ Example:
567
+ >>> registry = RegistryCompute()
568
+ >>> registry.register_plugin(
569
+ ... plugin_id="json_normalizer",
570
+ ... plugin_class=JsonNormalizerPlugin,
571
+ ... version="1.0.0",
572
+ ... )
573
+ """
574
+ registration = ModelComputeRegistration(
575
+ plugin_id=plugin_id,
576
+ plugin_class=plugin_class,
577
+ version=version,
578
+ description=description,
579
+ deterministic_async=deterministic_async,
580
+ )
581
+ self.register(registration)
582
+
583
+ def get(
584
+ self,
585
+ plugin_id: str,
586
+ version: str | None = None,
587
+ ) -> type[ProtocolPluginCompute]:
588
+ """Get compute plugin by ID and optional version.
589
+
590
+ Resolves the plugin class registered for the given plugin configuration.
591
+ If version is not specified, returns the latest version (semver sorted).
592
+
593
+ Performance Characteristics:
594
+ - Best case: O(1) - Direct lookup with single version
595
+ - Average case: O(k) where k = number of matching versions
596
+ - Uses secondary index for O(1) plugin_id lookup instead of O(n) scan
597
+ - Defers expensive error message generation until actually needed
598
+
599
+ Args:
600
+ plugin_id: Plugin identifier.
601
+ version: Optional version filter. If None, returns latest version.
602
+
603
+ Returns:
604
+ Plugin class registered for the configuration.
605
+
606
+ Raises:
607
+ ComputeRegistryError: If no matching plugin is found.
608
+
609
+ Example:
610
+ >>> registry = RegistryCompute()
611
+ >>> registry.register_plugin("normalizer", NormalizerPlugin)
612
+ >>> plugin_cls = registry.get("normalizer")
613
+ >>> plugin_cls = registry.get("normalizer", version="1.0.0")
614
+ """
615
+ timer = _MetricsTimer()
616
+ try:
617
+ with timer:
618
+ with self._lock:
619
+ # Performance optimization: Use secondary index for O(1) lookup
620
+ # This avoids iterating through all registry entries (O(n) -> O(1))
621
+ candidate_keys = self._plugin_id_index.get(plugin_id, [])
622
+
623
+ # Early exit if plugin_id not found - avoid building matches list
624
+ if not candidate_keys:
625
+ # Record error before raising
626
+ if self._metrics is not None:
627
+ try:
628
+ self._metrics.record_error("not_found", plugin_id)
629
+ except Exception:
630
+ # Metrics recording should never break registry operations
631
+ # WARNING level for development visibility (change to DEBUG for production)
632
+ logger.warning(
633
+ "Metrics error suppressed during get() not_found",
634
+ exc_info=True,
635
+ extra={"plugin_id": plugin_id},
636
+ )
637
+ # Get unique, sorted list of registered plugin IDs for error context
638
+ # Uses secondary index for O(m) where m=unique plugins vs O(n) scan
639
+ registered: list[str] = sorted(self._plugin_id_index.keys())
640
+ raise ComputeRegistryError(
641
+ f"No compute plugin registered with id={plugin_id!r}. "
642
+ f"Registered plugins: {registered}",
643
+ plugin_id=plugin_id,
644
+ registered_plugins=registered,
645
+ context=ModelInfraErrorContext.with_correlation(
646
+ operation="get",
647
+ ),
648
+ version=version,
649
+ )
650
+
651
+ # If version specified, do exact match
652
+ if version is not None:
653
+ for key in candidate_keys:
654
+ if key.version == version:
655
+ return self._registry[key]
656
+ # Record error before raising
657
+ if self._metrics is not None:
658
+ try:
659
+ self._metrics.record_error(
660
+ "version_not_found", plugin_id
661
+ )
662
+ except Exception:
663
+ # Metrics recording should never break registry operations
664
+ # WARNING level for development visibility (change to DEBUG for production)
665
+ logger.warning(
666
+ "Metrics error suppressed during get() version_not_found",
667
+ exc_info=True,
668
+ extra={"plugin_id": plugin_id, "version": version},
669
+ )
670
+ # Version not found - get versions from candidate_keys
671
+ available_versions = sorted(
672
+ [key.version for key in candidate_keys],
673
+ key=self._parse_semver,
674
+ )
675
+ raise ComputeRegistryError(
676
+ f"Compute plugin {plugin_id!r} version {version!r} "
677
+ f"not found. Available versions: {available_versions}",
678
+ plugin_id=plugin_id,
679
+ context=ModelInfraErrorContext.with_correlation(
680
+ operation="get",
681
+ ),
682
+ version=version,
683
+ )
684
+
685
+ # Return latest version (no version filter)
686
+ # Fast path optimization: avoid sorting if only one version
687
+ if len(candidate_keys) == 1:
688
+ return self._registry[candidate_keys[0]]
689
+
690
+ # Multiple versions - find latest using semver comparison
691
+ latest_key = max(
692
+ candidate_keys,
693
+ key=lambda k: self._parse_semver(k.version),
694
+ )
695
+ return self._registry[latest_key]
696
+ finally:
697
+ # Record latency if metrics collector is set
698
+ if self._metrics is not None:
699
+ try:
700
+ self._metrics.record_get_latency(
701
+ plugin_id, version, timer.elapsed_ms
702
+ )
703
+ except Exception:
704
+ # Metrics recording should never break registry operations
705
+ # WARNING level for development visibility (change to DEBUG for production)
706
+ logger.warning(
707
+ "Metrics error suppressed during get() latency recording",
708
+ exc_info=True,
709
+ extra={"plugin_id": plugin_id, "version": version},
710
+ )
711
+
712
+ def list_keys(self) -> list[tuple[str, str]]:
713
+ """List registered plugin keys as (plugin_id, version) tuples.
714
+
715
+ Returns:
716
+ List of (plugin_id, version) tuples, sorted by plugin_id then semver.
717
+
718
+ Example:
719
+ >>> registry = RegistryCompute()
720
+ >>> registry.register_plugin("normalizer", NormalizerV1, version="1.0.0")
721
+ >>> registry.register_plugin("normalizer", NormalizerV2, version="2.0.0")
722
+ >>> print(registry.list_keys())
723
+ [('normalizer', '1.0.0'), ('normalizer', '2.0.0')]
724
+ """
725
+ with self._lock:
726
+ return sorted(
727
+ [k.to_tuple() for k in self._registry],
728
+ key=lambda x: (x[0], self._parse_semver(x[1])),
729
+ )
730
+
731
+ def list_versions(self, plugin_id: str) -> list[str]:
732
+ """List registered versions for a plugin ID.
733
+
734
+ Args:
735
+ plugin_id: The plugin ID to list versions for.
736
+
737
+ Returns:
738
+ List of version strings registered for the plugin ID, sorted by semver.
739
+
740
+ Example:
741
+ >>> registry = RegistryCompute()
742
+ >>> registry.register_plugin("normalizer", NormalizerV1, version="1.0.0")
743
+ >>> registry.register_plugin("normalizer", NormalizerV2, version="2.0.0")
744
+ >>> print(registry.list_versions("normalizer"))
745
+ ['1.0.0', '2.0.0']
746
+ """
747
+ with self._lock:
748
+ # Performance optimization: Use secondary index
749
+ candidate_keys = self._plugin_id_index.get(plugin_id, [])
750
+ versions = sorted(
751
+ [key.version for key in candidate_keys],
752
+ key=self._parse_semver,
753
+ )
754
+ return versions
755
+
756
+ def is_registered(
757
+ self,
758
+ plugin_id: str,
759
+ version: str | None = None,
760
+ ) -> bool:
761
+ """Check if a plugin is registered.
762
+
763
+ Args:
764
+ plugin_id: Plugin identifier.
765
+ version: Optional version filter.
766
+
767
+ Returns:
768
+ True if a matching plugin is registered, False otherwise.
769
+
770
+ Example:
771
+ >>> registry = RegistryCompute()
772
+ >>> registry.register_plugin("normalizer", NormalizerPlugin)
773
+ >>> registry.is_registered("normalizer")
774
+ True
775
+ >>> registry.is_registered("unknown")
776
+ False
777
+ """
778
+ with self._lock:
779
+ # Performance optimization: Use secondary index
780
+ candidate_keys = self._plugin_id_index.get(plugin_id, [])
781
+ if not candidate_keys:
782
+ return False
783
+ if version is None:
784
+ return True
785
+ return any(key.version == version for key in candidate_keys)
786
+
787
+ def unregister(
788
+ self,
789
+ plugin_id: str,
790
+ version: str | None = None,
791
+ ) -> int:
792
+ """Unregister compute plugin(s).
793
+
794
+ Removes plugin registrations matching the given criteria.
795
+ This is useful for testing and hot-reload scenarios.
796
+
797
+ Args:
798
+ plugin_id: Plugin identifier to unregister.
799
+ version: Optional version filter. If None, removes all versions.
800
+
801
+ Returns:
802
+ Number of plugins unregistered.
803
+
804
+ Example:
805
+ >>> registry = RegistryCompute()
806
+ >>> registry.register_plugin("normalizer", NormalizerV1, version="1.0.0")
807
+ >>> registry.register_plugin("normalizer", NormalizerV2, version="2.0.0")
808
+ >>> registry.unregister("normalizer") # Removes all versions
809
+ 2
810
+ >>> registry.unregister("normalizer", version="1.0.0") # Remove specific version
811
+ 1
812
+ """
813
+ # Thread safety: Lock held during full unregister operation (write operation)
814
+ with self._lock:
815
+ # Performance optimization: Use secondary index
816
+ candidate_keys = self._plugin_id_index.get(plugin_id, [])
817
+ keys_to_remove: list[ModelComputeKey] = []
818
+
819
+ for key in candidate_keys:
820
+ if version is None or key.version == version:
821
+ keys_to_remove.append(key)
822
+
823
+ for key in keys_to_remove:
824
+ del self._registry[key]
825
+ # Update secondary index
826
+ self._plugin_id_index[plugin_id].remove(key)
827
+
828
+ # Clean up empty index entries
829
+ if (
830
+ plugin_id in self._plugin_id_index
831
+ and not self._plugin_id_index[plugin_id]
832
+ ):
833
+ del self._plugin_id_index[plugin_id]
834
+
835
+ registry_size = len(self._registry)
836
+ removed_count = len(keys_to_remove)
837
+
838
+ # Record registry size if metrics collector is set and we removed something
839
+ if removed_count > 0 and self._metrics is not None:
840
+ try:
841
+ self._metrics.record_registry_size(registry_size)
842
+ except Exception:
843
+ # Metrics recording should never break registry operations
844
+ # WARNING level for development visibility (change to DEBUG for production)
845
+ logger.warning(
846
+ "Metrics error suppressed during unregister()",
847
+ exc_info=True,
848
+ extra={"plugin_id": plugin_id, "version": version},
849
+ )
850
+
851
+ return removed_count
852
+
853
+ def clear(self) -> None:
854
+ """Clear all plugin registrations.
855
+
856
+ Removes all registered plugins from the registry.
857
+
858
+ Warning:
859
+ This method is intended for **testing purposes only**.
860
+ Calling it in production code will emit a warning.
861
+ It breaks the immutability guarantee after startup.
862
+
863
+ Example:
864
+ >>> registry = RegistryCompute()
865
+ >>> registry.register_plugin("normalizer", NormalizerPlugin)
866
+ >>> registry.clear()
867
+ >>> registry.list_keys()
868
+ []
869
+ """
870
+ warnings.warn(
871
+ "RegistryCompute.clear() is intended for testing only. "
872
+ "Do not use in production code.",
873
+ UserWarning,
874
+ stacklevel=2,
875
+ )
876
+ with self._lock:
877
+ self._registry.clear()
878
+ self._plugin_id_index.clear()
879
+
880
+ def __len__(self) -> int:
881
+ """Return the number of registered plugins.
882
+
883
+ Returns:
884
+ Number of registered plugin (plugin_id, version) combinations.
885
+
886
+ Example:
887
+ >>> registry = RegistryCompute()
888
+ >>> len(registry)
889
+ 0
890
+ >>> registry.register_plugin("normalizer", NormalizerPlugin)
891
+ >>> len(registry)
892
+ 1
893
+ """
894
+ with self._lock:
895
+ return len(self._registry)
896
+
897
+ def __contains__(self, key: ModelComputeKey | str) -> bool:
898
+ """Check if plugin is registered using 'in' operator.
899
+
900
+ Args:
901
+ key: Either a ModelComputeKey instance or a plugin_id string.
902
+
903
+ Returns:
904
+ True if plugin is registered, False otherwise.
905
+
906
+ Example:
907
+ >>> registry = RegistryCompute()
908
+ >>> registry.register_plugin("normalizer", NormalizerPlugin)
909
+ >>> "normalizer" in registry
910
+ True
911
+ >>> ModelComputeKey(plugin_id="normalizer", version="1.0.0") in registry
912
+ True
913
+ >>> "unknown" in registry
914
+ False
915
+ """
916
+ if isinstance(key, str):
917
+ return self.is_registered(key)
918
+ return self.is_registered(key.plugin_id, key.version)
919
+
920
+ # ==========================================================================
921
+ # Semver Cache Configuration Methods
922
+ # ==========================================================================
923
+
924
+ @classmethod
925
+ def _get_semver_parser(cls) -> Callable[[str], tuple[int, int, int, str]]:
926
+ """Get or create the semver parser with configured cache size.
927
+
928
+ This method implements lazy initialization of the LRU-cached semver parser.
929
+ The cache size is determined by SEMVER_CACHE_SIZE at initialization time.
930
+
931
+ Thread Safety:
932
+ Uses double-checked locking pattern for thread-safe lazy initialization.
933
+ The fast path stores the cache reference in a local variable to prevent
934
+ TOCTOU (time-of-check-time-of-use) race conditions where another thread
935
+ could call _reset_semver_cache() between the None check and the return.
936
+
937
+ Returns:
938
+ Cached semver parsing function.
939
+
940
+ Performance:
941
+ - First call: Creates LRU-cached function (one-time cost)
942
+ - Subsequent calls: Returns cached function reference (O(1))
943
+ """
944
+ # Fast path: cache already initialized
945
+ # CRITICAL: Store in local variable to prevent TOCTOU race condition.
946
+ # Without this, another thread could call _reset_semver_cache() between
947
+ # the None check and the return, causing this method to return None.
948
+ cache = cls._semver_cache
949
+ if cache is not None:
950
+ return cache
951
+
952
+ # Slow path: initialize with lock
953
+ with cls._semver_cache_lock:
954
+ # Double-check after acquiring lock
955
+ if cls._semver_cache is not None:
956
+ return cls._semver_cache
957
+
958
+ # Create LRU-cached parser with configured size
959
+ @functools.lru_cache(maxsize=cls.SEMVER_CACHE_SIZE)
960
+ def _parse_semver_impl(version: str) -> tuple[int, int, int, str]:
961
+ """Parse semantic version string into comparable tuple.
962
+
963
+ Implementation moved here to support configurable cache size.
964
+ See _parse_semver docstring for full documentation.
965
+ """
966
+ # Validate non-empty version string
967
+ if not version or not version.strip():
968
+ raise ProtocolConfigurationError(
969
+ "Invalid semantic version format: empty version string",
970
+ context=ModelInfraErrorContext.with_correlation(
971
+ operation="parse_semver",
972
+ ),
973
+ version=version,
974
+ )
975
+
976
+ # Trim whitespace BEFORE any split operations
977
+ version = version.strip()
978
+
979
+ # Split off prerelease suffix (e.g., "1.0.0-alpha" -> "1.0.0", "alpha")
980
+ if "-" in version:
981
+ version_part, prerelease = version.split("-", 1)
982
+ # Validate prerelease is non-empty when dash is present
983
+ if not prerelease:
984
+ raise ProtocolConfigurationError(
985
+ f"Invalid semantic version format: '{version}'. "
986
+ f"Prerelease suffix cannot be empty when '-' is specified.",
987
+ context=ModelInfraErrorContext.with_correlation(
988
+ operation="parse_semver",
989
+ ),
990
+ version=version,
991
+ )
992
+ else:
993
+ version_part, prerelease = version, ""
994
+
995
+ # Parse major.minor.patch
996
+ parts = version_part.split(".")
997
+
998
+ # Validate version format (max 3 parts, no empty parts)
999
+ # Note: len(parts) >= 1 is guaranteed since split(".") always returns
1000
+ # at least one element, so we only need to check the upper bound
1001
+ if len(parts) > 3 or any(not p.strip() for p in parts):
1002
+ raise ProtocolConfigurationError(
1003
+ f"Invalid semantic version format: '{version}'",
1004
+ context=ModelInfraErrorContext.with_correlation(
1005
+ operation="parse_semver",
1006
+ ),
1007
+ version=version,
1008
+ )
1009
+
1010
+ try:
1011
+ major = int(parts[0])
1012
+ minor = int(parts[1]) if len(parts) > 1 else 0
1013
+ patch = int(parts[2]) if len(parts) > 2 else 0
1014
+ except (ValueError, IndexError) as e:
1015
+ raise ProtocolConfigurationError(
1016
+ f"Invalid semantic version format: '{version}'",
1017
+ context=ModelInfraErrorContext.with_correlation(
1018
+ operation="parse_semver",
1019
+ ),
1020
+ version=version,
1021
+ ) from e
1022
+
1023
+ # Validate non-negative integers
1024
+ if major < 0 or minor < 0 or patch < 0:
1025
+ raise ProtocolConfigurationError(
1026
+ f"Invalid semantic version: negative component in '{version}'",
1027
+ context=ModelInfraErrorContext.with_correlation(
1028
+ operation="parse_semver",
1029
+ ),
1030
+ version=version,
1031
+ )
1032
+
1033
+ # Empty prerelease uses sentinel (chr(127)) to sort AFTER any prerelease string
1034
+ # This ensures "1.0.0" > "1.0.0-alpha" in version comparisons
1035
+ sort_prerelease = prerelease if prerelease else _SEMVER_SORT_SENTINEL
1036
+
1037
+ return (major, minor, patch, sort_prerelease)
1038
+
1039
+ cls._semver_cache = _parse_semver_impl
1040
+ return cls._semver_cache
1041
+
1042
+ @classmethod
1043
+ def _parse_semver(cls, version: str) -> tuple[int, int, int, str]:
1044
+ """Parse semantic version string into comparable tuple with INTEGER components.
1045
+
1046
+ This method implements SEMANTIC VERSION SORTING, not lexicographic sorting.
1047
+ This is critical for correct "latest version" selection.
1048
+
1049
+ Why This Matters:
1050
+ Lexicographic sorting (string comparison):
1051
+ "1.10.0" < "1.9.0" WRONG (because '1' < '9' in strings)
1052
+ "10.0.0" < "2.0.0" WRONG (because '1' < '2' in strings)
1053
+
1054
+ Semantic version sorting (integer comparison):
1055
+ 1.10.0 > 1.9.0 CORRECT (because 10 > 9 as integers)
1056
+ 10.0.0 > 2.0.0 CORRECT (because 10 > 2 as integers)
1057
+
1058
+ Implementation:
1059
+ - Parses version components as INTEGERS (not strings)
1060
+ - Returns tuple (major: int, minor: int, patch: int, prerelease: str)
1061
+ - Python's tuple comparison then works correctly: (1, 10, 0) > (1, 9, 0)
1062
+ - Prerelease versions sort before release: "1.0.0-alpha" < "1.0.0"
1063
+
1064
+ Supported Formats:
1065
+ - Full: "1.2.3", "1.2.3-beta"
1066
+ - Partial: "1" -> (1, 0, 0), "1.2" -> (1, 2, 0)
1067
+ - Prerelease: "1.0.0-alpha", "2.1.0-rc.1"
1068
+
1069
+ Performance:
1070
+ This method uses an LRU cache with configurable size (default: 128)
1071
+ to avoid re-parsing the same version strings repeatedly.
1072
+
1073
+ Args:
1074
+ version: Semantic version string (e.g., "1.2.3" or "1.0.0-beta")
1075
+
1076
+ Returns:
1077
+ Tuple of (major, minor, patch, prerelease) for comparison.
1078
+ Components are INTEGERS (not strings) for correct semantic sorting.
1079
+
1080
+ Raises:
1081
+ ProtocolConfigurationError: If version format is invalid
1082
+ """
1083
+ parser = cls._get_semver_parser()
1084
+ return parser(version)
1085
+
1086
+ @classmethod
1087
+ def _reset_semver_cache(cls) -> None:
1088
+ """Reset semver cache. For testing only.
1089
+
1090
+ Clears the cached semver parser, allowing reconfiguration of cache size.
1091
+ This should only be used in test fixtures to ensure test isolation.
1092
+
1093
+ Thread Safety:
1094
+ This method is thread-safe and uses the class-level lock. The reset
1095
+ operation is atomic - either the cache is fully reset or not at all.
1096
+
1097
+ In-flight Operations:
1098
+ If other threads have already obtained a reference to the cache
1099
+ via _get_semver_parser(), they will continue using the old cache
1100
+ until they complete. This is safe because the old cache remains
1101
+ a valid callable until garbage collected. New operations after
1102
+ reset will get the new cache instance when created.
1103
+
1104
+ Memory Reclamation:
1105
+ The old cache's internal LRU entries are explicitly cleared via
1106
+ cache_clear() before the reference is released. This ensures
1107
+ prompt memory reclamation rather than waiting for garbage
1108
+ collection.
1109
+
1110
+ Concurrent Reset:
1111
+ Multiple concurrent reset calls are safe. Each reset will clear
1112
+ the current cache (if any) and set the reference to None. The
1113
+ lock ensures only one reset executes at a time.
1114
+
1115
+ Example:
1116
+ >>> # In test fixture
1117
+ >>> RegistryCompute._reset_semver_cache()
1118
+ >>> RegistryCompute.SEMVER_CACHE_SIZE = 64
1119
+ >>> # Now cache will be initialized with size 64 on next use
1120
+ """
1121
+ with cls._semver_cache_lock:
1122
+ old_cache = cls._semver_cache
1123
+ if old_cache is not None:
1124
+ # Clear internal LRU cache entries before releasing reference.
1125
+ # This ensures prompt memory reclamation rather than waiting
1126
+ # for garbage collection of the orphaned function object.
1127
+ # NOTE: cache_clear() is added by @lru_cache decorator but not
1128
+ # reflected in Callable type annotation. This is a known mypy
1129
+ # limitation with lru_cache wrappers.
1130
+ old_cache.cache_clear() # type: ignore[attr-defined] # NOTE: lru_cache dynamic method
1131
+ cls._semver_cache = None
1132
+
1133
+
1134
+ # =============================================================================
1135
+ # Module Exports
1136
+ # =============================================================================
1137
+
1138
+ __all__: list[str] = [
1139
+ "ENV_COMPUTE_REGISTRY_CACHE_SIZE", # Environment variable constant
1140
+ "ModelComputeKey", # Re-export for convenience
1141
+ "ModelComputeRegistration", # Re-export for convenience
1142
+ "RegistryCompute", # Registry class
1143
+ ]