omnibase_infra 0.2.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (833) hide show
  1. omnibase_infra/__init__.py +101 -0
  2. omnibase_infra/adapters/adapter_onex_tool_execution.py +451 -0
  3. omnibase_infra/capabilities/__init__.py +15 -0
  4. omnibase_infra/capabilities/capability_inference_rules.py +211 -0
  5. omnibase_infra/capabilities/contract_capability_extractor.py +221 -0
  6. omnibase_infra/capabilities/intent_type_extractor.py +160 -0
  7. omnibase_infra/cli/__init__.py +1 -0
  8. omnibase_infra/cli/commands.py +216 -0
  9. omnibase_infra/clients/__init__.py +0 -0
  10. omnibase_infra/configs/widget_mapping.yaml +176 -0
  11. omnibase_infra/constants_topic_patterns.py +26 -0
  12. omnibase_infra/contracts/handlers/filesystem/handler_contract.yaml +264 -0
  13. omnibase_infra/contracts/handlers/mcp/handler_contract.yaml +141 -0
  14. omnibase_infra/decorators/__init__.py +29 -0
  15. omnibase_infra/decorators/allow_any.py +109 -0
  16. omnibase_infra/dlq/__init__.py +90 -0
  17. omnibase_infra/dlq/constants_dlq.py +57 -0
  18. omnibase_infra/dlq/models/__init__.py +26 -0
  19. omnibase_infra/dlq/models/enum_replay_status.py +37 -0
  20. omnibase_infra/dlq/models/model_dlq_replay_record.py +135 -0
  21. omnibase_infra/dlq/models/model_dlq_tracking_config.py +184 -0
  22. omnibase_infra/dlq/service_dlq_tracking.py +611 -0
  23. omnibase_infra/enums/__init__.py +132 -0
  24. omnibase_infra/enums/enum_any_type_violation.py +104 -0
  25. omnibase_infra/enums/enum_backend_type.py +27 -0
  26. omnibase_infra/enums/enum_capture_outcome.py +42 -0
  27. omnibase_infra/enums/enum_capture_state.py +88 -0
  28. omnibase_infra/enums/enum_chain_violation_type.py +119 -0
  29. omnibase_infra/enums/enum_circuit_state.py +51 -0
  30. omnibase_infra/enums/enum_confirmation_event_type.py +27 -0
  31. omnibase_infra/enums/enum_consumer_group_purpose.py +92 -0
  32. omnibase_infra/enums/enum_contract_type.py +84 -0
  33. omnibase_infra/enums/enum_dedupe_strategy.py +46 -0
  34. omnibase_infra/enums/enum_dispatch_status.py +191 -0
  35. omnibase_infra/enums/enum_environment.py +46 -0
  36. omnibase_infra/enums/enum_execution_shape_violation.py +103 -0
  37. omnibase_infra/enums/enum_handler_error_type.py +111 -0
  38. omnibase_infra/enums/enum_handler_loader_error.py +178 -0
  39. omnibase_infra/enums/enum_handler_source_mode.py +86 -0
  40. omnibase_infra/enums/enum_handler_source_type.py +87 -0
  41. omnibase_infra/enums/enum_handler_type.py +77 -0
  42. omnibase_infra/enums/enum_handler_type_category.py +61 -0
  43. omnibase_infra/enums/enum_infra_transport_type.py +73 -0
  44. omnibase_infra/enums/enum_introspection_reason.py +154 -0
  45. omnibase_infra/enums/enum_kafka_acks.py +99 -0
  46. omnibase_infra/enums/enum_message_category.py +213 -0
  47. omnibase_infra/enums/enum_node_archetype.py +74 -0
  48. omnibase_infra/enums/enum_node_output_type.py +185 -0
  49. omnibase_infra/enums/enum_non_retryable_error_category.py +224 -0
  50. omnibase_infra/enums/enum_policy_type.py +32 -0
  51. omnibase_infra/enums/enum_registration_state.py +261 -0
  52. omnibase_infra/enums/enum_registration_status.py +33 -0
  53. omnibase_infra/enums/enum_registry_response_status.py +28 -0
  54. omnibase_infra/enums/enum_response_status.py +26 -0
  55. omnibase_infra/enums/enum_retry_error_category.py +98 -0
  56. omnibase_infra/enums/enum_security_rule_id.py +103 -0
  57. omnibase_infra/enums/enum_selection_strategy.py +91 -0
  58. omnibase_infra/enums/enum_topic_standard.py +42 -0
  59. omnibase_infra/enums/enum_validation_severity.py +78 -0
  60. omnibase_infra/errors/__init__.py +160 -0
  61. omnibase_infra/errors/error_architecture_violation.py +152 -0
  62. omnibase_infra/errors/error_binding_resolution.py +128 -0
  63. omnibase_infra/errors/error_chain_propagation.py +188 -0
  64. omnibase_infra/errors/error_compute_registry.py +95 -0
  65. omnibase_infra/errors/error_consul.py +132 -0
  66. omnibase_infra/errors/error_container_wiring.py +243 -0
  67. omnibase_infra/errors/error_event_bus_registry.py +105 -0
  68. omnibase_infra/errors/error_infra.py +610 -0
  69. omnibase_infra/errors/error_message_type_registry.py +101 -0
  70. omnibase_infra/errors/error_policy_registry.py +115 -0
  71. omnibase_infra/errors/error_vault.py +123 -0
  72. omnibase_infra/event_bus/__init__.py +72 -0
  73. omnibase_infra/event_bus/configs/kafka_event_bus_config.yaml +84 -0
  74. omnibase_infra/event_bus/event_bus_inmemory.py +797 -0
  75. omnibase_infra/event_bus/event_bus_kafka.py +1716 -0
  76. omnibase_infra/event_bus/mixin_kafka_broadcast.py +180 -0
  77. omnibase_infra/event_bus/mixin_kafka_dlq.py +771 -0
  78. omnibase_infra/event_bus/models/__init__.py +29 -0
  79. omnibase_infra/event_bus/models/config/__init__.py +20 -0
  80. omnibase_infra/event_bus/models/config/model_kafka_event_bus_config.py +693 -0
  81. omnibase_infra/event_bus/models/model_dlq_event.py +206 -0
  82. omnibase_infra/event_bus/models/model_dlq_metrics.py +304 -0
  83. omnibase_infra/event_bus/models/model_event_headers.py +115 -0
  84. omnibase_infra/event_bus/models/model_event_message.py +60 -0
  85. omnibase_infra/event_bus/testing/__init__.py +26 -0
  86. omnibase_infra/event_bus/testing/adapter_protocol_event_publisher_inmemory.py +418 -0
  87. omnibase_infra/event_bus/testing/model_publisher_metrics.py +64 -0
  88. omnibase_infra/event_bus/topic_constants.py +376 -0
  89. omnibase_infra/handlers/__init__.py +82 -0
  90. omnibase_infra/handlers/filesystem/__init__.py +48 -0
  91. omnibase_infra/handlers/filesystem/enum_file_system_operation.py +35 -0
  92. omnibase_infra/handlers/filesystem/model_file_system_request.py +298 -0
  93. omnibase_infra/handlers/filesystem/model_file_system_result.py +166 -0
  94. omnibase_infra/handlers/handler_consul.py +795 -0
  95. omnibase_infra/handlers/handler_db.py +1046 -0
  96. omnibase_infra/handlers/handler_filesystem.py +1478 -0
  97. omnibase_infra/handlers/handler_graph.py +2015 -0
  98. omnibase_infra/handlers/handler_http.py +926 -0
  99. omnibase_infra/handlers/handler_intent.py +387 -0
  100. omnibase_infra/handlers/handler_manifest_persistence.contract.yaml +184 -0
  101. omnibase_infra/handlers/handler_manifest_persistence.py +1539 -0
  102. omnibase_infra/handlers/handler_mcp.py +1430 -0
  103. omnibase_infra/handlers/handler_qdrant.py +1076 -0
  104. omnibase_infra/handlers/handler_vault.py +428 -0
  105. omnibase_infra/handlers/mcp/__init__.py +19 -0
  106. omnibase_infra/handlers/mcp/adapter_onex_to_mcp.py +446 -0
  107. omnibase_infra/handlers/mcp/protocols.py +178 -0
  108. omnibase_infra/handlers/mcp/transport_streamable_http.py +352 -0
  109. omnibase_infra/handlers/mixins/__init__.py +47 -0
  110. omnibase_infra/handlers/mixins/mixin_consul_initialization.py +349 -0
  111. omnibase_infra/handlers/mixins/mixin_consul_kv.py +338 -0
  112. omnibase_infra/handlers/mixins/mixin_consul_service.py +542 -0
  113. omnibase_infra/handlers/mixins/mixin_consul_topic_index.py +585 -0
  114. omnibase_infra/handlers/mixins/mixin_vault_initialization.py +338 -0
  115. omnibase_infra/handlers/mixins/mixin_vault_retry.py +412 -0
  116. omnibase_infra/handlers/mixins/mixin_vault_secrets.py +450 -0
  117. omnibase_infra/handlers/mixins/mixin_vault_token.py +365 -0
  118. omnibase_infra/handlers/models/__init__.py +286 -0
  119. omnibase_infra/handlers/models/consul/__init__.py +81 -0
  120. omnibase_infra/handlers/models/consul/enum_consul_operation_type.py +57 -0
  121. omnibase_infra/handlers/models/consul/model_consul_deregister_payload.py +51 -0
  122. omnibase_infra/handlers/models/consul/model_consul_handler_config.py +153 -0
  123. omnibase_infra/handlers/models/consul/model_consul_handler_payload.py +89 -0
  124. omnibase_infra/handlers/models/consul/model_consul_kv_get_found_payload.py +55 -0
  125. omnibase_infra/handlers/models/consul/model_consul_kv_get_not_found_payload.py +49 -0
  126. omnibase_infra/handlers/models/consul/model_consul_kv_get_recurse_payload.py +50 -0
  127. omnibase_infra/handlers/models/consul/model_consul_kv_item.py +33 -0
  128. omnibase_infra/handlers/models/consul/model_consul_kv_put_payload.py +41 -0
  129. omnibase_infra/handlers/models/consul/model_consul_register_payload.py +53 -0
  130. omnibase_infra/handlers/models/consul/model_consul_retry_config.py +66 -0
  131. omnibase_infra/handlers/models/consul/model_payload_consul.py +66 -0
  132. omnibase_infra/handlers/models/consul/registry_payload_consul.py +214 -0
  133. omnibase_infra/handlers/models/graph/__init__.py +35 -0
  134. omnibase_infra/handlers/models/graph/enum_graph_operation_type.py +20 -0
  135. omnibase_infra/handlers/models/graph/model_graph_execute_payload.py +38 -0
  136. omnibase_infra/handlers/models/graph/model_graph_handler_config.py +54 -0
  137. omnibase_infra/handlers/models/graph/model_graph_handler_payload.py +44 -0
  138. omnibase_infra/handlers/models/graph/model_graph_query_payload.py +40 -0
  139. omnibase_infra/handlers/models/graph/model_graph_record.py +22 -0
  140. omnibase_infra/handlers/models/http/__init__.py +50 -0
  141. omnibase_infra/handlers/models/http/enum_http_operation_type.py +29 -0
  142. omnibase_infra/handlers/models/http/model_http_body_content.py +45 -0
  143. omnibase_infra/handlers/models/http/model_http_get_payload.py +88 -0
  144. omnibase_infra/handlers/models/http/model_http_handler_payload.py +90 -0
  145. omnibase_infra/handlers/models/http/model_http_post_payload.py +88 -0
  146. omnibase_infra/handlers/models/http/model_payload_http.py +66 -0
  147. omnibase_infra/handlers/models/http/registry_payload_http.py +212 -0
  148. omnibase_infra/handlers/models/mcp/__init__.py +23 -0
  149. omnibase_infra/handlers/models/mcp/enum_mcp_operation_type.py +24 -0
  150. omnibase_infra/handlers/models/mcp/model_mcp_handler_config.py +40 -0
  151. omnibase_infra/handlers/models/mcp/model_mcp_tool_call.py +32 -0
  152. omnibase_infra/handlers/models/mcp/model_mcp_tool_result.py +45 -0
  153. omnibase_infra/handlers/models/model_consul_handler_response.py +96 -0
  154. omnibase_infra/handlers/models/model_db_describe_response.py +83 -0
  155. omnibase_infra/handlers/models/model_db_query_payload.py +95 -0
  156. omnibase_infra/handlers/models/model_db_query_response.py +60 -0
  157. omnibase_infra/handlers/models/model_filesystem_config.py +98 -0
  158. omnibase_infra/handlers/models/model_filesystem_delete_payload.py +54 -0
  159. omnibase_infra/handlers/models/model_filesystem_delete_result.py +77 -0
  160. omnibase_infra/handlers/models/model_filesystem_directory_entry.py +75 -0
  161. omnibase_infra/handlers/models/model_filesystem_ensure_directory_payload.py +54 -0
  162. omnibase_infra/handlers/models/model_filesystem_ensure_directory_result.py +60 -0
  163. omnibase_infra/handlers/models/model_filesystem_list_directory_payload.py +60 -0
  164. omnibase_infra/handlers/models/model_filesystem_list_directory_result.py +68 -0
  165. omnibase_infra/handlers/models/model_filesystem_read_payload.py +62 -0
  166. omnibase_infra/handlers/models/model_filesystem_read_result.py +61 -0
  167. omnibase_infra/handlers/models/model_filesystem_write_payload.py +70 -0
  168. omnibase_infra/handlers/models/model_filesystem_write_result.py +55 -0
  169. omnibase_infra/handlers/models/model_graph_handler_response.py +98 -0
  170. omnibase_infra/handlers/models/model_handler_response.py +103 -0
  171. omnibase_infra/handlers/models/model_http_handler_response.py +101 -0
  172. omnibase_infra/handlers/models/model_manifest_metadata.py +75 -0
  173. omnibase_infra/handlers/models/model_manifest_persistence_config.py +62 -0
  174. omnibase_infra/handlers/models/model_manifest_query_payload.py +90 -0
  175. omnibase_infra/handlers/models/model_manifest_query_result.py +97 -0
  176. omnibase_infra/handlers/models/model_manifest_retrieve_payload.py +44 -0
  177. omnibase_infra/handlers/models/model_manifest_retrieve_result.py +98 -0
  178. omnibase_infra/handlers/models/model_manifest_store_payload.py +47 -0
  179. omnibase_infra/handlers/models/model_manifest_store_result.py +67 -0
  180. omnibase_infra/handlers/models/model_operation_context.py +187 -0
  181. omnibase_infra/handlers/models/model_qdrant_handler_response.py +98 -0
  182. omnibase_infra/handlers/models/model_retry_state.py +162 -0
  183. omnibase_infra/handlers/models/model_vault_handler_response.py +98 -0
  184. omnibase_infra/handlers/models/qdrant/__init__.py +44 -0
  185. omnibase_infra/handlers/models/qdrant/enum_qdrant_operation_type.py +26 -0
  186. omnibase_infra/handlers/models/qdrant/model_qdrant_collection_payload.py +42 -0
  187. omnibase_infra/handlers/models/qdrant/model_qdrant_delete_payload.py +36 -0
  188. omnibase_infra/handlers/models/qdrant/model_qdrant_handler_config.py +42 -0
  189. omnibase_infra/handlers/models/qdrant/model_qdrant_handler_payload.py +54 -0
  190. omnibase_infra/handlers/models/qdrant/model_qdrant_search_payload.py +42 -0
  191. omnibase_infra/handlers/models/qdrant/model_qdrant_search_result.py +30 -0
  192. omnibase_infra/handlers/models/qdrant/model_qdrant_upsert_payload.py +36 -0
  193. omnibase_infra/handlers/models/vault/__init__.py +69 -0
  194. omnibase_infra/handlers/models/vault/enum_vault_operation_type.py +35 -0
  195. omnibase_infra/handlers/models/vault/model_payload_vault.py +66 -0
  196. omnibase_infra/handlers/models/vault/model_vault_delete_payload.py +57 -0
  197. omnibase_infra/handlers/models/vault/model_vault_handler_config.py +148 -0
  198. omnibase_infra/handlers/models/vault/model_vault_handler_payload.py +101 -0
  199. omnibase_infra/handlers/models/vault/model_vault_list_payload.py +58 -0
  200. omnibase_infra/handlers/models/vault/model_vault_renew_token_payload.py +67 -0
  201. omnibase_infra/handlers/models/vault/model_vault_retry_config.py +66 -0
  202. omnibase_infra/handlers/models/vault/model_vault_secret_payload.py +106 -0
  203. omnibase_infra/handlers/models/vault/model_vault_write_payload.py +66 -0
  204. omnibase_infra/handlers/models/vault/registry_payload_vault.py +213 -0
  205. omnibase_infra/handlers/registration_storage/__init__.py +43 -0
  206. omnibase_infra/handlers/registration_storage/handler_registration_storage_mock.py +392 -0
  207. omnibase_infra/handlers/registration_storage/handler_registration_storage_postgres.py +922 -0
  208. omnibase_infra/handlers/registration_storage/models/__init__.py +23 -0
  209. omnibase_infra/handlers/registration_storage/models/model_delete_registration_request.py +58 -0
  210. omnibase_infra/handlers/registration_storage/models/model_update_registration_request.py +73 -0
  211. omnibase_infra/handlers/registration_storage/protocol_registration_persistence.py +191 -0
  212. omnibase_infra/handlers/service_discovery/__init__.py +43 -0
  213. omnibase_infra/handlers/service_discovery/handler_service_discovery_consul.py +1051 -0
  214. omnibase_infra/handlers/service_discovery/handler_service_discovery_mock.py +258 -0
  215. omnibase_infra/handlers/service_discovery/models/__init__.py +22 -0
  216. omnibase_infra/handlers/service_discovery/models/model_discovery_result.py +64 -0
  217. omnibase_infra/handlers/service_discovery/models/model_registration_result.py +138 -0
  218. omnibase_infra/handlers/service_discovery/models/model_service_info.py +109 -0
  219. omnibase_infra/handlers/service_discovery/protocol_discovery_operations.py +170 -0
  220. omnibase_infra/idempotency/__init__.py +94 -0
  221. omnibase_infra/idempotency/models/__init__.py +43 -0
  222. omnibase_infra/idempotency/models/model_idempotency_check_result.py +85 -0
  223. omnibase_infra/idempotency/models/model_idempotency_guard_config.py +130 -0
  224. omnibase_infra/idempotency/models/model_idempotency_record.py +86 -0
  225. omnibase_infra/idempotency/models/model_idempotency_store_health_check_result.py +81 -0
  226. omnibase_infra/idempotency/models/model_idempotency_store_metrics.py +140 -0
  227. omnibase_infra/idempotency/models/model_postgres_idempotency_store_config.py +299 -0
  228. omnibase_infra/idempotency/protocol_idempotency_store.py +184 -0
  229. omnibase_infra/idempotency/store_inmemory.py +265 -0
  230. omnibase_infra/idempotency/store_postgres.py +923 -0
  231. omnibase_infra/infrastructure/__init__.py +0 -0
  232. omnibase_infra/migrations/001_create_event_ledger.sql +166 -0
  233. omnibase_infra/migrations/001_drop_event_ledger.sql +18 -0
  234. omnibase_infra/mixins/__init__.py +71 -0
  235. omnibase_infra/mixins/mixin_async_circuit_breaker.py +656 -0
  236. omnibase_infra/mixins/mixin_dict_like_accessors.py +146 -0
  237. omnibase_infra/mixins/mixin_envelope_extraction.py +119 -0
  238. omnibase_infra/mixins/mixin_node_introspection.py +2670 -0
  239. omnibase_infra/mixins/mixin_retry_execution.py +386 -0
  240. omnibase_infra/mixins/protocol_circuit_breaker_aware.py +133 -0
  241. omnibase_infra/models/__init__.py +144 -0
  242. omnibase_infra/models/bindings/__init__.py +59 -0
  243. omnibase_infra/models/bindings/constants.py +144 -0
  244. omnibase_infra/models/bindings/model_binding_resolution_result.py +103 -0
  245. omnibase_infra/models/bindings/model_operation_binding.py +44 -0
  246. omnibase_infra/models/bindings/model_operation_bindings_subcontract.py +152 -0
  247. omnibase_infra/models/bindings/model_parsed_binding.py +52 -0
  248. omnibase_infra/models/corpus/__init__.py +17 -0
  249. omnibase_infra/models/corpus/model_capture_config.py +133 -0
  250. omnibase_infra/models/corpus/model_capture_result.py +86 -0
  251. omnibase_infra/models/discovery/__init__.py +42 -0
  252. omnibase_infra/models/discovery/model_dependency_spec.py +319 -0
  253. omnibase_infra/models/discovery/model_discovered_capabilities.py +50 -0
  254. omnibase_infra/models/discovery/model_introspection_config.py +330 -0
  255. omnibase_infra/models/discovery/model_introspection_performance_metrics.py +169 -0
  256. omnibase_infra/models/discovery/model_introspection_task_config.py +116 -0
  257. omnibase_infra/models/dispatch/__init__.py +155 -0
  258. omnibase_infra/models/dispatch/model_debug_trace_snapshot.py +114 -0
  259. omnibase_infra/models/dispatch/model_dispatch_context.py +439 -0
  260. omnibase_infra/models/dispatch/model_dispatch_error.py +336 -0
  261. omnibase_infra/models/dispatch/model_dispatch_log_context.py +400 -0
  262. omnibase_infra/models/dispatch/model_dispatch_metadata.py +228 -0
  263. omnibase_infra/models/dispatch/model_dispatch_metrics.py +496 -0
  264. omnibase_infra/models/dispatch/model_dispatch_outcome.py +317 -0
  265. omnibase_infra/models/dispatch/model_dispatch_outputs.py +231 -0
  266. omnibase_infra/models/dispatch/model_dispatch_result.py +436 -0
  267. omnibase_infra/models/dispatch/model_dispatch_route.py +279 -0
  268. omnibase_infra/models/dispatch/model_dispatcher_metrics.py +275 -0
  269. omnibase_infra/models/dispatch/model_dispatcher_registration.py +352 -0
  270. omnibase_infra/models/dispatch/model_materialized_dispatch.py +141 -0
  271. omnibase_infra/models/dispatch/model_parsed_topic.py +135 -0
  272. omnibase_infra/models/dispatch/model_topic_parser.py +725 -0
  273. omnibase_infra/models/dispatch/model_tracing_context.py +285 -0
  274. omnibase_infra/models/errors/__init__.py +45 -0
  275. omnibase_infra/models/errors/model_handler_validation_error.py +594 -0
  276. omnibase_infra/models/errors/model_infra_error_context.py +99 -0
  277. omnibase_infra/models/errors/model_message_type_registry_error_context.py +71 -0
  278. omnibase_infra/models/errors/model_timeout_error_context.py +110 -0
  279. omnibase_infra/models/handlers/__init__.py +80 -0
  280. omnibase_infra/models/handlers/model_bootstrap_handler_descriptor.py +162 -0
  281. omnibase_infra/models/handlers/model_contract_discovery_result.py +82 -0
  282. omnibase_infra/models/handlers/model_handler_descriptor.py +200 -0
  283. omnibase_infra/models/handlers/model_handler_identifier.py +215 -0
  284. omnibase_infra/models/handlers/model_handler_source_config.py +220 -0
  285. omnibase_infra/models/health/__init__.py +9 -0
  286. omnibase_infra/models/health/model_health_check_result.py +40 -0
  287. omnibase_infra/models/lifecycle/__init__.py +39 -0
  288. omnibase_infra/models/logging/__init__.py +51 -0
  289. omnibase_infra/models/logging/model_log_context.py +756 -0
  290. omnibase_infra/models/mcp/__init__.py +15 -0
  291. omnibase_infra/models/mcp/model_mcp_contract_config.py +80 -0
  292. omnibase_infra/models/mcp/model_mcp_server_config.py +67 -0
  293. omnibase_infra/models/mcp/model_mcp_tool_definition.py +73 -0
  294. omnibase_infra/models/mcp/model_mcp_tool_parameter.py +35 -0
  295. omnibase_infra/models/model_node_identity.py +126 -0
  296. omnibase_infra/models/model_retry_error_classification.py +78 -0
  297. omnibase_infra/models/projection/__init__.py +43 -0
  298. omnibase_infra/models/projection/model_capability_fields.py +112 -0
  299. omnibase_infra/models/projection/model_registration_projection.py +434 -0
  300. omnibase_infra/models/projection/model_registration_snapshot.py +322 -0
  301. omnibase_infra/models/projection/model_sequence_info.py +182 -0
  302. omnibase_infra/models/projection/model_snapshot_topic_config.py +591 -0
  303. omnibase_infra/models/projectors/__init__.py +41 -0
  304. omnibase_infra/models/projectors/model_projector_column.py +289 -0
  305. omnibase_infra/models/projectors/model_projector_discovery_result.py +65 -0
  306. omnibase_infra/models/projectors/model_projector_index.py +270 -0
  307. omnibase_infra/models/projectors/model_projector_schema.py +415 -0
  308. omnibase_infra/models/projectors/model_projector_validation_error.py +63 -0
  309. omnibase_infra/models/projectors/util_sql_identifiers.py +115 -0
  310. omnibase_infra/models/registration/__init__.py +68 -0
  311. omnibase_infra/models/registration/commands/__init__.py +15 -0
  312. omnibase_infra/models/registration/commands/model_node_registration_acked.py +108 -0
  313. omnibase_infra/models/registration/events/__init__.py +56 -0
  314. omnibase_infra/models/registration/events/model_node_became_active.py +103 -0
  315. omnibase_infra/models/registration/events/model_node_liveness_expired.py +103 -0
  316. omnibase_infra/models/registration/events/model_node_registration_accepted.py +98 -0
  317. omnibase_infra/models/registration/events/model_node_registration_ack_received.py +98 -0
  318. omnibase_infra/models/registration/events/model_node_registration_ack_timed_out.py +112 -0
  319. omnibase_infra/models/registration/events/model_node_registration_initiated.py +107 -0
  320. omnibase_infra/models/registration/events/model_node_registration_rejected.py +104 -0
  321. omnibase_infra/models/registration/model_event_bus_topic_entry.py +59 -0
  322. omnibase_infra/models/registration/model_introspection_metrics.py +253 -0
  323. omnibase_infra/models/registration/model_node_capabilities.py +190 -0
  324. omnibase_infra/models/registration/model_node_event_bus_config.py +99 -0
  325. omnibase_infra/models/registration/model_node_heartbeat_event.py +126 -0
  326. omnibase_infra/models/registration/model_node_introspection_event.py +195 -0
  327. omnibase_infra/models/registration/model_node_metadata.py +79 -0
  328. omnibase_infra/models/registration/model_node_registration.py +162 -0
  329. omnibase_infra/models/registration/model_node_registration_record.py +162 -0
  330. omnibase_infra/models/registry/__init__.py +29 -0
  331. omnibase_infra/models/registry/model_domain_constraint.py +202 -0
  332. omnibase_infra/models/registry/model_message_type_entry.py +271 -0
  333. omnibase_infra/models/resilience/__init__.py +9 -0
  334. omnibase_infra/models/resilience/model_circuit_breaker_config.py +227 -0
  335. omnibase_infra/models/routing/__init__.py +25 -0
  336. omnibase_infra/models/routing/model_routing_entry.py +52 -0
  337. omnibase_infra/models/routing/model_routing_subcontract.py +70 -0
  338. omnibase_infra/models/runtime/__init__.py +49 -0
  339. omnibase_infra/models/runtime/model_contract_security_config.py +41 -0
  340. omnibase_infra/models/runtime/model_discovery_error.py +81 -0
  341. omnibase_infra/models/runtime/model_discovery_result.py +162 -0
  342. omnibase_infra/models/runtime/model_discovery_warning.py +74 -0
  343. omnibase_infra/models/runtime/model_failed_plugin_load.py +63 -0
  344. omnibase_infra/models/runtime/model_handler_contract.py +296 -0
  345. omnibase_infra/models/runtime/model_loaded_handler.py +129 -0
  346. omnibase_infra/models/runtime/model_plugin_load_context.py +93 -0
  347. omnibase_infra/models/runtime/model_plugin_load_summary.py +124 -0
  348. omnibase_infra/models/security/__init__.py +50 -0
  349. omnibase_infra/models/security/classification_levels.py +99 -0
  350. omnibase_infra/models/security/model_environment_policy.py +145 -0
  351. omnibase_infra/models/security/model_handler_security_policy.py +107 -0
  352. omnibase_infra/models/security/model_security_error.py +81 -0
  353. omnibase_infra/models/security/model_security_validation_result.py +328 -0
  354. omnibase_infra/models/security/model_security_warning.py +67 -0
  355. omnibase_infra/models/snapshot/__init__.py +27 -0
  356. omnibase_infra/models/snapshot/model_field_change.py +65 -0
  357. omnibase_infra/models/snapshot/model_snapshot.py +270 -0
  358. omnibase_infra/models/snapshot/model_snapshot_diff.py +203 -0
  359. omnibase_infra/models/snapshot/model_subject_ref.py +81 -0
  360. omnibase_infra/models/types/__init__.py +71 -0
  361. omnibase_infra/models/validation/__init__.py +89 -0
  362. omnibase_infra/models/validation/model_any_type_validation_result.py +118 -0
  363. omnibase_infra/models/validation/model_any_type_violation.py +141 -0
  364. omnibase_infra/models/validation/model_category_match_result.py +345 -0
  365. omnibase_infra/models/validation/model_chain_violation.py +166 -0
  366. omnibase_infra/models/validation/model_coverage_metrics.py +316 -0
  367. omnibase_infra/models/validation/model_execution_shape_rule.py +159 -0
  368. omnibase_infra/models/validation/model_execution_shape_validation.py +208 -0
  369. omnibase_infra/models/validation/model_execution_shape_validation_result.py +294 -0
  370. omnibase_infra/models/validation/model_execution_shape_violation.py +122 -0
  371. omnibase_infra/models/validation/model_localhandler_validation_result.py +139 -0
  372. omnibase_infra/models/validation/model_localhandler_violation.py +100 -0
  373. omnibase_infra/models/validation/model_output_validation_params.py +74 -0
  374. omnibase_infra/models/validation/model_validate_and_raise_params.py +84 -0
  375. omnibase_infra/models/validation/model_validation_error_params.py +84 -0
  376. omnibase_infra/models/validation/model_validation_outcome.py +287 -0
  377. omnibase_infra/nodes/__init__.py +57 -0
  378. omnibase_infra/nodes/architecture_validator/__init__.py +79 -0
  379. omnibase_infra/nodes/architecture_validator/contract.yaml +252 -0
  380. omnibase_infra/nodes/architecture_validator/contract_architecture_validator.yaml +203 -0
  381. omnibase_infra/nodes/architecture_validator/mixins/__init__.py +16 -0
  382. omnibase_infra/nodes/architecture_validator/mixins/mixin_file_path_rule.py +92 -0
  383. omnibase_infra/nodes/architecture_validator/models/__init__.py +36 -0
  384. omnibase_infra/nodes/architecture_validator/models/model_architecture_validation_request.py +56 -0
  385. omnibase_infra/nodes/architecture_validator/models/model_architecture_validation_result.py +311 -0
  386. omnibase_infra/nodes/architecture_validator/models/model_architecture_violation.py +163 -0
  387. omnibase_infra/nodes/architecture_validator/models/model_rule_check_result.py +265 -0
  388. omnibase_infra/nodes/architecture_validator/models/model_validation_request.py +105 -0
  389. omnibase_infra/nodes/architecture_validator/models/model_validation_result.py +314 -0
  390. omnibase_infra/nodes/architecture_validator/node.py +262 -0
  391. omnibase_infra/nodes/architecture_validator/node_architecture_validator.py +383 -0
  392. omnibase_infra/nodes/architecture_validator/protocols/__init__.py +9 -0
  393. omnibase_infra/nodes/architecture_validator/protocols/protocol_architecture_rule.py +225 -0
  394. omnibase_infra/nodes/architecture_validator/registry/__init__.py +28 -0
  395. omnibase_infra/nodes/architecture_validator/registry/registry_infra_architecture_validator.py +106 -0
  396. omnibase_infra/nodes/architecture_validator/validators/__init__.py +104 -0
  397. omnibase_infra/nodes/architecture_validator/validators/validator_no_direct_dispatch.py +422 -0
  398. omnibase_infra/nodes/architecture_validator/validators/validator_no_handler_publishing.py +481 -0
  399. omnibase_infra/nodes/architecture_validator/validators/validator_no_orchestrator_fsm.py +491 -0
  400. omnibase_infra/nodes/contract_registry_reducer/__init__.py +29 -0
  401. omnibase_infra/nodes/contract_registry_reducer/contract.yaml +255 -0
  402. omnibase_infra/nodes/contract_registry_reducer/models/__init__.py +38 -0
  403. omnibase_infra/nodes/contract_registry_reducer/models/model_contract_registry_state.py +266 -0
  404. omnibase_infra/nodes/contract_registry_reducer/models/model_payload_cleanup_topic_references.py +55 -0
  405. omnibase_infra/nodes/contract_registry_reducer/models/model_payload_deactivate_contract.py +58 -0
  406. omnibase_infra/nodes/contract_registry_reducer/models/model_payload_mark_stale.py +49 -0
  407. omnibase_infra/nodes/contract_registry_reducer/models/model_payload_update_heartbeat.py +71 -0
  408. omnibase_infra/nodes/contract_registry_reducer/models/model_payload_update_topic.py +66 -0
  409. omnibase_infra/nodes/contract_registry_reducer/models/model_payload_upsert_contract.py +92 -0
  410. omnibase_infra/nodes/contract_registry_reducer/node.py +121 -0
  411. omnibase_infra/nodes/contract_registry_reducer/reducer.py +784 -0
  412. omnibase_infra/nodes/contract_registry_reducer/registry/__init__.py +9 -0
  413. omnibase_infra/nodes/contract_registry_reducer/registry/registry_infra_contract_registry_reducer.py +101 -0
  414. omnibase_infra/nodes/effects/README.md +358 -0
  415. omnibase_infra/nodes/effects/__init__.py +26 -0
  416. omnibase_infra/nodes/effects/contract.yaml +167 -0
  417. omnibase_infra/nodes/effects/models/__init__.py +32 -0
  418. omnibase_infra/nodes/effects/models/model_backend_result.py +190 -0
  419. omnibase_infra/nodes/effects/models/model_effect_idempotency_config.py +92 -0
  420. omnibase_infra/nodes/effects/models/model_registry_request.py +132 -0
  421. omnibase_infra/nodes/effects/models/model_registry_response.py +263 -0
  422. omnibase_infra/nodes/effects/protocol_consul_client.py +89 -0
  423. omnibase_infra/nodes/effects/protocol_effect_idempotency_store.py +143 -0
  424. omnibase_infra/nodes/effects/protocol_postgres_adapter.py +96 -0
  425. omnibase_infra/nodes/effects/registry_effect.py +525 -0
  426. omnibase_infra/nodes/effects/store_effect_idempotency_inmemory.py +425 -0
  427. omnibase_infra/nodes/handlers/consul/contract.yaml +85 -0
  428. omnibase_infra/nodes/handlers/db/contract.yaml +72 -0
  429. omnibase_infra/nodes/handlers/graph/contract.yaml +127 -0
  430. omnibase_infra/nodes/handlers/http/contract.yaml +74 -0
  431. omnibase_infra/nodes/handlers/intent/contract.yaml +66 -0
  432. omnibase_infra/nodes/handlers/mcp/contract.yaml +69 -0
  433. omnibase_infra/nodes/handlers/vault/contract.yaml +91 -0
  434. omnibase_infra/nodes/node_intent_storage_effect/__init__.py +50 -0
  435. omnibase_infra/nodes/node_intent_storage_effect/contract.yaml +194 -0
  436. omnibase_infra/nodes/node_intent_storage_effect/models/__init__.py +24 -0
  437. omnibase_infra/nodes/node_intent_storage_effect/models/model_intent_storage_input.py +141 -0
  438. omnibase_infra/nodes/node_intent_storage_effect/models/model_intent_storage_output.py +130 -0
  439. omnibase_infra/nodes/node_intent_storage_effect/node.py +94 -0
  440. omnibase_infra/nodes/node_intent_storage_effect/registry/__init__.py +35 -0
  441. omnibase_infra/nodes/node_intent_storage_effect/registry/registry_infra_intent_storage.py +294 -0
  442. omnibase_infra/nodes/node_ledger_projection_compute/__init__.py +50 -0
  443. omnibase_infra/nodes/node_ledger_projection_compute/contract.yaml +104 -0
  444. omnibase_infra/nodes/node_ledger_projection_compute/node.py +284 -0
  445. omnibase_infra/nodes/node_ledger_projection_compute/registry/__init__.py +29 -0
  446. omnibase_infra/nodes/node_ledger_projection_compute/registry/registry_infra_ledger_projection.py +118 -0
  447. omnibase_infra/nodes/node_ledger_write_effect/__init__.py +82 -0
  448. omnibase_infra/nodes/node_ledger_write_effect/contract.yaml +200 -0
  449. omnibase_infra/nodes/node_ledger_write_effect/handlers/__init__.py +22 -0
  450. omnibase_infra/nodes/node_ledger_write_effect/handlers/handler_ledger_append.py +372 -0
  451. omnibase_infra/nodes/node_ledger_write_effect/handlers/handler_ledger_query.py +597 -0
  452. omnibase_infra/nodes/node_ledger_write_effect/models/__init__.py +31 -0
  453. omnibase_infra/nodes/node_ledger_write_effect/models/model_ledger_append_result.py +54 -0
  454. omnibase_infra/nodes/node_ledger_write_effect/models/model_ledger_entry.py +92 -0
  455. omnibase_infra/nodes/node_ledger_write_effect/models/model_ledger_query.py +53 -0
  456. omnibase_infra/nodes/node_ledger_write_effect/models/model_ledger_query_result.py +41 -0
  457. omnibase_infra/nodes/node_ledger_write_effect/node.py +89 -0
  458. omnibase_infra/nodes/node_ledger_write_effect/protocols/__init__.py +13 -0
  459. omnibase_infra/nodes/node_ledger_write_effect/protocols/protocol_ledger_persistence.py +127 -0
  460. omnibase_infra/nodes/node_ledger_write_effect/registry/__init__.py +9 -0
  461. omnibase_infra/nodes/node_ledger_write_effect/registry/registry_infra_ledger_write.py +121 -0
  462. omnibase_infra/nodes/node_registration_orchestrator/README.md +542 -0
  463. omnibase_infra/nodes/node_registration_orchestrator/__init__.py +120 -0
  464. omnibase_infra/nodes/node_registration_orchestrator/contract.yaml +482 -0
  465. omnibase_infra/nodes/node_registration_orchestrator/dispatchers/__init__.py +53 -0
  466. omnibase_infra/nodes/node_registration_orchestrator/dispatchers/dispatcher_node_introspected.py +376 -0
  467. omnibase_infra/nodes/node_registration_orchestrator/dispatchers/dispatcher_node_registration_acked.py +376 -0
  468. omnibase_infra/nodes/node_registration_orchestrator/dispatchers/dispatcher_runtime_tick.py +373 -0
  469. omnibase_infra/nodes/node_registration_orchestrator/handlers/__init__.py +62 -0
  470. omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_heartbeat.py +376 -0
  471. omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_introspected.py +694 -0
  472. omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_registration_acked.py +458 -0
  473. omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_runtime_tick.py +364 -0
  474. omnibase_infra/nodes/node_registration_orchestrator/introspection_event_router.py +544 -0
  475. omnibase_infra/nodes/node_registration_orchestrator/models/__init__.py +75 -0
  476. omnibase_infra/nodes/node_registration_orchestrator/models/model_consul_intent_payload.py +194 -0
  477. omnibase_infra/nodes/node_registration_orchestrator/models/model_consul_registration_intent.py +67 -0
  478. omnibase_infra/nodes/node_registration_orchestrator/models/model_intent_execution_result.py +50 -0
  479. omnibase_infra/nodes/node_registration_orchestrator/models/model_node_liveness_expired.py +107 -0
  480. omnibase_infra/nodes/node_registration_orchestrator/models/model_orchestrator_config.py +67 -0
  481. omnibase_infra/nodes/node_registration_orchestrator/models/model_orchestrator_input.py +41 -0
  482. omnibase_infra/nodes/node_registration_orchestrator/models/model_orchestrator_output.py +166 -0
  483. omnibase_infra/nodes/node_registration_orchestrator/models/model_postgres_intent_payload.py +235 -0
  484. omnibase_infra/nodes/node_registration_orchestrator/models/model_postgres_upsert_intent.py +68 -0
  485. omnibase_infra/nodes/node_registration_orchestrator/models/model_reducer_execution_result.py +384 -0
  486. omnibase_infra/nodes/node_registration_orchestrator/models/model_reducer_state.py +60 -0
  487. omnibase_infra/nodes/node_registration_orchestrator/models/model_registration_intent.py +177 -0
  488. omnibase_infra/nodes/node_registration_orchestrator/models/model_registry_intent.py +247 -0
  489. omnibase_infra/nodes/node_registration_orchestrator/node.py +195 -0
  490. omnibase_infra/nodes/node_registration_orchestrator/plugin.py +909 -0
  491. omnibase_infra/nodes/node_registration_orchestrator/protocols.py +439 -0
  492. omnibase_infra/nodes/node_registration_orchestrator/registry/__init__.py +41 -0
  493. omnibase_infra/nodes/node_registration_orchestrator/registry/registry_infra_node_registration_orchestrator.py +528 -0
  494. omnibase_infra/nodes/node_registration_orchestrator/timeout_coordinator.py +393 -0
  495. omnibase_infra/nodes/node_registration_orchestrator/wiring.py +743 -0
  496. omnibase_infra/nodes/node_registration_reducer/__init__.py +15 -0
  497. omnibase_infra/nodes/node_registration_reducer/contract.yaml +301 -0
  498. omnibase_infra/nodes/node_registration_reducer/models/__init__.py +38 -0
  499. omnibase_infra/nodes/node_registration_reducer/models/model_validation_result.py +113 -0
  500. omnibase_infra/nodes/node_registration_reducer/node.py +139 -0
  501. omnibase_infra/nodes/node_registration_reducer/registry/__init__.py +9 -0
  502. omnibase_infra/nodes/node_registration_reducer/registry/registry_infra_node_registration_reducer.py +79 -0
  503. omnibase_infra/nodes/node_registration_storage_effect/__init__.py +41 -0
  504. omnibase_infra/nodes/node_registration_storage_effect/contract.yaml +220 -0
  505. omnibase_infra/nodes/node_registration_storage_effect/models/__init__.py +44 -0
  506. omnibase_infra/nodes/node_registration_storage_effect/models/model_delete_result.py +132 -0
  507. omnibase_infra/nodes/node_registration_storage_effect/models/model_registration_record.py +199 -0
  508. omnibase_infra/nodes/node_registration_storage_effect/models/model_registration_update.py +155 -0
  509. omnibase_infra/nodes/node_registration_storage_effect/models/model_storage_health_check_details.py +123 -0
  510. omnibase_infra/nodes/node_registration_storage_effect/models/model_storage_health_check_result.py +117 -0
  511. omnibase_infra/nodes/node_registration_storage_effect/models/model_storage_query.py +100 -0
  512. omnibase_infra/nodes/node_registration_storage_effect/models/model_storage_result.py +136 -0
  513. omnibase_infra/nodes/node_registration_storage_effect/models/model_upsert_result.py +127 -0
  514. omnibase_infra/nodes/node_registration_storage_effect/node.py +112 -0
  515. omnibase_infra/nodes/node_registration_storage_effect/protocols/__init__.py +22 -0
  516. omnibase_infra/nodes/node_registration_storage_effect/protocols/protocol_registration_persistence.py +333 -0
  517. omnibase_infra/nodes/node_registration_storage_effect/registry/__init__.py +23 -0
  518. omnibase_infra/nodes/node_registration_storage_effect/registry/registry_infra_registration_storage.py +215 -0
  519. omnibase_infra/nodes/node_registry_effect/__init__.py +85 -0
  520. omnibase_infra/nodes/node_registry_effect/contract.yaml +677 -0
  521. omnibase_infra/nodes/node_registry_effect/handlers/__init__.py +70 -0
  522. omnibase_infra/nodes/node_registry_effect/handlers/handler_consul_deregister.py +211 -0
  523. omnibase_infra/nodes/node_registry_effect/handlers/handler_consul_register.py +212 -0
  524. omnibase_infra/nodes/node_registry_effect/handlers/handler_partial_retry.py +417 -0
  525. omnibase_infra/nodes/node_registry_effect/handlers/handler_postgres_deactivate.py +215 -0
  526. omnibase_infra/nodes/node_registry_effect/handlers/handler_postgres_upsert.py +208 -0
  527. omnibase_infra/nodes/node_registry_effect/models/__init__.py +43 -0
  528. omnibase_infra/nodes/node_registry_effect/models/model_partial_retry_request.py +92 -0
  529. omnibase_infra/nodes/node_registry_effect/node.py +165 -0
  530. omnibase_infra/nodes/node_registry_effect/registry/__init__.py +27 -0
  531. omnibase_infra/nodes/node_registry_effect/registry/registry_infra_registry_effect.py +196 -0
  532. omnibase_infra/nodes/node_service_discovery_effect/__init__.py +111 -0
  533. omnibase_infra/nodes/node_service_discovery_effect/contract.yaml +246 -0
  534. omnibase_infra/nodes/node_service_discovery_effect/models/__init__.py +67 -0
  535. omnibase_infra/nodes/node_service_discovery_effect/models/enum_health_status.py +72 -0
  536. omnibase_infra/nodes/node_service_discovery_effect/models/enum_service_discovery_operation.py +58 -0
  537. omnibase_infra/nodes/node_service_discovery_effect/models/model_discovery_query.py +99 -0
  538. omnibase_infra/nodes/node_service_discovery_effect/models/model_discovery_result.py +98 -0
  539. omnibase_infra/nodes/node_service_discovery_effect/models/model_health_check_config.py +121 -0
  540. omnibase_infra/nodes/node_service_discovery_effect/models/model_query_metadata.py +63 -0
  541. omnibase_infra/nodes/node_service_discovery_effect/models/model_registration_result.py +130 -0
  542. omnibase_infra/nodes/node_service_discovery_effect/models/model_service_discovery_health_check_details.py +111 -0
  543. omnibase_infra/nodes/node_service_discovery_effect/models/model_service_discovery_health_check_result.py +119 -0
  544. omnibase_infra/nodes/node_service_discovery_effect/models/model_service_info.py +106 -0
  545. omnibase_infra/nodes/node_service_discovery_effect/models/model_service_registration.py +121 -0
  546. omnibase_infra/nodes/node_service_discovery_effect/node.py +111 -0
  547. omnibase_infra/nodes/node_service_discovery_effect/protocols/__init__.py +14 -0
  548. omnibase_infra/nodes/node_service_discovery_effect/protocols/protocol_discovery_operations.py +279 -0
  549. omnibase_infra/nodes/node_service_discovery_effect/registry/__init__.py +13 -0
  550. omnibase_infra/nodes/node_service_discovery_effect/registry/registry_infra_service_discovery.py +222 -0
  551. omnibase_infra/nodes/reducers/__init__.py +30 -0
  552. omnibase_infra/nodes/reducers/models/__init__.py +37 -0
  553. omnibase_infra/nodes/reducers/models/model_payload_consul_register.py +87 -0
  554. omnibase_infra/nodes/reducers/models/model_payload_ledger_append.py +133 -0
  555. omnibase_infra/nodes/reducers/models/model_payload_postgres_upsert_registration.py +60 -0
  556. omnibase_infra/nodes/reducers/models/model_registration_confirmation.py +166 -0
  557. omnibase_infra/nodes/reducers/models/model_registration_state.py +433 -0
  558. omnibase_infra/nodes/reducers/registration_reducer.py +1138 -0
  559. omnibase_infra/observability/__init__.py +143 -0
  560. omnibase_infra/observability/constants_metrics.py +91 -0
  561. omnibase_infra/observability/factory_observability_sink.py +525 -0
  562. omnibase_infra/observability/handlers/__init__.py +118 -0
  563. omnibase_infra/observability/handlers/handler_logging_structured.py +967 -0
  564. omnibase_infra/observability/handlers/handler_metrics_prometheus.py +1120 -0
  565. omnibase_infra/observability/handlers/model_logging_handler_config.py +71 -0
  566. omnibase_infra/observability/handlers/model_logging_handler_response.py +77 -0
  567. omnibase_infra/observability/handlers/model_metrics_handler_config.py +172 -0
  568. omnibase_infra/observability/handlers/model_metrics_handler_payload.py +135 -0
  569. omnibase_infra/observability/handlers/model_metrics_handler_response.py +101 -0
  570. omnibase_infra/observability/hooks/__init__.py +74 -0
  571. omnibase_infra/observability/hooks/hook_observability.py +1223 -0
  572. omnibase_infra/observability/models/__init__.py +30 -0
  573. omnibase_infra/observability/models/enum_required_log_context_key.py +77 -0
  574. omnibase_infra/observability/models/model_buffered_log_entry.py +117 -0
  575. omnibase_infra/observability/models/model_logging_sink_config.py +73 -0
  576. omnibase_infra/observability/models/model_metrics_sink_config.py +156 -0
  577. omnibase_infra/observability/sinks/__init__.py +69 -0
  578. omnibase_infra/observability/sinks/sink_logging_structured.py +809 -0
  579. omnibase_infra/observability/sinks/sink_metrics_prometheus.py +710 -0
  580. omnibase_infra/plugins/__init__.py +27 -0
  581. omnibase_infra/plugins/examples/__init__.py +28 -0
  582. omnibase_infra/plugins/examples/plugin_json_normalizer.py +271 -0
  583. omnibase_infra/plugins/examples/plugin_json_normalizer_error_handling.py +210 -0
  584. omnibase_infra/plugins/models/__init__.py +21 -0
  585. omnibase_infra/plugins/models/model_plugin_context.py +76 -0
  586. omnibase_infra/plugins/models/model_plugin_input_data.py +58 -0
  587. omnibase_infra/plugins/models/model_plugin_output_data.py +62 -0
  588. omnibase_infra/plugins/plugin_compute_base.py +449 -0
  589. omnibase_infra/projectors/__init__.py +30 -0
  590. omnibase_infra/projectors/contracts/__init__.py +63 -0
  591. omnibase_infra/projectors/contracts/registration_projector.yaml +370 -0
  592. omnibase_infra/projectors/projection_reader_registration.py +1559 -0
  593. omnibase_infra/projectors/snapshot_publisher_registration.py +1329 -0
  594. omnibase_infra/protocols/__init__.py +104 -0
  595. omnibase_infra/protocols/protocol_capability_projection.py +253 -0
  596. omnibase_infra/protocols/protocol_capability_query.py +251 -0
  597. omnibase_infra/protocols/protocol_container_aware.py +200 -0
  598. omnibase_infra/protocols/protocol_dispatch_engine.py +152 -0
  599. omnibase_infra/protocols/protocol_event_bus_like.py +127 -0
  600. omnibase_infra/protocols/protocol_event_projector.py +96 -0
  601. omnibase_infra/protocols/protocol_idempotency_store.py +142 -0
  602. omnibase_infra/protocols/protocol_message_dispatcher.py +247 -0
  603. omnibase_infra/protocols/protocol_message_type_registry.py +306 -0
  604. omnibase_infra/protocols/protocol_plugin_compute.py +368 -0
  605. omnibase_infra/protocols/protocol_projector_schema_validator.py +82 -0
  606. omnibase_infra/protocols/protocol_registry_metrics.py +215 -0
  607. omnibase_infra/protocols/protocol_snapshot_publisher.py +396 -0
  608. omnibase_infra/protocols/protocol_snapshot_store.py +567 -0
  609. omnibase_infra/runtime/__init__.py +445 -0
  610. omnibase_infra/runtime/binding_config_resolver.py +2771 -0
  611. omnibase_infra/runtime/binding_resolver.py +753 -0
  612. omnibase_infra/runtime/chain_aware_dispatch.py +467 -0
  613. omnibase_infra/runtime/constants_notification.py +75 -0
  614. omnibase_infra/runtime/constants_security.py +70 -0
  615. omnibase_infra/runtime/contract_handler_discovery.py +587 -0
  616. omnibase_infra/runtime/contract_loaders/__init__.py +51 -0
  617. omnibase_infra/runtime/contract_loaders/handler_routing_loader.py +464 -0
  618. omnibase_infra/runtime/contract_loaders/operation_bindings_loader.py +789 -0
  619. omnibase_infra/runtime/dispatch_context_enforcer.py +427 -0
  620. omnibase_infra/runtime/emit_daemon/__init__.py +97 -0
  621. omnibase_infra/runtime/emit_daemon/cli.py +844 -0
  622. omnibase_infra/runtime/emit_daemon/client.py +811 -0
  623. omnibase_infra/runtime/emit_daemon/config.py +535 -0
  624. omnibase_infra/runtime/emit_daemon/daemon.py +812 -0
  625. omnibase_infra/runtime/emit_daemon/event_registry.py +477 -0
  626. omnibase_infra/runtime/emit_daemon/model_daemon_request.py +139 -0
  627. omnibase_infra/runtime/emit_daemon/model_daemon_response.py +191 -0
  628. omnibase_infra/runtime/emit_daemon/queue.py +618 -0
  629. omnibase_infra/runtime/enums/__init__.py +18 -0
  630. omnibase_infra/runtime/enums/enum_config_ref_scheme.py +33 -0
  631. omnibase_infra/runtime/enums/enum_scheduler_status.py +170 -0
  632. omnibase_infra/runtime/envelope_validator.py +179 -0
  633. omnibase_infra/runtime/event_bus_subcontract_wiring.py +466 -0
  634. omnibase_infra/runtime/handler_bootstrap_source.py +507 -0
  635. omnibase_infra/runtime/handler_contract_config_loader.py +603 -0
  636. omnibase_infra/runtime/handler_contract_source.py +750 -0
  637. omnibase_infra/runtime/handler_identity.py +81 -0
  638. omnibase_infra/runtime/handler_plugin_loader.py +2046 -0
  639. omnibase_infra/runtime/handler_registry.py +329 -0
  640. omnibase_infra/runtime/handler_source_resolver.py +367 -0
  641. omnibase_infra/runtime/invocation_security_enforcer.py +427 -0
  642. omnibase_infra/runtime/kafka_contract_source.py +984 -0
  643. omnibase_infra/runtime/kernel.py +40 -0
  644. omnibase_infra/runtime/mixin_policy_validation.py +522 -0
  645. omnibase_infra/runtime/mixin_semver_cache.py +402 -0
  646. omnibase_infra/runtime/mixins/__init__.py +24 -0
  647. omnibase_infra/runtime/mixins/mixin_projector_notification_publishing.py +566 -0
  648. omnibase_infra/runtime/mixins/mixin_projector_sql_operations.py +778 -0
  649. omnibase_infra/runtime/models/__init__.py +229 -0
  650. omnibase_infra/runtime/models/model_batch_lifecycle_result.py +217 -0
  651. omnibase_infra/runtime/models/model_binding_config.py +168 -0
  652. omnibase_infra/runtime/models/model_binding_config_cache_stats.py +135 -0
  653. omnibase_infra/runtime/models/model_binding_config_resolver_config.py +329 -0
  654. omnibase_infra/runtime/models/model_cached_secret.py +138 -0
  655. omnibase_infra/runtime/models/model_compute_key.py +138 -0
  656. omnibase_infra/runtime/models/model_compute_registration.py +97 -0
  657. omnibase_infra/runtime/models/model_config_cache_entry.py +61 -0
  658. omnibase_infra/runtime/models/model_config_ref.py +331 -0
  659. omnibase_infra/runtime/models/model_config_ref_parse_result.py +125 -0
  660. omnibase_infra/runtime/models/model_contract_load_result.py +224 -0
  661. omnibase_infra/runtime/models/model_domain_plugin_config.py +92 -0
  662. omnibase_infra/runtime/models/model_domain_plugin_result.py +270 -0
  663. omnibase_infra/runtime/models/model_duplicate_response.py +54 -0
  664. omnibase_infra/runtime/models/model_enabled_protocols_config.py +61 -0
  665. omnibase_infra/runtime/models/model_event_bus_config.py +54 -0
  666. omnibase_infra/runtime/models/model_failed_component.py +55 -0
  667. omnibase_infra/runtime/models/model_health_check_response.py +168 -0
  668. omnibase_infra/runtime/models/model_health_check_result.py +229 -0
  669. omnibase_infra/runtime/models/model_lifecycle_result.py +245 -0
  670. omnibase_infra/runtime/models/model_logging_config.py +42 -0
  671. omnibase_infra/runtime/models/model_optional_correlation_id.py +167 -0
  672. omnibase_infra/runtime/models/model_optional_string.py +94 -0
  673. omnibase_infra/runtime/models/model_optional_uuid.py +110 -0
  674. omnibase_infra/runtime/models/model_policy_context.py +100 -0
  675. omnibase_infra/runtime/models/model_policy_key.py +138 -0
  676. omnibase_infra/runtime/models/model_policy_registration.py +139 -0
  677. omnibase_infra/runtime/models/model_policy_result.py +103 -0
  678. omnibase_infra/runtime/models/model_policy_type_filter.py +157 -0
  679. omnibase_infra/runtime/models/model_projector_notification_config.py +171 -0
  680. omnibase_infra/runtime/models/model_projector_plugin_loader_config.py +47 -0
  681. omnibase_infra/runtime/models/model_protocol_registration_config.py +65 -0
  682. omnibase_infra/runtime/models/model_retry_policy.py +105 -0
  683. omnibase_infra/runtime/models/model_runtime_config.py +150 -0
  684. omnibase_infra/runtime/models/model_runtime_contract_config.py +268 -0
  685. omnibase_infra/runtime/models/model_runtime_scheduler_config.py +625 -0
  686. omnibase_infra/runtime/models/model_runtime_scheduler_metrics.py +233 -0
  687. omnibase_infra/runtime/models/model_runtime_tick.py +193 -0
  688. omnibase_infra/runtime/models/model_secret_cache_stats.py +82 -0
  689. omnibase_infra/runtime/models/model_secret_mapping.py +63 -0
  690. omnibase_infra/runtime/models/model_secret_resolver_config.py +107 -0
  691. omnibase_infra/runtime/models/model_secret_resolver_metrics.py +111 -0
  692. omnibase_infra/runtime/models/model_secret_source_info.py +72 -0
  693. omnibase_infra/runtime/models/model_secret_source_spec.py +66 -0
  694. omnibase_infra/runtime/models/model_security_config.py +109 -0
  695. omnibase_infra/runtime/models/model_shutdown_batch_result.py +75 -0
  696. omnibase_infra/runtime/models/model_shutdown_config.py +94 -0
  697. omnibase_infra/runtime/models/model_transition_notification_outbox_config.py +112 -0
  698. omnibase_infra/runtime/models/model_transition_notification_outbox_metrics.py +140 -0
  699. omnibase_infra/runtime/models/model_transition_notification_publisher_metrics.py +357 -0
  700. omnibase_infra/runtime/projector_plugin_loader.py +1462 -0
  701. omnibase_infra/runtime/projector_schema_manager.py +565 -0
  702. omnibase_infra/runtime/projector_shell.py +1330 -0
  703. omnibase_infra/runtime/protocol_contract_descriptor.py +92 -0
  704. omnibase_infra/runtime/protocol_contract_source.py +92 -0
  705. omnibase_infra/runtime/protocol_domain_plugin.py +474 -0
  706. omnibase_infra/runtime/protocol_handler_discovery.py +221 -0
  707. omnibase_infra/runtime/protocol_handler_plugin_loader.py +327 -0
  708. omnibase_infra/runtime/protocol_lifecycle_executor.py +435 -0
  709. omnibase_infra/runtime/protocol_policy.py +366 -0
  710. omnibase_infra/runtime/protocols/__init__.py +37 -0
  711. omnibase_infra/runtime/protocols/protocol_runtime_scheduler.py +468 -0
  712. omnibase_infra/runtime/publisher_topic_scoped.py +294 -0
  713. omnibase_infra/runtime/registry/__init__.py +93 -0
  714. omnibase_infra/runtime/registry/mixin_message_type_query.py +326 -0
  715. omnibase_infra/runtime/registry/mixin_message_type_registration.py +354 -0
  716. omnibase_infra/runtime/registry/registry_event_bus_binding.py +268 -0
  717. omnibase_infra/runtime/registry/registry_message_type.py +542 -0
  718. omnibase_infra/runtime/registry/registry_protocol_binding.py +445 -0
  719. omnibase_infra/runtime/registry_compute.py +1143 -0
  720. omnibase_infra/runtime/registry_contract_source.py +693 -0
  721. omnibase_infra/runtime/registry_dispatcher.py +678 -0
  722. omnibase_infra/runtime/registry_policy.py +1185 -0
  723. omnibase_infra/runtime/runtime_contract_config_loader.py +406 -0
  724. omnibase_infra/runtime/runtime_scheduler.py +1070 -0
  725. omnibase_infra/runtime/secret_resolver.py +2112 -0
  726. omnibase_infra/runtime/security_metadata_validator.py +776 -0
  727. omnibase_infra/runtime/service_kernel.py +1651 -0
  728. omnibase_infra/runtime/service_message_dispatch_engine.py +2350 -0
  729. omnibase_infra/runtime/service_runtime_host_process.py +3493 -0
  730. omnibase_infra/runtime/transition_notification_outbox.py +1190 -0
  731. omnibase_infra/runtime/transition_notification_publisher.py +765 -0
  732. omnibase_infra/runtime/util_container_wiring.py +1124 -0
  733. omnibase_infra/runtime/util_validation.py +314 -0
  734. omnibase_infra/runtime/util_version.py +98 -0
  735. omnibase_infra/runtime/util_wiring.py +723 -0
  736. omnibase_infra/schemas/schema_registration_projection.sql +320 -0
  737. omnibase_infra/schemas/schema_transition_notification_outbox.sql +245 -0
  738. omnibase_infra/services/__init__.py +89 -0
  739. omnibase_infra/services/corpus_capture.py +684 -0
  740. omnibase_infra/services/mcp/__init__.py +31 -0
  741. omnibase_infra/services/mcp/mcp_server_lifecycle.py +449 -0
  742. omnibase_infra/services/mcp/service_mcp_tool_discovery.py +411 -0
  743. omnibase_infra/services/mcp/service_mcp_tool_registry.py +329 -0
  744. omnibase_infra/services/mcp/service_mcp_tool_sync.py +565 -0
  745. omnibase_infra/services/registry_api/__init__.py +40 -0
  746. omnibase_infra/services/registry_api/main.py +261 -0
  747. omnibase_infra/services/registry_api/models/__init__.py +66 -0
  748. omnibase_infra/services/registry_api/models/model_capability_widget_mapping.py +38 -0
  749. omnibase_infra/services/registry_api/models/model_pagination_info.py +48 -0
  750. omnibase_infra/services/registry_api/models/model_registry_discovery_response.py +73 -0
  751. omnibase_infra/services/registry_api/models/model_registry_health_response.py +49 -0
  752. omnibase_infra/services/registry_api/models/model_registry_instance_view.py +88 -0
  753. omnibase_infra/services/registry_api/models/model_registry_node_view.py +88 -0
  754. omnibase_infra/services/registry_api/models/model_registry_summary.py +60 -0
  755. omnibase_infra/services/registry_api/models/model_response_list_instances.py +43 -0
  756. omnibase_infra/services/registry_api/models/model_response_list_nodes.py +51 -0
  757. omnibase_infra/services/registry_api/models/model_warning.py +49 -0
  758. omnibase_infra/services/registry_api/models/model_widget_defaults.py +28 -0
  759. omnibase_infra/services/registry_api/models/model_widget_mapping.py +51 -0
  760. omnibase_infra/services/registry_api/routes.py +371 -0
  761. omnibase_infra/services/registry_api/service.py +837 -0
  762. omnibase_infra/services/service_capability_query.py +945 -0
  763. omnibase_infra/services/service_health.py +898 -0
  764. omnibase_infra/services/service_node_selector.py +530 -0
  765. omnibase_infra/services/service_timeout_emitter.py +699 -0
  766. omnibase_infra/services/service_timeout_scanner.py +394 -0
  767. omnibase_infra/services/session/__init__.py +56 -0
  768. omnibase_infra/services/session/config_consumer.py +137 -0
  769. omnibase_infra/services/session/config_store.py +139 -0
  770. omnibase_infra/services/session/consumer.py +1007 -0
  771. omnibase_infra/services/session/protocol_session_aggregator.py +117 -0
  772. omnibase_infra/services/session/store.py +997 -0
  773. omnibase_infra/services/snapshot/__init__.py +31 -0
  774. omnibase_infra/services/snapshot/service_snapshot.py +647 -0
  775. omnibase_infra/services/snapshot/store_inmemory.py +637 -0
  776. omnibase_infra/services/snapshot/store_postgres.py +1279 -0
  777. omnibase_infra/shared/__init__.py +8 -0
  778. omnibase_infra/testing/__init__.py +10 -0
  779. omnibase_infra/testing/utils.py +23 -0
  780. omnibase_infra/topics/__init__.py +45 -0
  781. omnibase_infra/topics/platform_topic_suffixes.py +140 -0
  782. omnibase_infra/topics/util_topic_composition.py +95 -0
  783. omnibase_infra/types/__init__.py +48 -0
  784. omnibase_infra/types/type_cache_info.py +49 -0
  785. omnibase_infra/types/type_dsn.py +173 -0
  786. omnibase_infra/types/type_infra_aliases.py +60 -0
  787. omnibase_infra/types/typed_dict/__init__.py +29 -0
  788. omnibase_infra/types/typed_dict/typed_dict_envelope_build_params.py +115 -0
  789. omnibase_infra/types/typed_dict/typed_dict_introspection_cache.py +128 -0
  790. omnibase_infra/types/typed_dict/typed_dict_performance_metrics_cache.py +140 -0
  791. omnibase_infra/types/typed_dict_capabilities.py +64 -0
  792. omnibase_infra/utils/__init__.py +117 -0
  793. omnibase_infra/utils/correlation.py +208 -0
  794. omnibase_infra/utils/util_atomic_file.py +261 -0
  795. omnibase_infra/utils/util_consumer_group.py +232 -0
  796. omnibase_infra/utils/util_datetime.py +372 -0
  797. omnibase_infra/utils/util_db_transaction.py +239 -0
  798. omnibase_infra/utils/util_dsn_validation.py +333 -0
  799. omnibase_infra/utils/util_env_parsing.py +264 -0
  800. omnibase_infra/utils/util_error_sanitization.py +457 -0
  801. omnibase_infra/utils/util_pydantic_validators.py +477 -0
  802. omnibase_infra/utils/util_retry_optimistic.py +281 -0
  803. omnibase_infra/utils/util_semver.py +233 -0
  804. omnibase_infra/validation/__init__.py +307 -0
  805. omnibase_infra/validation/contracts/security.validation.yaml +114 -0
  806. omnibase_infra/validation/enums/__init__.py +11 -0
  807. omnibase_infra/validation/enums/enum_contract_violation_severity.py +13 -0
  808. omnibase_infra/validation/infra_validators.py +1514 -0
  809. omnibase_infra/validation/linter_contract.py +907 -0
  810. omnibase_infra/validation/mixin_any_type_classification.py +120 -0
  811. omnibase_infra/validation/mixin_any_type_exemption.py +580 -0
  812. omnibase_infra/validation/mixin_any_type_reporting.py +106 -0
  813. omnibase_infra/validation/mixin_execution_shape_violation_checks.py +596 -0
  814. omnibase_infra/validation/mixin_node_archetype_detection.py +254 -0
  815. omnibase_infra/validation/models/__init__.py +15 -0
  816. omnibase_infra/validation/models/model_contract_lint_result.py +101 -0
  817. omnibase_infra/validation/models/model_contract_violation.py +41 -0
  818. omnibase_infra/validation/service_validation_aggregator.py +395 -0
  819. omnibase_infra/validation/validation_exemptions.yaml +2033 -0
  820. omnibase_infra/validation/validator_any_type.py +715 -0
  821. omnibase_infra/validation/validator_chain_propagation.py +839 -0
  822. omnibase_infra/validation/validator_execution_shape.py +465 -0
  823. omnibase_infra/validation/validator_localhandler.py +261 -0
  824. omnibase_infra/validation/validator_registration_security.py +410 -0
  825. omnibase_infra/validation/validator_routing_coverage.py +1020 -0
  826. omnibase_infra/validation/validator_runtime_shape.py +915 -0
  827. omnibase_infra/validation/validator_security.py +513 -0
  828. omnibase_infra/validation/validator_topic_category.py +1152 -0
  829. omnibase_infra-0.2.6.dist-info/METADATA +197 -0
  830. omnibase_infra-0.2.6.dist-info/RECORD +833 -0
  831. omnibase_infra-0.2.6.dist-info/WHEEL +4 -0
  832. omnibase_infra-0.2.6.dist-info/entry_points.txt +5 -0
  833. omnibase_infra-0.2.6.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,997 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2025 OmniNode Team
