omnibase_infra 0.2.1__py3-none-any.whl → 0.2.3__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 (161) hide show
  1. omnibase_infra/__init__.py +1 -1
  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/commands.py +1 -1
  8. omnibase_infra/configs/widget_mapping.yaml +176 -0
  9. omnibase_infra/contracts/handlers/filesystem/handler_contract.yaml +5 -2
  10. omnibase_infra/contracts/handlers/mcp/handler_contract.yaml +5 -2
  11. omnibase_infra/enums/__init__.py +6 -0
  12. omnibase_infra/enums/enum_handler_error_type.py +10 -0
  13. omnibase_infra/enums/enum_handler_source_mode.py +72 -0
  14. omnibase_infra/enums/enum_kafka_acks.py +99 -0
  15. omnibase_infra/errors/error_compute_registry.py +4 -1
  16. omnibase_infra/errors/error_event_bus_registry.py +4 -1
  17. omnibase_infra/errors/error_infra.py +3 -1
  18. omnibase_infra/errors/error_policy_registry.py +4 -1
  19. omnibase_infra/event_bus/event_bus_kafka.py +1 -1
  20. omnibase_infra/event_bus/models/config/model_kafka_event_bus_config.py +59 -10
  21. omnibase_infra/handlers/__init__.py +8 -1
  22. omnibase_infra/handlers/handler_consul.py +7 -1
  23. omnibase_infra/handlers/handler_db.py +10 -3
  24. omnibase_infra/handlers/handler_graph.py +10 -5
  25. omnibase_infra/handlers/handler_http.py +8 -2
  26. omnibase_infra/handlers/handler_intent.py +387 -0
  27. omnibase_infra/handlers/handler_mcp.py +745 -63
  28. omnibase_infra/handlers/handler_vault.py +11 -5
  29. omnibase_infra/handlers/mixins/mixin_consul_kv.py +4 -3
  30. omnibase_infra/handlers/mixins/mixin_consul_service.py +2 -1
  31. omnibase_infra/handlers/registration_storage/handler_registration_storage_postgres.py +7 -0
  32. omnibase_infra/handlers/service_discovery/handler_service_discovery_consul.py +308 -4
  33. omnibase_infra/handlers/service_discovery/models/model_service_info.py +10 -0
  34. omnibase_infra/mixins/mixin_async_circuit_breaker.py +3 -2
  35. omnibase_infra/mixins/mixin_node_introspection.py +42 -7
  36. omnibase_infra/mixins/mixin_retry_execution.py +1 -1
  37. omnibase_infra/models/discovery/model_introspection_config.py +11 -0
  38. omnibase_infra/models/handlers/__init__.py +48 -5
  39. omnibase_infra/models/handlers/model_bootstrap_handler_descriptor.py +162 -0
  40. omnibase_infra/models/handlers/model_contract_discovery_result.py +6 -4
  41. omnibase_infra/models/handlers/model_handler_descriptor.py +15 -0
  42. omnibase_infra/models/handlers/model_handler_source_config.py +220 -0
  43. omnibase_infra/models/mcp/__init__.py +15 -0
  44. omnibase_infra/models/mcp/model_mcp_contract_config.py +80 -0
  45. omnibase_infra/models/mcp/model_mcp_server_config.py +67 -0
  46. omnibase_infra/models/mcp/model_mcp_tool_definition.py +73 -0
  47. omnibase_infra/models/mcp/model_mcp_tool_parameter.py +35 -0
  48. omnibase_infra/models/registration/model_node_capabilities.py +11 -0
  49. omnibase_infra/models/registration/model_node_introspection_event.py +9 -0
  50. omnibase_infra/models/runtime/model_handler_contract.py +25 -9
  51. omnibase_infra/models/runtime/model_loaded_handler.py +9 -0
  52. omnibase_infra/nodes/architecture_validator/contract_architecture_validator.yaml +0 -5
  53. omnibase_infra/nodes/architecture_validator/registry/registry_infra_architecture_validator.py +17 -10
  54. omnibase_infra/nodes/effects/contract.yaml +0 -5
  55. omnibase_infra/nodes/node_registration_orchestrator/contract.yaml +7 -0
  56. omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_introspected.py +86 -1
  57. omnibase_infra/nodes/node_registration_orchestrator/introspection_event_router.py +3 -3
  58. omnibase_infra/nodes/node_registration_orchestrator/plugin.py +1 -1
  59. omnibase_infra/nodes/node_registration_orchestrator/registry/registry_infra_node_registration_orchestrator.py +9 -8
  60. omnibase_infra/nodes/node_registration_orchestrator/timeout_coordinator.py +4 -3
  61. omnibase_infra/nodes/node_registration_orchestrator/wiring.py +14 -13
  62. omnibase_infra/nodes/node_registration_storage_effect/contract.yaml +0 -5
  63. omnibase_infra/nodes/node_registration_storage_effect/node.py +4 -1
  64. omnibase_infra/nodes/node_registration_storage_effect/registry/registry_infra_registration_storage.py +47 -26
  65. omnibase_infra/nodes/node_registry_effect/contract.yaml +0 -5
  66. omnibase_infra/nodes/node_registry_effect/handlers/handler_partial_retry.py +2 -1
  67. omnibase_infra/nodes/node_service_discovery_effect/registry/registry_infra_service_discovery.py +28 -20
  68. omnibase_infra/plugins/examples/plugin_json_normalizer.py +2 -2
  69. omnibase_infra/plugins/examples/plugin_json_normalizer_error_handling.py +2 -2
  70. omnibase_infra/plugins/plugin_compute_base.py +16 -2
  71. omnibase_infra/protocols/__init__.py +2 -0
  72. omnibase_infra/protocols/protocol_container_aware.py +200 -0
  73. omnibase_infra/protocols/protocol_event_projector.py +1 -1
  74. omnibase_infra/runtime/__init__.py +90 -1
  75. omnibase_infra/runtime/binding_config_resolver.py +102 -37
  76. omnibase_infra/runtime/constants_notification.py +75 -0
  77. omnibase_infra/runtime/contract_handler_discovery.py +6 -1
  78. omnibase_infra/runtime/handler_bootstrap_source.py +507 -0
  79. omnibase_infra/runtime/handler_contract_config_loader.py +603 -0
  80. omnibase_infra/runtime/handler_contract_source.py +267 -186
  81. omnibase_infra/runtime/handler_identity.py +81 -0
  82. omnibase_infra/runtime/handler_plugin_loader.py +19 -2
  83. omnibase_infra/runtime/handler_registry.py +11 -3
  84. omnibase_infra/runtime/handler_source_resolver.py +326 -0
  85. omnibase_infra/runtime/mixin_semver_cache.py +25 -1
  86. omnibase_infra/runtime/mixins/__init__.py +7 -0
  87. omnibase_infra/runtime/mixins/mixin_projector_notification_publishing.py +566 -0
  88. omnibase_infra/runtime/mixins/mixin_projector_sql_operations.py +31 -10
  89. omnibase_infra/runtime/models/__init__.py +24 -0
  90. omnibase_infra/runtime/models/model_health_check_result.py +2 -1
  91. omnibase_infra/runtime/models/model_projector_notification_config.py +171 -0
  92. omnibase_infra/runtime/models/model_transition_notification_outbox_config.py +112 -0
  93. omnibase_infra/runtime/models/model_transition_notification_outbox_metrics.py +140 -0
  94. omnibase_infra/runtime/models/model_transition_notification_publisher_metrics.py +357 -0
  95. omnibase_infra/runtime/projector_plugin_loader.py +1 -1
  96. omnibase_infra/runtime/projector_shell.py +229 -1
  97. omnibase_infra/runtime/protocol_lifecycle_executor.py +6 -6
  98. omnibase_infra/runtime/protocols/__init__.py +10 -0
  99. omnibase_infra/runtime/registry/registry_protocol_binding.py +16 -15
  100. omnibase_infra/runtime/registry_contract_source.py +693 -0
  101. omnibase_infra/runtime/registry_policy.py +9 -326
  102. omnibase_infra/runtime/secret_resolver.py +4 -2
  103. omnibase_infra/runtime/service_kernel.py +11 -3
  104. omnibase_infra/runtime/service_message_dispatch_engine.py +4 -2
  105. omnibase_infra/runtime/service_runtime_host_process.py +589 -106
  106. omnibase_infra/runtime/transition_notification_outbox.py +1190 -0
  107. omnibase_infra/runtime/transition_notification_publisher.py +764 -0
  108. omnibase_infra/runtime/util_container_wiring.py +6 -5
  109. omnibase_infra/runtime/util_wiring.py +17 -4
  110. omnibase_infra/schemas/schema_transition_notification_outbox.sql +245 -0
  111. omnibase_infra/services/__init__.py +21 -0
  112. omnibase_infra/services/corpus_capture.py +7 -1
  113. omnibase_infra/services/mcp/__init__.py +31 -0
  114. omnibase_infra/services/mcp/mcp_server_lifecycle.py +449 -0
  115. omnibase_infra/services/mcp/service_mcp_tool_discovery.py +411 -0
  116. omnibase_infra/services/mcp/service_mcp_tool_registry.py +329 -0
  117. omnibase_infra/services/mcp/service_mcp_tool_sync.py +547 -0
  118. omnibase_infra/services/registry_api/__init__.py +40 -0
  119. omnibase_infra/services/registry_api/main.py +261 -0
  120. omnibase_infra/services/registry_api/models/__init__.py +66 -0
  121. omnibase_infra/services/registry_api/models/model_capability_widget_mapping.py +38 -0
  122. omnibase_infra/services/registry_api/models/model_pagination_info.py +48 -0
  123. omnibase_infra/services/registry_api/models/model_registry_discovery_response.py +73 -0
  124. omnibase_infra/services/registry_api/models/model_registry_health_response.py +49 -0
  125. omnibase_infra/services/registry_api/models/model_registry_instance_view.py +88 -0
  126. omnibase_infra/services/registry_api/models/model_registry_node_view.py +88 -0
  127. omnibase_infra/services/registry_api/models/model_registry_summary.py +60 -0
  128. omnibase_infra/services/registry_api/models/model_response_list_instances.py +43 -0
  129. omnibase_infra/services/registry_api/models/model_response_list_nodes.py +51 -0
  130. omnibase_infra/services/registry_api/models/model_warning.py +49 -0
  131. omnibase_infra/services/registry_api/models/model_widget_defaults.py +28 -0
  132. omnibase_infra/services/registry_api/models/model_widget_mapping.py +51 -0
  133. omnibase_infra/services/registry_api/routes.py +371 -0
  134. omnibase_infra/services/registry_api/service.py +837 -0
  135. omnibase_infra/services/service_capability_query.py +4 -4
  136. omnibase_infra/services/service_health.py +3 -2
  137. omnibase_infra/services/service_timeout_emitter.py +20 -3
  138. omnibase_infra/services/service_timeout_scanner.py +7 -3
  139. omnibase_infra/services/session/__init__.py +56 -0
  140. omnibase_infra/services/session/config_consumer.py +120 -0
  141. omnibase_infra/services/session/config_store.py +139 -0
  142. omnibase_infra/services/session/consumer.py +1007 -0
  143. omnibase_infra/services/session/protocol_session_aggregator.py +117 -0
  144. omnibase_infra/services/session/store.py +997 -0
  145. omnibase_infra/utils/__init__.py +19 -0
  146. omnibase_infra/utils/util_atomic_file.py +261 -0
  147. omnibase_infra/utils/util_db_transaction.py +239 -0
  148. omnibase_infra/utils/util_dsn_validation.py +1 -1
  149. omnibase_infra/utils/util_retry_optimistic.py +281 -0
  150. omnibase_infra/validation/__init__.py +3 -19
  151. omnibase_infra/validation/contracts/security.validation.yaml +114 -0
  152. omnibase_infra/validation/infra_validators.py +35 -24
  153. omnibase_infra/validation/validation_exemptions.yaml +140 -9
  154. omnibase_infra/validation/validator_chain_propagation.py +2 -2
  155. omnibase_infra/validation/validator_runtime_shape.py +1 -1
  156. omnibase_infra/validation/validator_security.py +473 -370
  157. {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.3.dist-info}/METADATA +3 -3
  158. {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.3.dist-info}/RECORD +161 -98
  159. {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.3.dist-info}/WHEEL +0 -0
  160. {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.3.dist-info}/entry_points.txt +0 -0
  161. {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.3.dist-info}/licenses/LICENSE +0 -0