3
+ """PostgreSQL storage adapter for session snapshots.
4
+
5
+ Persists session snapshots to PostgreSQL with child tables
6
+ for prompts and tools. Supports idempotent upserts.
7
+
8
+ Table Schema:
9
+ - claude_session_snapshots: Main aggregate with session lifecycle
10
+ - claude_session_prompts: Child table for prompt records
11
+ - claude_session_tools: Child table for tool execution records
12
+ - claude_session_event_idempotency: Deduplication tracking
13
+
14
+ See migrations/016_create_session_snapshots.sql for full schema.
15
+
16
+ Idempotency Cleanup:
17
+ The idempotency table has a 24-hour TTL. Call cleanup_expired_idempotency()
18
+ periodically (e.g., hourly) to remove expired records and prevent table bloat.
19
+
20
+ Moved from omniclaude as part of OMN-1526 architectural cleanup.
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ import asyncio
26
+ import logging
27
+ from datetime import UTC, datetime
28
+ from typing import TYPE_CHECKING, Any
29
+ from uuid import UUID
30
+
31
+ import asyncpg
32
+
33
+ from omnibase_infra.services.session.config_store import ConfigSessionStorage
34
+
35
+ if TYPE_CHECKING:
36
+ from asyncpg import Connection, Pool
37
+
38
+ logger = logging.getLogger(__name__)
39
+
40
+
41
+ class SessionStoreNotInitializedError(RuntimeError):
42
+ """Raised when SessionSnapshotStore operations are called before initialize().
43
+
44
+ This error indicates the store's connection pool has not been created.
45
+ Call initialize() before performing any database operations.
46
+ """
47
+
48
+
49
+ # Idempotency domain constant
50
+ _IDEMPOTENCY_DOMAIN = "claude_session"
51
+
52
+
53
+ def _ensure_uuid(value: str | UUID | None) -> UUID | None:
54
+ """Convert string to UUID if needed.
55
+
56
+ Handles values that may be either string (from JSON deserialization)
57
+ or UUID objects, converting strings to proper UUID type for database.
58
+
59
+ Args:
60
+ value: A string, UUID, or None.
61
+
62
+ Returns:
63
+ UUID object or None if input was None.
64
+ """
65
+ if value is None:
66
+ return None
67
+ if isinstance(value, UUID):
68
+ return value
69
+ return UUID(value)
70
+
71
+
72
+ def _ensure_datetime(value: str | datetime | None) -> datetime | None:
73
+ """Convert string to datetime if needed.
74
+
75
+ Handles values that may be either ISO format string (from JSON deserialization)
76
+ or datetime objects, converting strings to proper datetime type for database.
77
+
78
+ Supports ISO 8601 format with timezone designators:
79
+ - "2024-01-15T10:30:00+00:00"
80
+ - "2024-01-15T10:30:00Z" (UTC shorthand)
81
+
82
+ Args:
83
+ value: An ISO format string, datetime, or None.
84
+
85
+ Returns:
86
+ datetime object or None if input was None.
87
+ """
88
+ if value is None:
89
+ return None
90
+ if isinstance(value, datetime):
91
+ return value
92
+ # Parse ISO format string, handling 'Z' suffix for UTC
93
+ return datetime.fromisoformat(value.replace("Z", "+00:00"))
94
+
95
+
96
+ class SessionSnapshotStore:
97
+ """PostgreSQL storage for session snapshots.
98
+
99
+ Handles persistence of session snapshots with child tables
100
+ for prompts and tool executions. Uses asyncpg for async operations
101
+ and connection pooling.
102
+
103
+ Thread Safety:
104
+ This class is thread-safe. The asyncpg pool handles connection
105
+ management internally.
106
+
107
+ Example:
108
+ >>> config = ConfigSessionStorage(postgres_password=SecretStr("secret"))
109
+ >>> store = SessionSnapshotStore(config)
110
+ >>> await store.initialize()
111
+ >>> try:
112
+ ... snapshot_id = await store.save_snapshot(snapshot_data, correlation_id)
113
+ ... finally:
114
+ ... await store.close()
115
+ """
116
+
117
+ def __init__(self, config: ConfigSessionStorage) -> None:
118
+ """Initialize store with configuration.
119
+
120
+ Args:
121
+ config: PostgreSQL connection configuration.
122
+ """
123
+ self._config = config
124
+ self._pool: Pool | None = None
125
+
126
+ @property
127
+ def is_initialized(self) -> bool:
128
+ """Check if the store is initialized and ready for use."""
129
+ return self._pool is not None
130
+
131
+ async def initialize(self) -> None:
132
+ """Initialize connection pool.
133
+
134
+ Creates an asyncpg connection pool with the configured parameters.
135
+ Must be called before any other operations.
136
+
137
+ Raises:
138
+ asyncpg.PostgresError: If connection fails.
139
+ """
140
+ if self._pool is not None:
141
+ logger.warning("SessionSnapshotStore already initialized, skipping")
142
+ return
143
+
144
+ self._pool = await asyncpg.create_pool(
145
+ dsn=self._config.dsn,
146
+ min_size=self._config.pool_min_size,
147
+ max_size=self._config.pool_max_size,
148
+ command_timeout=self._config.query_timeout_seconds,
149
+ )
150
+ logger.info(
151
+ "SessionSnapshotStore initialized",
152
+ extra={
153
+ "pool_min_size": self._config.pool_min_size,
154
+ "pool_max_size": self._config.pool_max_size,
155
+ "timeout_seconds": self._config.query_timeout_seconds,
156
+ },
157
+ )
158
+
159
+ async def close(self) -> None:
160
+ """Close connection pool.
161
+
162
+ Releases all connections back to the pool and closes them.
163
+ Safe to call multiple times.
164
+ """
165
+ if self._pool is not None:
166
+ await self._pool.close()
167
+ self._pool = None
168
+ logger.info("SessionSnapshotStore closed")
169
+
170
+ def _require_pool(self) -> Pool:
171
+ """Get pool or raise if not initialized.
172
+
173
+ Returns:
174
+ The connection pool.
175
+
176
+ Raises:
177
+ SessionStoreNotInitializedError: If store not initialized.
178
+ """
179
+ if self._pool is None:
180
+ raise SessionStoreNotInitializedError(
181
+ "SessionSnapshotStore not initialized. Call initialize() first."
182
+ )
183
+ return self._pool
184
+
185
+ # =========================================================================
186
+ # Public API - CRUD Operations
187
+ # =========================================================================
188
+
189
+ # ONEX_EXCLUDE: any_type - dict[str, Any] required for JSON-like snapshot data
190
+ async def save_snapshot(
191
+ self,
192
+ snapshot: dict[str, Any],
193
+ correlation_id: UUID,
194
+ ) -> UUID:
195
+ """Save or update a session snapshot.
196
+
197
+ Uses upsert semantics - updates existing snapshot if session_id exists.
198
+ Handles child tables (prompts, tools) in a transaction.
199
+
200
+ Args:
201
+ snapshot: Snapshot data containing:
202
+ - session_id: Required session identifier
203
+ - status: Session status (orphan, active, ended, timed_out)
204
+ - started_at: Session start time
205
+ - ended_at: Session end time (optional)
206
+ - duration_seconds: Session duration (optional)
207
+ - working_directory: Working directory path
208
+ - git_branch: Git branch name (optional)
209
+ - hook_source: How session was detected
210
+ - end_reason: Why session ended (optional)
211
+ - prompt_count: Number of prompts
212
+ - tool_count: Number of tool executions
213
+ - tools_used_count: Unique tools used
214
+ - event_count: Total events processed
215
+ - last_event_at: Timestamp of last event
216
+ - schema_version: Schema version
217
+ - prompts: List of prompt records (optional)
218
+ - tools: List of tool records (optional)
219
+ correlation_id: Correlation ID for tracing.
220
+
221
+ Returns:
222
+ The snapshot_id (UUID) of the saved snapshot.
223
+
224
+ Raises:
225
+ RuntimeError: If store not initialized.
226
+ asyncpg.PostgresError: If database operation fails.
227
+ """
228
+ pool = self._require_pool()
229
+
230
+ async with pool.acquire() as conn:
231
+ async with conn.transaction():
232
+ # Upsert main snapshot first (required for foreign key references)
233
+ snapshot_id = await self._upsert_snapshot(conn, snapshot)
234
+
235
+ # Sync child tables in parallel if provided.
236
+ # This is safe because:
237
+ # 1. Both operations are within the same transaction (atomicity preserved)
238
+ # 2. prompts and tools tables are independent (no cross-table constraints)
239
+ # 3. Both reference the same snapshot_id but don't conflict with each other
240
+ prompts = snapshot.get("prompts", [])
241
+ tools = snapshot.get("tools", [])
242
+
243
+ if prompts or tools:
244
+ async with asyncio.TaskGroup() as tg:
245
+ if prompts:
246
+ tg.create_task(
247
+ self._sync_prompts_with_context(
248
+ conn, snapshot_id, prompts
249
+ )
250
+ )
251
+ if tools:
252
+ tg.create_task(
253
+ self._sync_tools_with_context(conn, snapshot_id, tools)
254
+ )
255
+
256
+ logger.debug(
257
+ "Saved session snapshot",
258
+ extra={
259
+ "snapshot_id": str(snapshot_id),
260
+ "session_id": snapshot.get("session_id"),
261
+ "correlation_id": str(correlation_id),
262
+ "prompt_count": len(prompts),
263
+ "tool_count": len(tools),
264
+ },
265
+ )
266
+
267
+ return snapshot_id
268
+
269
+ # ONEX_EXCLUDE: any_type - dict[str, Any] required for JSON-like snapshot data
270
+ async def get_snapshot(
271
+ self,
272
+ session_id: str,
273
+ correlation_id: UUID,
274
+ ) -> dict[str, Any] | None:
275
+ """Get snapshot by session_id.
276
+
277
+ Includes prompts and tools as nested lists.
278
+
279
+ Args:
280
+ session_id: The session identifier.
281
+ correlation_id: Correlation ID for tracing.
282
+
283
+ Returns:
284
+ Snapshot dict with prompts and tools, or None if not found.
285
+
286
+ Raises:
287
+ RuntimeError: If store not initialized.
288
+ asyncpg.PostgresError: If database operation fails.
289
+ """
290
+ pool = self._require_pool()
291
+
292
+ async with pool.acquire() as conn:
293
+ # Fetch main snapshot
294
+ row = await conn.fetchrow(
295
+ """
296
+ SELECT
297
+ snapshot_id, session_id, correlation_id, status,
298
+ started_at, ended_at, duration_seconds,
299
+ working_directory, git_branch, hook_source, end_reason,
300
+ prompt_count, tool_count, tools_used_count, event_count,
301
+ last_event_at, schema_version, created_at, updated_at
302
+ FROM claude_session_snapshots
303
+ WHERE session_id = $1
304
+ """,
305
+ session_id,
306
+ )
307
+
308
+ if row is None:
309
+ logger.debug(
310
+ "Snapshot not found",
311
+ extra={
312
+ "session_id": session_id,
313
+ "correlation_id": str(correlation_id),
314
+ },
315
+ )
316
+ return None
317
+
318
+ snapshot = dict(row)
319
+ snapshot_id = snapshot["snapshot_id"]
320
+
321
+ # Fetch child records
322
+ snapshot["prompts"] = await self._fetch_prompts(conn, snapshot_id)
323
+ snapshot["tools"] = await self._fetch_tools(conn, snapshot_id)
324
+
325
+ logger.debug(
326
+ "Retrieved session snapshot",
327
+ extra={
328
+ "snapshot_id": str(snapshot_id),
329
+ "session_id": session_id,
330
+ "correlation_id": str(correlation_id),
331
+ },
332
+ )
333
+
334
+ return snapshot
335
+
336
+ # ONEX_EXCLUDE: any_type - dict[str, Any] required for JSON-like snapshot data
337
+ async def get_snapshot_by_id(
338
+ self,
339
+ snapshot_id: UUID,
340
+ correlation_id: UUID,
341
+ ) -> dict[str, Any] | None:
342
+ """Get snapshot by snapshot_id (UUID).
343
+
344
+ Includes prompts and tools as nested lists.
345
+
346
+ Args:
347
+ snapshot_id: The snapshot UUID.
348
+ correlation_id: Correlation ID for tracing.
349
+
350
+ Returns:
351
+ Snapshot dict with prompts and tools, or None if not found.
352
+
353
+ Raises:
354
+ RuntimeError: If store not initialized.
355
+ asyncpg.PostgresError: If database operation fails.
356
+ """
357
+ pool = self._require_pool()
358
+
359
+ async with pool.acquire() as conn:
360
+ # Fetch main snapshot
361
+ row = await conn.fetchrow(
362
+ """
363
+ SELECT
364
+ snapshot_id, session_id, correlation_id, status,
365
+ started_at, ended_at, duration_seconds,
366
+ working_directory, git_branch, hook_source, end_reason,
367
+ prompt_count, tool_count, tools_used_count, event_count,
368
+ last_event_at, schema_version, created_at, updated_at
369
+ FROM claude_session_snapshots
370
+ WHERE snapshot_id = $1
371
+ """,
372
+ snapshot_id,
373
+ )
374
+
375
+ if row is None:
376
+ logger.debug(
377
+ "Snapshot not found by ID",
378
+ extra={
379
+ "snapshot_id": str(snapshot_id),
380
+ "correlation_id": str(correlation_id),
381
+ },
382
+ )
383
+ return None
384
+
385
+ snapshot = dict(row)
386
+
387
+ # Fetch child records
388
+ snapshot["prompts"] = await self._fetch_prompts(conn, snapshot_id)
389
+ snapshot["tools"] = await self._fetch_tools(conn, snapshot_id)
390
+
391
+ logger.debug(
392
+ "Retrieved session snapshot by ID",
393
+ extra={
394
+ "snapshot_id": str(snapshot_id),
395
+ "session_id": snapshot.get("session_id"),
396
+ "correlation_id": str(correlation_id),
397
+ },
398
+ )
399
+
400
+ return snapshot
401
+
402
+ async def list_snapshots(
403
+ self,
404
+ status: str | None = None,
405
+ working_directory: str | None = None,
406
+ limit: int = 100,
407
+ offset: int = 0,
408
+ correlation_id: UUID | None = None,
409
+ # ONEX_EXCLUDE: any_type - dict[str, Any] required for JSON-like snapshot data
410
+ ) -> list[dict[str, Any]]:
411
+ """List snapshots with optional filters.
412
+
413
+ Does NOT include prompts/tools (use get_snapshot for full data).
414
+
415
+ Args:
416
+ status: Filter by session status (orphan, active, ended, timed_out).
417
+ working_directory: Filter by working directory (exact match).
418
+ limit: Maximum number of results (default 100, max 1000).
419
+ offset: Number of results to skip (for pagination).
420
+ correlation_id: Correlation ID for tracing.
421
+
422
+ Returns:
423
+ List of snapshot dicts (without child records).
424
+
425
+ Raises:
426
+ RuntimeError: If store not initialized.
427
+ asyncpg.PostgresError: If database operation fails.
428
+ """
429
+ pool = self._require_pool()
430
+
431
+ # Clamp limit to prevent excessive queries
432
+ limit = min(limit, 1000)
433
+
434
+ # Build query with optional filters
435
+ conditions: list[str] = []
436
+ # ONEX_EXCLUDE: any_type - list[Any] for SQL query parameters
437
+ params: list[Any] = []
438
+ param_idx = 1
439
+
440
+ if status is not None:
441
+ conditions.append(f"status = ${param_idx}")
442
+ params.append(status)
443
+ param_idx += 1
444
+
445
+ if working_directory is not None:
446
+ conditions.append(f"working_directory = ${param_idx}")
447
+ params.append(working_directory)
448
+ param_idx += 1
449
+
450
+ where_clause = ""
451
+ if conditions:
452
+ where_clause = "WHERE " + " AND ".join(conditions)
453
+
454
+ # Add limit and offset
455
+ params.append(limit)
456
+ params.append(offset)
457
+
458
+ # NOTE: S608 is a false positive - where_clause is built from validated
459
+ # string literals, all user inputs are parameterized via $N placeholders
460
+ query = f"""
461
+ SELECT
462
+ snapshot_id, session_id, correlation_id, status,
463
+ started_at, ended_at, duration_seconds,
464
+ working_directory, git_branch, hook_source, end_reason,
465
+ prompt_count, tool_count, tools_used_count, event_count,
466
+ last_event_at, schema_version, created_at, updated_at
467
+ FROM claude_session_snapshots
468
+ {where_clause}
469
+ ORDER BY last_event_at DESC
470
+ LIMIT ${param_idx} OFFSET ${param_idx + 1}
471
+ """ # noqa: S608
472
+
473
+ async with pool.acquire() as conn:
474
+ rows = await conn.fetch(query, *params)
475
+
476
+ snapshots = [dict(row) for row in rows]
477
+
478
+ logger.debug(
479
+ "Listed session snapshots",
480
+ extra={
481
+ "count": len(snapshots),
482
+ "status_filter": status,
483
+ "working_directory_filter": working_directory,
484
+ "limit": limit,
485
+ "offset": offset,
486
+ "correlation_id": str(correlation_id) if correlation_id else None,
487
+ },
488
+ )
489
+
490
+ return snapshots
491
+
492
+ async def delete_snapshot(
493
+ self,
494
+ session_id: str,
495
+ correlation_id: UUID,
496
+ ) -> bool:
497
+ """Delete a snapshot and its children.
498
+
499
+ Child records (prompts, tools) are deleted automatically via CASCADE.
500
+
501
+ Args:
502
+ session_id: The session identifier.
503
+ correlation_id: Correlation ID for tracing.
504
+
505
+ Returns:
506
+ True if deleted, False if not found.
507
+
508
+ Raises:
509
+ RuntimeError: If store not initialized.
510
+ asyncpg.PostgresError: If database operation fails.
511
+ """
512
+ pool = self._require_pool()
513
+
514
+ async with pool.acquire() as conn:
515
+ result = await conn.execute(
516
+ "DELETE FROM claude_session_snapshots WHERE session_id = $1",
517
+ session_id,
518
+ )
519
+
520
+ # Parse result string (e.g., "DELETE 1" or "DELETE 0")
521
+ deleted = self._parse_row_count(result) > 0
522
+
523
+ logger.debug(
524
+ "Delete snapshot result",
525
+ extra={
526
+ "session_id": session_id,
527
+ "deleted": deleted,
528
+ "correlation_id": str(correlation_id),
529
+ },
530
+ )
531
+
532
+ return deleted
533
+
534
+ # =========================================================================
535
+ # Public API - Idempotency Operations
536
+ # =========================================================================
537
+
538
+ async def check_idempotency(
539
+ self,
540
+ message_id: UUID,
541
+ correlation_id: UUID,
542
+ ) -> bool:
543
+ """Check if message was already processed.
544
+
545
+ Uses SELECT to check if message_id exists in idempotency table.
546
+
547
+ Args:
548
+ message_id: The unique message identifier.
549
+ correlation_id: Correlation ID for tracing.
550
+
551
+ Returns:
552
+ True if processed (duplicate), False if new.
553
+
554
+ Raises:
555
+ RuntimeError: If store not initialized.
556
+ asyncpg.PostgresError: If database operation fails.
557
+ """
558
+ pool = self._require_pool()
559
+
560
+ async with pool.acquire() as conn:
561
+ row = await conn.fetchrow(
562
+ """
563
+ SELECT message_id FROM claude_session_event_idempotency
564
+ WHERE message_id = $1 AND domain = $2
565
+ """,
566
+ message_id,
567
+ _IDEMPOTENCY_DOMAIN,
568
+ )
569
+
570
+ is_duplicate = row is not None
571
+
572
+ if is_duplicate:
573
+ logger.debug(
574
+ "Duplicate message detected",
575
+ extra={
576
+ "message_id": str(message_id),
577
+ "correlation_id": str(correlation_id),
578
+ },
579
+ )
580
+
581
+ return is_duplicate
582
+
583
+ async def record_idempotency(
584
+ self,
585
+ message_id: UUID,
586
+ correlation_id: UUID,
587
+ ) -> None:
588
+ """Record message as processed for idempotency.
589
+
590
+ Uses INSERT ... ON CONFLICT DO NOTHING to handle races.
591
+
592
+ Args:
593
+ message_id: The unique message identifier.
594
+ correlation_id: Correlation ID for tracing.
595
+
596
+ Raises:
597
+ RuntimeError: If store not initialized.
598
+ asyncpg.PostgresError: If database operation fails.
599
+ """
600
+ pool = self._require_pool()
601
+
602
+ async with pool.acquire() as conn:
603
+ await conn.execute(
604
+ """
605
+ INSERT INTO claude_session_event_idempotency (message_id, domain)
606
+ VALUES ($1, $2)
607
+ ON CONFLICT (message_id) DO NOTHING
608
+ """,
609
+ message_id,
610
+ _IDEMPOTENCY_DOMAIN,
611
+ )
612
+
613
+ logger.debug(
614
+ "Recorded idempotency",
615
+ extra={
616
+ "message_id": str(message_id),
617
+ "correlation_id": str(correlation_id),
618
+ },
619
+ )
620
+
621
+ async def cleanup_expired_idempotency(
622
+ self,
623
+ correlation_id: UUID,
624
+ ) -> int:
625
+ """Remove expired idempotency records.
626
+
627
+ Deletes records where expires_at < NOW(). This prevents the idempotency
628
+ table from growing unbounded over time.
629
+
630
+ Scheduling Guidance:
631
+ This method should be called periodically to clean up expired records.
632
+ Recommended approaches:
633
+
634
+ 1. **Cron Job / Scheduled Task**: Run every hour or daily
635
+ ```python
636
+ # Example with APScheduler
637
+ scheduler.add_job(
638
+ lambda: asyncio.run(store.cleanup_expired_idempotency(uuid4())),
639
+ 'interval',
640
+ hours=1,
641
+ )
642
+ ```
643
+
644
+ 2. **Background Task**: Run in consumer after N messages processed
645
+ ```python
646
+ if messages_processed % 1000 == 0:
647
+ await store.cleanup_expired_idempotency(correlation_id)
648
+ ```
649
+
650
+ 3. **Startup Cleanup**: Run once when consumer starts
651
+ ```python
652
+ await store.initialize()
653
+ await store.cleanup_expired_idempotency(uuid4()) # Initial cleanup
654
+ ```
655
+
656
+ The default TTL is 24 hours (set in database migration). Cleanup frequency
657
+ should be adjusted based on message volume - high-volume systems may need
658
+ more frequent cleanup.
659
+
660
+ Args:
661
+ correlation_id: Correlation ID for tracing.
662
+
663
+ Returns:
664
+ Count of removed records.
665
+
666
+ Raises:
667
+ SessionStoreNotInitializedError: If store not initialized.
668
+ asyncpg.PostgresError: If database operation fails.
669
+ """
670
+ pool = self._require_pool()
671
+
672
+ async with pool.acquire() as conn:
673
+ result = await conn.execute(
674
+ """
675
+ DELETE FROM claude_session_event_idempotency
676
+ WHERE expires_at < NOW() AND domain = $1
677
+ """,
678
+ _IDEMPOTENCY_DOMAIN,
679
+ )
680
+
681
+ count = self._parse_row_count(result)
682
+
683
+ if count > 0:
684
+ logger.info(
685
+ "Cleaned up expired idempotency records",
686
+ extra={
687
+ "deleted_count": count,
688
+ "correlation_id": str(correlation_id),
689
+ },
690
+ )
691
+
692
+ return count
693
+
694
+ # =========================================================================
695
+ # Private Helpers - Snapshot Operations
696
+ # =========================================================================
697
+
698
+ # ONEX_EXCLUDE: any_type - dict[str, Any] required for JSON-like snapshot data
699
+ async def _upsert_snapshot(
700
+ self,
701
+ conn: Connection,
702
+ snapshot: dict[str, Any],
703
+ ) -> UUID:
704
+ """Upsert main snapshot record.
705
+
706
+ Args:
707
+ conn: Database connection (within transaction).
708
+ snapshot: Snapshot data.
709
+
710
+ Returns:
711
+ The snapshot_id.
712
+ """
713
+ # Extract required fields
714
+ session_id = snapshot["session_id"]
715
+ status = snapshot.get("status", "active")
716
+ working_directory = snapshot["working_directory"]
717
+ hook_source = snapshot["hook_source"]
718
+ last_event_at = _ensure_datetime(snapshot.get("last_event_at")) or datetime.now(
719
+ UTC
720
+ )
721
+
722
+ # Extract optional fields with datetime coercion
723
+ correlation_id = snapshot.get("correlation_id")
724
+ started_at = _ensure_datetime(snapshot.get("started_at"))
725
+ ended_at = _ensure_datetime(snapshot.get("ended_at"))
726
+ duration_seconds = snapshot.get("duration_seconds")
727
+ git_branch = snapshot.get("git_branch")
728
+ end_reason = snapshot.get("end_reason")
729
+ prompt_count = snapshot.get("prompt_count", 0)
730
+ tool_count = snapshot.get("tool_count", 0)
731
+ tools_used_count = snapshot.get("tools_used_count", 0)
732
+ event_count = snapshot.get("event_count", 0)
733
+ schema_version = snapshot.get("schema_version", "1.0.0")
734
+
735
+ row = await conn.fetchrow(
736
+ """
737
+ INSERT INTO claude_session_snapshots (
738
+ session_id, correlation_id, status, started_at, ended_at,
739
+ duration_seconds, working_directory, git_branch, hook_source,
740
+ end_reason, prompt_count, tool_count, tools_used_count,
741
+ event_count, last_event_at, schema_version
742
+ ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)
743
+ ON CONFLICT (session_id) DO UPDATE SET
744
+ status = EXCLUDED.status,
745
+ ended_at = COALESCE(EXCLUDED.ended_at, claude_session_snapshots.ended_at),
746
+ duration_seconds = COALESCE(EXCLUDED.duration_seconds, claude_session_snapshots.duration_seconds),
747
+ end_reason = COALESCE(EXCLUDED.end_reason, claude_session_snapshots.end_reason),
748
+ prompt_count = EXCLUDED.prompt_count,
749
+ tool_count = EXCLUDED.tool_count,
750
+ tools_used_count = EXCLUDED.tools_used_count,
751
+ event_count = EXCLUDED.event_count,
752
+ last_event_at = EXCLUDED.last_event_at,
753
+ schema_version = EXCLUDED.schema_version
754
+ RETURNING snapshot_id
755
+ """,
756
+ session_id,
757
+ correlation_id,
758
+ status,
759
+ started_at,
760
+ ended_at,
761
+ duration_seconds,
762
+ working_directory,
763
+ git_branch,
764
+ hook_source,
765
+ end_reason,
766
+ prompt_count,
767
+ tool_count,
768
+ tools_used_count,
769
+ event_count,
770
+ last_event_at,
771
+ schema_version,
772
+ )
773
+
774
+ # row is guaranteed to exist due to RETURNING clause
775
+ snapshot_id: UUID = row["snapshot_id"]
776
+ return snapshot_id
777
+
778
+ # ONEX_EXCLUDE: any_type - list[dict[str, Any]] required for JSON-like data
779
+ async def _sync_prompts_with_context(
780
+ self,
781
+ conn: Connection,
782
+ snapshot_id: UUID,
783
+ prompts: list[dict[str, Any]],
784
+ ) -> None:
785
+ """Sync prompts with error context wrapper.
786
+
787
+ Wraps _sync_prompts to provide context about which table
788
+ operation failed when errors occur in parallel execution.
789
+
790
+ Args:
791
+ conn: Database connection (within transaction).
792
+ snapshot_id: Parent snapshot UUID.
793
+ prompts: List of prompt records.
794
+
795
+ Raises:
796
+ RuntimeError: If sync fails, with context about the prompts table.
797
+ """
798
+ try:
799
+ await self._sync_prompts(conn, snapshot_id, prompts)
800
+ except Exception as e:
801
+ raise RuntimeError(
802
+ f"Failed to sync prompts for snapshot {snapshot_id}: "
803
+ f"{len(prompts)} prompts"
804
+ ) from e
805
+
806
+ # ONEX_EXCLUDE: any_type - list[dict[str, Any]] required for JSON-like data
807
+ async def _sync_tools_with_context(
808
+ self,
809
+ conn: Connection,
810
+ snapshot_id: UUID,
811
+ tools: list[dict[str, Any]],
812
+ ) -> None:
813
+ """Sync tools with error context wrapper.
814
+
815
+ Wraps _sync_tools to provide context about which table
816
+ operation failed when errors occur in parallel execution.
817
+
818
+ Args:
819
+ conn: Database connection (within transaction).
820
+ snapshot_id: Parent snapshot UUID.
821
+ tools: List of tool records.
822
+
823
+ Raises:
824
+ RuntimeError: If sync fails, with context about the tools table.
825
+ """
826
+ try:
827
+ await self._sync_tools(conn, snapshot_id, tools)
828
+ except Exception as e:
829
+ raise RuntimeError(
830
+ f"Failed to sync tools for snapshot {snapshot_id}: {len(tools)} tools"
831
+ ) from e
832
+
833
+ # ONEX_EXCLUDE: any_type - list[dict[str, Any]] required for JSON-like data
834
+ async def _sync_prompts(
835
+ self,
836
+ conn: Connection,
837
+ snapshot_id: UUID,
838
+ prompts: list[dict[str, Any]],
839
+ ) -> None:
840
+ """Sync prompt records for snapshot.
841
+
842
+ Uses INSERT ... ON CONFLICT DO NOTHING for idempotent writes.
843
+
844
+ Args:
845
+ conn: Database connection (within transaction).
846
+ snapshot_id: Parent snapshot UUID.
847
+ prompts: List of prompt records.
848
+ """
849
+ if not prompts:
850
+ return
851
+
852
+ # Use executemany with ON CONFLICT for efficiency
853
+ await conn.executemany(
854
+ """
855
+ INSERT INTO claude_session_prompts (
856
+ snapshot_id, prompt_id, emitted_at, prompt_preview,
857
+ prompt_length, detected_intent, causation_id
858
+ ) VALUES ($1, $2, $3, $4, $5, $6, $7)
859
+ ON CONFLICT (snapshot_id, prompt_id) DO NOTHING
860
+ """,
861
+ [
862
+ (
863
+ snapshot_id,
864
+ _ensure_uuid(p["prompt_id"]),
865
+ _ensure_datetime(p["emitted_at"]),
866
+ p.get("prompt_preview"),
867
+ p["prompt_length"],
868
+ p.get("detected_intent"),
869
+ _ensure_uuid(p.get("causation_id")),
870
+ )
871
+ for p in prompts
872
+ ],
873
+ )
874
+
875
+ # ONEX_EXCLUDE: any_type - list[dict[str, Any]] required for JSON-like data
876
+ async def _sync_tools(
877
+ self,
878
+ conn: Connection,
879
+ snapshot_id: UUID,
880
+ tools: list[dict[str, Any]],
881
+ ) -> None:
882
+ """Sync tool records for snapshot.
883
+
884
+ Uses INSERT ... ON CONFLICT DO NOTHING for idempotent writes.
885
+
886
+ Args:
887
+ conn: Database connection (within transaction).
888
+ snapshot_id: Parent snapshot UUID.
889
+ tools: List of tool records.
890
+ """
891
+ if not tools:
892
+ return
893
+
894
+ # Use executemany with ON CONFLICT for efficiency
895
+ await conn.executemany(
896
+ """
897
+ INSERT INTO claude_session_tools (
898
+ snapshot_id, tool_execution_id, emitted_at, tool_name,
899
+ success, duration_ms, summary, causation_id
900
+ ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
901
+ ON CONFLICT (snapshot_id, tool_execution_id) DO NOTHING
902
+ """,
903
+ [
904
+ (
905
+ snapshot_id,
906
+ _ensure_uuid(t["tool_execution_id"]),
907
+ _ensure_datetime(t["emitted_at"]),
908
+ t["tool_name"],
909
+ t["success"],
910
+ t["duration_ms"],
911
+ t.get("summary"),
912
+ _ensure_uuid(t.get("causation_id")),
913
+ )
914
+ for t in tools
915
+ ],
916
+ )
917
+
918
+ # ONEX_EXCLUDE: any_type - list[dict[str, Any]] required for JSON-like data
919
+ async def _fetch_prompts(
920
+ self,
921
+ conn: Connection,
922
+ snapshot_id: UUID,
923
+ ) -> list[dict[str, Any]]:
924
+ """Fetch prompt records for snapshot.
925
+
926
+ Args:
927
+ conn: Database connection.
928
+ snapshot_id: Parent snapshot UUID.
929
+
930
+ Returns:
931
+ List of prompt dicts.
932
+ """
933
+ rows = await conn.fetch(
934
+ """
935
+ SELECT
936
+ id, prompt_id, emitted_at, prompt_preview,
937
+ prompt_length, detected_intent, causation_id
938
+ FROM claude_session_prompts
939
+ WHERE snapshot_id = $1
940
+ ORDER BY emitted_at ASC
941
+ """,
942
+ snapshot_id,
943
+ )
944
+ return [dict(row) for row in rows]
945
+
946
+ # ONEX_EXCLUDE: any_type - list[dict[str, Any]] required for JSON-like data
947
+ async def _fetch_tools(
948
+ self,
949
+ conn: Connection,
950
+ snapshot_id: UUID,
951
+ ) -> list[dict[str, Any]]:
952
+ """Fetch tool records for snapshot.
953
+
954
+ Args:
955
+ conn: Database connection.
956
+ snapshot_id: Parent snapshot UUID.
957
+
958
+ Returns:
959
+ List of tool dicts.
960
+ """
961
+ rows = await conn.fetch(
962
+ """
963
+ SELECT
964
+ id, tool_execution_id, emitted_at, tool_name,
965
+ success, duration_ms, summary, causation_id
966
+ FROM claude_session_tools
967
+ WHERE snapshot_id = $1
968
+ ORDER BY emitted_at ASC
969
+ """,
970
+ snapshot_id,
971
+ )
972
+ return [dict(row) for row in rows]
973
+
974
+ def _parse_row_count(self, result: str) -> int:
975
+ """Parse row count from asyncpg execute result string.
976
+
977
+ asyncpg returns strings like:
978
+ - "INSERT 0 1" -> 1 row inserted
979
+ - "UPDATE 5" -> 5 rows updated
980
+ - "DELETE 3" -> 3 rows deleted
981
+
982
+ Args:
983
+ result: Result string from execute().
984
+
985
+ Returns:
986
+ Number of affected rows.
987
+ """
988
+ try:
989
+ parts = result.split()
990
+ if len(parts) >= 2:
991
+ return int(parts[-1])
992
+ except (ValueError, IndexError):
993
+ pass
994
+ return 0
995
+
996
+
997
+ __all__ = ["SessionSnapshotStore", "SessionStoreNotInitializedError"]