@@ -54,6 +54,7 @@ from __future__ import annotations
54
54
  import logging
55
55
  from typing import TYPE_CHECKING
56
56
 
57
+ from omnibase_core.enums import EnumInjectionScope
57
58
  from omnibase_core.models.primitives import ModelSemVer
58
59
  from omnibase_infra.enums import EnumInfraTransportType
59
60
  from omnibase_infra.errors import (
@@ -257,7 +258,7 @@ async def wire_infrastructure_services(
257
258
  await container.service_registry.register_instance(
258
259
  interface=RegistryPolicy,
259
260
  instance=policy_registry,
260
- scope="global",
261
+ scope=EnumInjectionScope.GLOBAL,
261
262
  metadata={
262
263
  "description": "ONEX policy plugin registry",
263
264
  "version": str(SEMVER_DEFAULT),
@@ -274,7 +275,7 @@ async def wire_infrastructure_services(
274
275
  await container.service_registry.register_instance(
275
276
  interface=RegistryProtocolBinding,
276
277
  instance=handler_registry,
277
- scope="global",
278
+ scope=EnumInjectionScope.GLOBAL,
278
279
  metadata={
279
280
  "description": "ONEX protocol handler binding registry",
280
281
  "version": str(SEMVER_DEFAULT),
@@ -291,7 +292,7 @@ async def wire_infrastructure_services(
291
292
  await container.service_registry.register_instance(
292
293
  interface=RegistryCompute,
293
294
  instance=compute_registry,
294
- scope="global",
295
+ scope=EnumInjectionScope.GLOBAL,
295
296
  metadata={
296
297
  "description": "ONEX compute plugin registry",
297
298
  "version": str(SEMVER_DEFAULT),
@@ -530,7 +531,7 @@ async def get_or_create_policy_registry(
530
531
  await container.service_registry.register_instance(
531
532
  interface=RegistryPolicy,
532
533
  instance=policy_registry,
533
- scope="global",
534
+ scope=EnumInjectionScope.GLOBAL,
534
535
  metadata={
535
536
  "description": "ONEX policy plugin registry (auto-registered)",
536
537
  "version": str(SEMVER_DEFAULT),
@@ -804,7 +805,7 @@ async def get_or_create_compute_registry(
804
805
  await container.service_registry.register_instance(
805
806
  interface=RegistryCompute,
806
807
  instance=compute_registry,
807
- scope="global",
808
+ scope=EnumInjectionScope.GLOBAL,
808
809
  metadata={
809
810
  "description": "ONEX compute plugin registry (auto-registered)",
810
811
  "version": str(SEMVER_DEFAULT),
@@ -121,13 +121,19 @@ from omnibase_infra.errors import ModelInfraErrorContext, ProtocolConfigurationE
121
121
  from omnibase_infra.event_bus.event_bus_inmemory import EventBusInmemory
122
122
  from omnibase_infra.handlers.handler_consul import HandlerConsul
123
123
  from omnibase_infra.handlers.handler_db import HandlerDb
124
+ from omnibase_infra.handlers.handler_graph import HandlerGraph
124
125
  from omnibase_infra.handlers.handler_http import HandlerHttpRest
126
+ from omnibase_infra.handlers.handler_intent import HandlerIntent
127
+ from omnibase_infra.handlers.handler_mcp import HandlerMCP
125
128
  from omnibase_infra.handlers.handler_vault import HandlerVault
126
129
  from omnibase_infra.runtime.handler_registry import (
127
130
  EVENT_BUS_INMEMORY,
128
131
  HANDLER_TYPE_CONSUL,
129
132
  HANDLER_TYPE_DATABASE,
133
+ HANDLER_TYPE_GRAPH,
130
134
  HANDLER_TYPE_HTTP,
135
+ HANDLER_TYPE_INTENT,
136
+ HANDLER_TYPE_MCP,
131
137
  HANDLER_TYPE_VAULT,
132
138
  RegistryEventBusBinding,
133
139
  RegistryProtocolBinding,
@@ -137,7 +143,7 @@ from omnibase_infra.runtime.handler_registry import (
137
143
 
138
144
  if TYPE_CHECKING:
139
145
  from omnibase_core.protocol.protocol_event_bus import ProtocolEventBus
140
- from omnibase_spi.protocols.handlers.protocol_handler import ProtocolHandler
146
+ from omnibase_infra.protocols import ProtocolContainerAware
141
147
 
142
148
  logger = logging.getLogger(__name__)
143
149
 
@@ -164,11 +170,15 @@ logger = logging.getLogger(__name__)
164
170
  # NOTE: HandlerHttpRest and HandlerDb use legacy execute(envelope: dict) signature.
165
171
  # They will be migrated to ProtocolHandler.execute(request, operation_config) in future.
166
172
  # Type ignore comments suppress MyPy errors during MVP phase.
167
- _KNOWN_HANDLERS: dict[str, tuple[type[ProtocolHandler], str]] = {
173
+ _KNOWN_HANDLERS: dict[str, tuple[type[ProtocolContainerAware], str]] = {
168
174
  # NOTE: Handlers implement ProtocolHandler structurally but concrete types differ from protocol.
169
175
  HANDLER_TYPE_CONSUL: (HandlerConsul, "HashiCorp Consul service discovery handler"), # type: ignore[dict-item] # NOTE: structural subtyping
170
176
  HANDLER_TYPE_DATABASE: (HandlerDb, "PostgreSQL database handler"), # type: ignore[dict-item] # NOTE: structural subtyping
177
+ HANDLER_TYPE_GRAPH: (HandlerGraph, "Graph database (Memgraph/Neo4j) handler"), # type: ignore[dict-item] # NOTE: structural subtyping
171
178
  HANDLER_TYPE_HTTP: (HandlerHttpRest, "HTTP REST protocol handler"), # type: ignore[dict-item] # NOTE: structural subtyping
179
+ # DEMO: Temporary registration - remove when contract-driven (OMN-1515)
180
+ HANDLER_TYPE_INTENT: (HandlerIntent, "Intent storage and query handler for demo"), # type: ignore[dict-item] # NOTE: structural subtyping
181
+ HANDLER_TYPE_MCP: (HandlerMCP, "Model Context Protocol handler for AI agents"), # type: ignore[dict-item] # NOTE: structural subtyping
172
182
  HANDLER_TYPE_VAULT: (HandlerVault, "HashiCorp Vault secret management handler"), # type: ignore[dict-item] # NOTE: structural subtyping
173
183
  }
174
184
 
@@ -194,7 +204,10 @@ def wire_default_handlers() -> dict[str, list[str]]:
194
204
  Registered Handlers:
195
205
  - CONSUL: HandlerConsul for HashiCorp Consul service discovery
196
206
  - DB: HandlerDb for PostgreSQL database operations
207
+ - GRAPH: HandlerGraph for graph database (Memgraph/Neo4j) operations
197
208
  - HTTP: HandlerHttpRest for HTTP/REST protocol operations
209
+ - INTENT: HandlerIntent for intent storage and query (demo)
210
+ - MCP: HandlerMCP for Model Context Protocol AI agent integration
198
211
  - VAULT: HandlerVault for HashiCorp Vault secret management
199
212
 
200
213
  Registered Event Buses:
@@ -217,7 +230,7 @@ def wire_default_handlers() -> dict[str, list[str]]:
217
230
  Example:
218
231
  >>> summary = wire_default_handlers()
219
232
  >>> print(summary)
220
- {'handlers': ['consul', 'db', 'http', 'vault'], 'event_buses': ['inmemory']}
233
+ {'handlers': ['consul', 'db', 'http', 'mcp', 'vault'], 'event_buses': ['inmemory']}
221
234
 
222
235
  Note:
223
236
  This function uses the singleton registries returned by
@@ -483,7 +496,7 @@ def get_known_event_bus_kinds() -> list[str]:
483
496
 
484
497
  def wire_custom_handler(
485
498
  handler_type: str,
486
- handler_cls: type[ProtocolHandler],
499
+ handler_cls: type[ProtocolContainerAware],
487
500
  registry: RegistryProtocolBinding | None = None,
488
501
  ) -> None:
489
502
  """Register a custom handler class with the registry.
@@ -0,0 +1,245 @@
1
+ -- SPDX-License-Identifier: MIT
2
+ -- Copyright (c) 2025 OmniNode Team
3
+ --
4
+ -- Transition Notification Outbox Schema
5
+ -- Ticket: OMN-1139 (TransitionNotificationOutbox implementation)
6
+ -- Version: 1.0.0
7
+ --
8
+ -- Design Notes:
9
+ -- - Implements the outbox pattern for guaranteed notification delivery
10
+ -- - Stores notifications in same transaction as projections for atomicity
11
+ -- - Supports concurrent processing via SELECT FOR UPDATE SKIP LOCKED
12
+ -- - Includes retry tracking with error recording
13
+ -- - Indexes optimized for processor query patterns:
14
+ -- 1. Pending notification queries (processed_at IS NULL)
15
+ -- 2. Aggregate-specific queries (aggregate_type, aggregate_id)
16
+ -- 3. Retry processing (high retry counts for monitoring)
17
+ -- 4. Cleanup of old processed records
18
+ -- - All timestamps are timezone-aware (TIMESTAMPTZ)
19
+ -- - This schema is idempotent (IF NOT EXISTS used throughout)
20
+ --
21
+ -- Usage:
22
+ -- Execute this SQL file to create or update the outbox schema.
23
+ -- The schema is designed to be re-run safely (idempotent).
24
+ --
25
+ -- Related:
26
+ -- - TransitionNotificationOutbox: src/omnibase_infra/runtime/transition_notification_outbox.py
27
+ -- - ModelStateTransitionNotification: omnibase_core.models.notifications
28
+ -- - ProtocolTransitionNotificationPublisher: omnibase_core.protocols.notifications
29
+
30
+ -- =============================================================================
31
+ -- MAIN TABLE
32
+ -- =============================================================================
33
+
34
+ CREATE TABLE IF NOT EXISTS transition_notification_outbox (
35
+ -- Identity
36
+ id BIGSERIAL PRIMARY KEY,
37
+
38
+ -- Notification Payload (serialized ModelStateTransitionNotification)
39
+ notification_data JSONB NOT NULL,
40
+
41
+ -- Timestamps
42
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
43
+ -- processed_at encodes both "pending" and "processed" states in a single column:
44
+ -- NULL = pending (not yet processed, eligible for processing)
45
+ -- non-NULL = processed (successfully published, timestamp of completion)
46
+ -- Note: No separate "processed_implies_no_pending" constraint is needed because
47
+ -- the single-column semantic makes the states mutually exclusive by design -
48
+ -- a row cannot be both pending (NULL) and processed (non-NULL) simultaneously.
49
+ processed_at TIMESTAMPTZ,
50
+
51
+ -- Retry Tracking
52
+ retry_count INT NOT NULL DEFAULT 0,
53
+ last_error TEXT, -- Most recent error message (sanitized, max 1000 chars)
54
+
55
+ -- Aggregate Information (for queries and debugging)
56
+ aggregate_type TEXT NOT NULL,
57
+ aggregate_id UUID NOT NULL,
58
+
59
+ -- Constraints
60
+ CONSTRAINT valid_retry_count CHECK (retry_count >= 0)
61
+ );
62
+
63
+ -- =============================================================================
64
+ -- INDEXES FOR OUTBOX PROCESSING
65
+ -- =============================================================================
66
+
67
+ -- Index for efficient pending notification queries (PRIMARY query pattern)
68
+ -- The processor uses: SELECT ... WHERE processed_at IS NULL ORDER BY created_at
69
+ -- Partial index: only index rows with NULL processed_at (pending notifications)
70
+ -- Query pattern: SELECT id, notification_data FROM transition_notification_outbox
71
+ -- WHERE processed_at IS NULL ORDER BY created_at LIMIT :batch_size
72
+ -- FOR UPDATE SKIP LOCKED
73
+ CREATE INDEX IF NOT EXISTS idx_outbox_pending
74
+ ON transition_notification_outbox (created_at)
75
+ WHERE processed_at IS NULL;
76
+
77
+ -- Index for aggregate-specific queries (debugging and monitoring)
78
+ -- Enables queries like "show all notifications for entity X"
79
+ -- Query pattern: SELECT * FROM transition_notification_outbox
80
+ -- WHERE aggregate_type = :type AND aggregate_id = :id
81
+ CREATE INDEX IF NOT EXISTS idx_outbox_aggregate
82
+ ON transition_notification_outbox (aggregate_type, aggregate_id);
83
+
84
+ -- Index for retry monitoring (identify stuck/failing notifications)
85
+ -- Partial index: only pending notifications with retries
86
+ -- Query pattern: SELECT * FROM transition_notification_outbox
87
+ -- WHERE processed_at IS NULL AND retry_count > :threshold
88
+ CREATE INDEX IF NOT EXISTS idx_outbox_retry_pending
89
+ ON transition_notification_outbox (retry_count, created_at)
90
+ WHERE processed_at IS NULL AND retry_count > 0;
91
+
92
+ -- Index for cleanup queries (delete old processed records)
93
+ -- Enables efficient deletion of processed records older than a threshold
94
+ -- Query pattern: DELETE FROM transition_notification_outbox
95
+ -- WHERE processed_at IS NOT NULL AND processed_at < :cutoff_time
96
+ CREATE INDEX IF NOT EXISTS idx_outbox_cleanup
97
+ ON transition_notification_outbox (processed_at)
98
+ WHERE processed_at IS NOT NULL;
99
+
100
+ -- Index for aggregate type filtering with pending status
101
+ -- Useful for monitoring specific aggregate types
102
+ -- Query pattern: SELECT COUNT(*) FROM transition_notification_outbox
103
+ -- WHERE aggregate_type = :type AND processed_at IS NULL
104
+ CREATE INDEX IF NOT EXISTS idx_outbox_aggregate_type_pending
105
+ ON transition_notification_outbox (aggregate_type)
106
+ WHERE processed_at IS NULL;
107
+
108
+ -- =============================================================================
109
+ -- TABLE AND COLUMN COMMENTS
110
+ -- =============================================================================
111
+
112
+ COMMENT ON TABLE transition_notification_outbox IS
113
+ 'Outbox pattern table for guaranteed state transition notification delivery (OMN-1139). '
114
+ 'Stores notifications in same transaction as projections for atomicity. '
115
+ 'Background processor publishes pending notifications asynchronously.';
116
+
117
+ COMMENT ON COLUMN transition_notification_outbox.id IS
118
+ 'Auto-incrementing primary key. Used for efficient row locking with FOR UPDATE SKIP LOCKED.';
119
+
120
+ COMMENT ON COLUMN transition_notification_outbox.notification_data IS
121
+ 'Serialized ModelStateTransitionNotification as JSONB. Contains all notification fields: '
122
+ 'aggregate_type, aggregate_id, transition (from_state, to_state, event_type), '
123
+ 'correlation_id, timestamp, and optional metadata.';
124
+
125
+ COMMENT ON COLUMN transition_notification_outbox.created_at IS
126
+ 'Timestamp when notification was stored in outbox. Used for FIFO ordering of pending notifications.';
127
+
128
+ COMMENT ON COLUMN transition_notification_outbox.processed_at IS
129
+ 'Timestamp when notification was successfully published. NULL indicates pending status.';
130
+
131
+ COMMENT ON COLUMN transition_notification_outbox.retry_count IS
132
+ 'Number of failed publish attempts. Incremented on each failure, not reset on success. '
133
+ 'Use for monitoring and alerting on stuck notifications.';
134
+
135
+ COMMENT ON COLUMN transition_notification_outbox.last_error IS
136
+ 'Most recent error message from failed publish attempt (sanitized, max 1000 chars). '
137
+ 'Updated on each failure for debugging. May contain value even when processed_at is set '
138
+ 'if earlier retries failed before final success.';
139
+
140
+ COMMENT ON COLUMN transition_notification_outbox.aggregate_type IS
141
+ 'Type of aggregate this notification is for (e.g., "registration", "workflow"). '
142
+ 'Denormalized from notification_data for efficient indexing and filtering.';
143
+
144
+ COMMENT ON COLUMN transition_notification_outbox.aggregate_id IS
145
+ 'UUID of the aggregate entity this notification is for. '
146
+ 'Denormalized from notification_data for efficient indexing and aggregate-specific queries.';
147
+
148
+ -- =============================================================================
149
+ -- INDEX STRATEGY DOCUMENTATION
150
+ -- =============================================================================
151
+ --
152
+ -- This schema defines multiple indexes optimized for different query patterns
153
+ -- used by the TransitionNotificationOutbox processor and operators.
154
+ --
155
+ -- PENDING NOTIFICATION PROCESSING:
156
+ -- --------------------------------
157
+ -- 1. idx_outbox_pending:
158
+ -- - Single-column index on created_at
159
+ -- - WHERE: processed_at IS NULL
160
+ -- - Use case: Main processor query - fetch pending notifications in FIFO order
161
+ -- - Critical for: process_pending() batch retrieval
162
+ --
163
+ -- The partial WHERE clause keeps this index small and fast by excluding
164
+ -- all processed records.
165
+ --
166
+ -- AGGREGATE QUERIES (Debugging):
167
+ -- ------------------------------
168
+ -- 2. idx_outbox_aggregate:
169
+ -- - Composite index on (aggregate_type, aggregate_id)
170
+ -- - Use case: Query notifications for a specific entity
171
+ -- - Example: "Show all notifications for registration entity X"
172
+ --
173
+ -- RETRY MONITORING:
174
+ -- -----------------
175
+ -- 3. idx_outbox_retry_pending:
176
+ -- - Composite index on (retry_count, created_at)
177
+ -- - WHERE: processed_at IS NULL AND retry_count > 0
178
+ -- - Use case: Identify stuck or failing notifications
179
+ -- - Example: Alert when retry_count > 5 for pending notifications
180
+ --
181
+ -- CLEANUP OPERATIONS:
182
+ -- -------------------
183
+ -- 4. idx_outbox_cleanup:
184
+ -- - Single-column index on processed_at
185
+ -- - WHERE: processed_at IS NOT NULL
186
+ -- - Use case: Efficient deletion of old processed records
187
+ -- - Example: DELETE ... WHERE processed_at < NOW() - INTERVAL '7 days'
188
+ --
189
+ -- TYPE-SPECIFIC MONITORING:
190
+ -- -------------------------
191
+ -- 5. idx_outbox_aggregate_type_pending:
192
+ -- - Single-column index on aggregate_type
193
+ -- - WHERE: processed_at IS NULL
194
+ -- - Use case: Count pending notifications by type for monitoring dashboards
195
+ --
196
+ -- =============================================================================
197
+ -- CONCURRENT PROCESSING PATTERN
198
+ -- =============================================================================
199
+ --
200
+ -- The outbox processor uses SELECT FOR UPDATE SKIP LOCKED to enable safe
201
+ -- concurrent processing by multiple instances:
202
+ --
203
+ -- SELECT id, notification_data
204
+ -- FROM transition_notification_outbox
205
+ -- WHERE processed_at IS NULL
206
+ -- ORDER BY created_at
207
+ -- LIMIT :batch_size
208
+ -- FOR UPDATE SKIP LOCKED;
209
+ --
210
+ -- SKIP LOCKED ensures that if another processor has locked a row, this query
211
+ -- skips it rather than blocking. This prevents:
212
+ -- - Duplicate processing
213
+ -- - Deadlocks between processors
214
+ -- - Head-of-line blocking
215
+ --
216
+ -- The id column (BIGSERIAL PRIMARY KEY) provides an efficient row lock target.
217
+ --
218
+ -- =============================================================================
219
+ -- CLEANUP RECOMMENDATIONS
220
+ -- =============================================================================
221
+ --
222
+ -- Processed records should be periodically deleted to prevent table bloat.
223
+ -- Recommended cleanup query (run periodically via cron or pg_cron):
224
+ --
225
+ -- DELETE FROM transition_notification_outbox
226
+ -- WHERE processed_at IS NOT NULL
227
+ -- AND processed_at < NOW() - INTERVAL '7 days';
228
+ --
229
+ -- Alternatively, implement as a PostgreSQL function:
230
+ --
231
+ -- CREATE OR REPLACE FUNCTION cleanup_outbox(retention_interval INTERVAL)
232
+ -- RETURNS BIGINT AS $$
233
+ -- DECLARE
234
+ -- deleted_count BIGINT;
235
+ -- BEGIN
236
+ -- DELETE FROM transition_notification_outbox
237
+ -- WHERE processed_at IS NOT NULL
238
+ -- AND processed_at < NOW() - retention_interval;
239
+ -- GET DIAGNOSTICS deleted_count = ROW_COUNT;
240
+ -- RETURN deleted_count;
241
+ -- END;
242
+ -- $$ LANGUAGE plpgsql;
243
+ --
244
+ -- Usage: SELECT cleanup_outbox(INTERVAL '7 days');
245
+ --
@@ -39,6 +39,18 @@ from omnibase_infra.services.service_timeout_scanner import (
39
39
  ModelTimeoutQueryResult,
40
40
  ServiceTimeoutScanner,
41
41
  )
42
+
43
+ # Session services (moved from omniclaude in OMN-1526)
44
+ from omnibase_infra.services.session import (
45
+ ConfigSessionConsumer,
46
+ ConfigSessionStorage,
47
+ ConsumerMetrics,
48
+ EnumCircuitState,
49
+ ProtocolSessionAggregator,
50
+ SessionEventConsumer,
51
+ SessionSnapshotStore,
52
+ SessionStoreNotInitializedError,
53
+ )
42
54
  from omnibase_infra.services.snapshot import (
43
55
  ServiceSnapshot,
44
56
  StoreSnapshotInMemory,
@@ -65,4 +77,13 @@ __all__ = [
65
77
  "StoreSnapshotPostgres",
66
78
  "TimeoutEmitter",
67
79
  "TimeoutScanner",
80
+ # Session services (OMN-1526)
81
+ "ConfigSessionConsumer",
82
+ "ConfigSessionStorage",
83
+ "ConsumerMetrics",
84
+ "EnumCircuitState",
85
+ "ProtocolSessionAggregator",
86
+ "SessionEventConsumer",
87
+ "SessionSnapshotStore",
88
+ "SessionStoreNotInitializedError",
68
89
  ]
@@ -22,6 +22,7 @@ from datetime import UTC, datetime
22
22
  from typing import Protocol
23
23
  from uuid import UUID
24
24
 
25
+ from omnibase_core.container import ModelONEXContainer
25
26
  from omnibase_core.enums import EnumCoreErrorCode
26
27
  from omnibase_core.errors import OnexError
27
28
  from omnibase_core.models.manifest.model_execution_manifest import (
@@ -226,13 +227,15 @@ class CorpusCapture:
226
227
  - Max executions enforcement with automatic state transitions
227
228
 
228
229
  Example:
230
+ >>> from omnibase_core.container import ModelONEXContainer
231
+ >>> container = ModelONEXContainer(...) # Configure as needed
229
232
  >>> config = ModelCaptureConfig(
230
233
  ... corpus_display_name="regression-suite-v1",
231
234
  ... max_executions=50,
232
235
  ... sample_rate=0.5,
233
236
  ... handler_filter=("compute-handler",),
234
237
  ... )
235
- >>> service = CorpusCapture()
238
+ >>> service = CorpusCapture(container)
236
239
  >>> service.create_corpus(config)
237
240
  >>> service.start_capture()
238
241
  >>>
@@ -249,17 +252,20 @@ class CorpusCapture:
249
252
 
250
253
  def __init__(
251
254
  self,
255
+ container: ModelONEXContainer,
252
256
  persistence: ProtocolManifestPersistence | None = None,
253
257
  ) -> None:
254
258
  """
255
259
  Initialize the corpus capture service.
256
260
 
257
261
  Args:
262
+ container: ONEX container for dependency injection.
258
263
  persistence: Optional persistence handler for flushing manifests.
259
264
  If provided, manifests can be persisted via flush_to_persistence()
260
265
  or by calling close_corpus_async(flush=True). The synchronous
261
266
  close_corpus() does NOT automatically flush.
262
267
  """
268
+ self._container = container
263
269
  self._state_machine = CaptureLifecycleFSM()
264
270
  self._config: ModelCaptureConfig | None = None
265
271
  self._corpus: ModelExecutionCorpus | None = None
@@ -0,0 +1,31 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2025 OmniNode Team
3
+ """MCP services for Model Context Protocol integration.
4
+
5
+ This package provides services for exposing ONEX orchestrator nodes
6
+ as MCP tools for AI agent integration.
7
+
8
+ Services:
9
+ ServiceMCPToolRegistry: Event-loop safe in-memory cache of tool definitions
10
+ ServiceMCPToolDiscovery: Consul scanner for MCP-enabled orchestrators
11
+ ServiceMCPToolSync: Kafka listener for hot reload with idempotency
12
+ MCPServerLifecycle: Server lifecycle management
13
+ """
14
+
15
+ from omnibase_infra.services.mcp.mcp_server_lifecycle import (
16
+ MCPServerLifecycle,
17
+ ModelMCPServerConfig,
18
+ )
19
+ from omnibase_infra.services.mcp.service_mcp_tool_discovery import (
20
+ ServiceMCPToolDiscovery,
21
+ )
22
+ from omnibase_infra.services.mcp.service_mcp_tool_registry import ServiceMCPToolRegistry
23
+ from omnibase_infra.services.mcp.service_mcp_tool_sync import ServiceMCPToolSync
24
+
25
+ __all__ = [
26
+ "MCPServerLifecycle",
27
+ "ModelMCPServerConfig",
28
+ "ServiceMCPToolDiscovery",
29
+ "ServiceMCPToolRegistry",
30
+ "ServiceMCPToolSync",
31
+ ]