omnibase_infra 0.3.1__py3-none-any.whl → 0.4.0__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 (117) hide show
  1. omnibase_infra/__init__.py +1 -1
  2. omnibase_infra/enums/__init__.py +3 -0
  3. omnibase_infra/enums/enum_consumer_group_purpose.py +9 -0
  4. omnibase_infra/enums/enum_postgres_error_code.py +188 -0
  5. omnibase_infra/errors/__init__.py +4 -0
  6. omnibase_infra/errors/error_infra.py +60 -0
  7. omnibase_infra/handlers/__init__.py +3 -0
  8. omnibase_infra/handlers/handler_slack_webhook.py +426 -0
  9. omnibase_infra/handlers/models/__init__.py +14 -0
  10. omnibase_infra/handlers/models/enum_alert_severity.py +36 -0
  11. omnibase_infra/handlers/models/model_slack_alert.py +24 -0
  12. omnibase_infra/handlers/models/model_slack_alert_payload.py +77 -0
  13. omnibase_infra/handlers/models/model_slack_alert_result.py +73 -0
  14. omnibase_infra/handlers/registration_storage/handler_registration_storage_postgres.py +29 -20
  15. omnibase_infra/mixins/__init__.py +14 -0
  16. omnibase_infra/mixins/mixin_node_introspection.py +42 -20
  17. omnibase_infra/mixins/mixin_postgres_error_response.py +314 -0
  18. omnibase_infra/mixins/mixin_postgres_op_executor.py +298 -0
  19. omnibase_infra/models/__init__.py +3 -0
  20. omnibase_infra/models/discovery/model_dependency_spec.py +1 -0
  21. omnibase_infra/models/discovery/model_discovered_capabilities.py +1 -1
  22. omnibase_infra/models/discovery/model_introspection_config.py +28 -1
  23. omnibase_infra/models/discovery/model_introspection_performance_metrics.py +1 -0
  24. omnibase_infra/models/discovery/model_introspection_task_config.py +1 -0
  25. omnibase_infra/{nodes/effects/models → models}/model_backend_result.py +22 -6
  26. omnibase_infra/models/projection/__init__.py +11 -0
  27. omnibase_infra/models/projection/model_contract_projection.py +170 -0
  28. omnibase_infra/models/projection/model_topic_projection.py +148 -0
  29. omnibase_infra/models/runtime/__init__.py +4 -0
  30. omnibase_infra/models/runtime/model_resolved_dependencies.py +116 -0
  31. omnibase_infra/nodes/contract_registry_reducer/__init__.py +5 -0
  32. omnibase_infra/nodes/contract_registry_reducer/contract.yaml +6 -5
  33. omnibase_infra/nodes/contract_registry_reducer/contract_registration_event_router.py +689 -0
  34. omnibase_infra/nodes/contract_registry_reducer/reducer.py +9 -26
  35. omnibase_infra/nodes/effects/__init__.py +1 -1
  36. omnibase_infra/nodes/effects/models/__init__.py +6 -4
  37. omnibase_infra/nodes/effects/models/model_registry_response.py +1 -1
  38. omnibase_infra/nodes/effects/protocol_consul_client.py +1 -1
  39. omnibase_infra/nodes/effects/protocol_postgres_adapter.py +1 -1
  40. omnibase_infra/nodes/effects/registry_effect.py +1 -1
  41. omnibase_infra/nodes/node_contract_persistence_effect/__init__.py +101 -0
  42. omnibase_infra/nodes/node_contract_persistence_effect/contract.yaml +490 -0
  43. omnibase_infra/nodes/node_contract_persistence_effect/handlers/__init__.py +74 -0
  44. omnibase_infra/nodes/node_contract_persistence_effect/handlers/handler_postgres_cleanup_topics.py +217 -0
  45. omnibase_infra/nodes/node_contract_persistence_effect/handlers/handler_postgres_contract_upsert.py +242 -0
  46. omnibase_infra/nodes/node_contract_persistence_effect/handlers/handler_postgres_deactivate.py +194 -0
  47. omnibase_infra/nodes/node_contract_persistence_effect/handlers/handler_postgres_heartbeat.py +243 -0
  48. omnibase_infra/nodes/node_contract_persistence_effect/handlers/handler_postgres_mark_stale.py +208 -0
  49. omnibase_infra/nodes/node_contract_persistence_effect/handlers/handler_postgres_topic_update.py +298 -0
  50. omnibase_infra/nodes/node_contract_persistence_effect/models/__init__.py +15 -0
  51. omnibase_infra/nodes/node_contract_persistence_effect/models/model_persistence_result.py +52 -0
  52. omnibase_infra/nodes/node_contract_persistence_effect/node.py +131 -0
  53. omnibase_infra/nodes/node_contract_persistence_effect/registry/__init__.py +27 -0
  54. omnibase_infra/nodes/node_contract_persistence_effect/registry/registry_infra_contract_persistence_effect.py +251 -0
  55. omnibase_infra/nodes/node_registration_orchestrator/models/model_postgres_intent_payload.py +8 -12
  56. omnibase_infra/nodes/node_registry_effect/models/__init__.py +2 -2
  57. omnibase_infra/nodes/node_slack_alerter_effect/__init__.py +33 -0
  58. omnibase_infra/nodes/node_slack_alerter_effect/contract.yaml +291 -0
  59. omnibase_infra/nodes/node_slack_alerter_effect/node.py +106 -0
  60. omnibase_infra/projectors/__init__.py +6 -0
  61. omnibase_infra/projectors/projection_reader_contract.py +1301 -0
  62. omnibase_infra/runtime/__init__.py +12 -0
  63. omnibase_infra/runtime/baseline_subscriptions.py +13 -6
  64. omnibase_infra/runtime/contract_dependency_resolver.py +455 -0
  65. omnibase_infra/runtime/contract_registration_event_router.py +500 -0
  66. omnibase_infra/runtime/db/__init__.py +4 -0
  67. omnibase_infra/runtime/db/models/__init__.py +15 -10
  68. omnibase_infra/runtime/db/models/model_db_operation.py +40 -0
  69. omnibase_infra/runtime/db/models/model_db_param.py +24 -0
  70. omnibase_infra/runtime/db/models/model_db_repository_contract.py +40 -0
  71. omnibase_infra/runtime/db/models/model_db_return.py +26 -0
  72. omnibase_infra/runtime/db/models/model_db_safety_policy.py +32 -0
  73. omnibase_infra/runtime/emit_daemon/event_registry.py +34 -22
  74. omnibase_infra/runtime/event_bus_subcontract_wiring.py +63 -23
  75. omnibase_infra/runtime/intent_execution_router.py +430 -0
  76. omnibase_infra/runtime/models/__init__.py +6 -0
  77. omnibase_infra/runtime/models/model_contract_registry_config.py +41 -0
  78. omnibase_infra/runtime/models/model_intent_execution_summary.py +79 -0
  79. omnibase_infra/runtime/models/model_runtime_config.py +8 -0
  80. omnibase_infra/runtime/protocols/__init__.py +16 -0
  81. omnibase_infra/runtime/protocols/protocol_intent_executor.py +107 -0
  82. omnibase_infra/runtime/publisher_topic_scoped.py +16 -11
  83. omnibase_infra/runtime/registry_policy.py +29 -15
  84. omnibase_infra/runtime/request_response_wiring.py +793 -0
  85. omnibase_infra/runtime/service_kernel.py +295 -8
  86. omnibase_infra/runtime/service_runtime_host_process.py +149 -5
  87. omnibase_infra/runtime/util_version.py +5 -1
  88. omnibase_infra/schemas/schema_latency_baseline.sql +135 -0
  89. omnibase_infra/services/contract_publisher/config.py +4 -4
  90. omnibase_infra/services/contract_publisher/service.py +8 -5
  91. omnibase_infra/services/observability/injection_effectiveness/__init__.py +67 -0
  92. omnibase_infra/services/observability/injection_effectiveness/config.py +295 -0
  93. omnibase_infra/services/observability/injection_effectiveness/consumer.py +1461 -0
  94. omnibase_infra/services/observability/injection_effectiveness/models/__init__.py +32 -0
  95. omnibase_infra/services/observability/injection_effectiveness/models/model_agent_match.py +79 -0
  96. omnibase_infra/services/observability/injection_effectiveness/models/model_context_utilization.py +118 -0
  97. omnibase_infra/services/observability/injection_effectiveness/models/model_latency_breakdown.py +107 -0
  98. omnibase_infra/services/observability/injection_effectiveness/models/model_pattern_utilization.py +46 -0
  99. omnibase_infra/services/observability/injection_effectiveness/writer_postgres.py +596 -0
  100. omnibase_infra/services/registry_api/models/__init__.py +25 -0
  101. omnibase_infra/services/registry_api/models/model_contract_ref.py +44 -0
  102. omnibase_infra/services/registry_api/models/model_contract_view.py +81 -0
  103. omnibase_infra/services/registry_api/models/model_response_contracts.py +50 -0
  104. omnibase_infra/services/registry_api/models/model_response_topics.py +50 -0
  105. omnibase_infra/services/registry_api/models/model_topic_summary.py +57 -0
  106. omnibase_infra/services/registry_api/models/model_topic_view.py +63 -0
  107. omnibase_infra/services/registry_api/routes.py +205 -6
  108. omnibase_infra/services/registry_api/service.py +528 -1
  109. omnibase_infra/utils/__init__.py +7 -0
  110. omnibase_infra/utils/util_db_error_context.py +292 -0
  111. omnibase_infra/validation/infra_validators.py +3 -1
  112. omnibase_infra/validation/validation_exemptions.yaml +65 -0
  113. {omnibase_infra-0.3.1.dist-info → omnibase_infra-0.4.0.dist-info}/METADATA +3 -3
  114. {omnibase_infra-0.3.1.dist-info → omnibase_infra-0.4.0.dist-info}/RECORD +117 -58
  115. {omnibase_infra-0.3.1.dist-info → omnibase_infra-0.4.0.dist-info}/WHEEL +0 -0
  116. {omnibase_infra-0.3.1.dist-info → omnibase_infra-0.4.0.dist-info}/entry_points.txt +0 -0
  117. {omnibase_infra-0.3.1.dist-info → omnibase_infra-0.4.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,107 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2025 OmniNode Team
3
+ """Protocol for intent executors in the contract persistence pipeline.
4
+
5
+ This module defines the protocol interface for intent executors that process
6
+ persistence intents from the ContractRegistryReducer.
7
+
8
+ Design:
9
+ Uses a Generic Protocol with contravariant TypeVar to properly express that
10
+ each handler accepts its specific payload type while the router can store
11
+ any handler conforming to the protocol. This avoids the need for `object`
12
+ workarounds and `cast()` at call sites.
13
+
14
+ Related:
15
+ - IntentExecutionRouter: Uses this protocol for handler routing
16
+ - OMN-1869: Implementation ticket
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ from typing import TYPE_CHECKING, Protocol, TypeVar, runtime_checkable
22
+ from uuid import UUID
23
+
24
+ if TYPE_CHECKING:
25
+ # These imports are only needed for type annotations.
26
+ # Using TYPE_CHECKING avoids circular import during package initialization
27
+ # (runtime.protocols is loaded before nodes is loaded).
28
+ from omnibase_infra.models.model_backend_result import (
29
+ ModelBackendResult,
30
+ )
31
+ from omnibase_infra.nodes.contract_registry_reducer.models import (
32
+ ModelPayloadCleanupTopicReferences,
33
+ ModelPayloadDeactivateContract,
34
+ ModelPayloadMarkStale,
35
+ ModelPayloadUpdateHeartbeat,
36
+ ModelPayloadUpdateTopic,
37
+ ModelPayloadUpsertContract,
38
+ )
39
+
40
+ # Type alias for payload types (union of all supported payloads)
41
+ # Defined inside TYPE_CHECKING since it references models only available there
42
+ IntentPayloadType = (
43
+ ModelPayloadUpsertContract
44
+ | ModelPayloadUpdateTopic
45
+ | ModelPayloadMarkStale
46
+ | ModelPayloadUpdateHeartbeat
47
+ | ModelPayloadDeactivateContract
48
+ | ModelPayloadCleanupTopicReferences
49
+ )
50
+
51
+ # Contravariant TypeVar for payload types - allows handlers with specific
52
+ # payload types to satisfy the protocol when used with broader type hints
53
+ PayloadT_contra = TypeVar("PayloadT_contra", contravariant=True)
54
+
55
+
56
+ @runtime_checkable
57
+ class ProtocolIntentExecutor(Protocol[PayloadT_contra]):
58
+ """Generic protocol for intent executors.
59
+
60
+ All persistence executors implement this interface, enabling type-safe
61
+ routing without tight coupling to specific implementations.
62
+
63
+ The protocol uses a contravariant TypeVar for the payload parameter,
64
+ which correctly expresses that:
65
+ - A handler accepting `ModelPayloadUpsertContract` can be stored where
66
+ `ProtocolIntentExecutor[Any]` is expected
67
+ - The router can call `handle()` with any payload that matches the
68
+ handler's declared payload type
69
+
70
+ Type Parameters:
71
+ PayloadT_contra: The payload type this executor accepts (contravariant).
72
+
73
+ Example:
74
+ >>> class HandlerPostgresContractUpsert:
75
+ ... async def handle(
76
+ ... self,
77
+ ... payload: ModelPayloadUpsertContract,
78
+ ... correlation_id: UUID,
79
+ ... ) -> ModelBackendResult: ...
80
+ >>>
81
+ >>> # Handler satisfies ProtocolIntentExecutor[ModelPayloadUpsertContract]
82
+ >>> # and can be stored as ProtocolIntentExecutor[Any]
83
+ >>> handlers: dict[str, ProtocolIntentExecutor[Any]] = {
84
+ ... "upsert": HandlerPostgresContractUpsert(pool),
85
+ ... }
86
+ """
87
+
88
+ async def handle(
89
+ self,
90
+ payload: PayloadT_contra,
91
+ correlation_id: UUID,
92
+ ) -> ModelBackendResult:
93
+ """Execute the handler operation.
94
+
95
+ Args:
96
+ payload: The typed payload model for this handler.
97
+ correlation_id: Request correlation ID for distributed tracing.
98
+
99
+ Returns:
100
+ ModelBackendResult with execution status.
101
+ """
102
+ ...
103
+
104
+
105
+ # NOTE: IntentPayloadType is only available under TYPE_CHECKING.
106
+ # Import it with: if TYPE_CHECKING: from ...protocol_intent_executor import IntentPayloadType
107
+ __all__ = ["PayloadT_contra", "ProtocolIntentExecutor"]
@@ -9,7 +9,7 @@ event emission and maintaining clean architectural boundaries.
9
9
 
10
10
  Design Principles:
11
11
  - **Contract-Driven Access Control**: Topics must be declared in contract
12
- - **Environment-Aware Routing**: Topic suffixes are prefixed with environment
12
+ - **Realm-Agnostic Topics**: Topics passed through unchanged (no env prefix)
13
13
  - **Fail-Fast Validation**: Invalid topics raise immediately, not at delivery
14
14
  - **Duck-Typed Protocol**: Implements publisher protocol without explicit inheritance
15
15
 
@@ -95,7 +95,7 @@ class PublisherTopicScoped:
95
95
 
96
96
  Features:
97
97
  - Contract-driven topic access control
98
- - Environment-aware topic resolution
98
+ - Realm-agnostic topics (no environment prefix)
99
99
  - Fail-fast validation on disallowed topics
100
100
  - JSON serialization for payloads
101
101
  - Correlation ID propagation for distributed tracing
@@ -103,7 +103,7 @@ class PublisherTopicScoped:
103
103
  Attributes:
104
104
  _event_bus: The underlying event bus for publishing
105
105
  _allowed_topics: Set of topic suffixes allowed by contract
106
- _environment: Environment prefix for topic resolution
106
+ _environment: Environment identifier (retained for future use)
107
107
 
108
108
  Example:
109
109
  >>> publisher = PublisherTopicScoped(
@@ -132,8 +132,8 @@ class PublisherTopicScoped:
132
132
  Must implement publish(topic, key, value) method. Duck typed per ONEX.
133
133
  allowed_topics: Set of topic suffixes from contract's publish_topics.
134
134
  These are the ONLY topics this publisher can publish to.
135
- environment: Environment prefix (e.g., 'dev', 'staging', 'prod').
136
- Used to construct full topic names.
135
+ environment: Environment identifier (e.g., 'dev', 'staging', 'prod').
136
+ Retained for future use; topics are realm-agnostic (no prefix).
137
137
 
138
138
  Example:
139
139
  >>> publisher = PublisherTopicScoped(
@@ -174,22 +174,27 @@ class PublisherTopicScoped:
174
174
  return str(correlation_id).encode("utf-8")
175
175
 
176
176
  def resolve_topic(self, topic_suffix: str) -> str:
177
- """Resolve topic suffix to full topic name with environment prefix.
177
+ """Resolve topic suffix to topic name (realm-agnostic, no environment prefix).
178
178
 
179
- The full topic name follows the ONEX convention:
180
- `{environment}.{topic_suffix}`
179
+ Topics are realm-agnostic in ONEX. The environment/realm is enforced via
180
+ envelope identity, not topic naming. This enables cross-environment event
181
+ routing when needed while maintaining proper isolation through identity.
181
182
 
182
183
  Args:
183
184
  topic_suffix: ONEX format topic suffix (e.g., 'onex.events.v1')
184
185
 
185
186
  Returns:
186
- Full topic name with environment prefix (e.g., 'dev.onex.events.v1')
187
+ Topic name (same as suffix, no environment prefix)
187
188
 
188
189
  Example:
189
190
  >>> publisher.resolve_topic("onex.events.v1")
190
- 'dev.onex.events.v1'
191
+ 'onex.events.v1'
192
+
193
+ Note:
194
+ The environment is still stored for potential consumer group derivation
195
+ in related components. Topics themselves are realm-agnostic.
191
196
  """
192
- return f"{self._environment}.{topic_suffix}"
197
+ return topic_suffix
193
198
 
194
199
  async def publish(
195
200
  self,
@@ -86,7 +86,6 @@ from typing import TYPE_CHECKING
86
86
 
87
87
  from pydantic import ValidationError
88
88
 
89
- from omnibase_core.models.primitives import ModelSemVer
90
89
  from omnibase_infra.enums import EnumInfraTransportType, EnumPolicyType
91
90
  from omnibase_infra.errors import PolicyRegistryError, ProtocolConfigurationError
92
91
  from omnibase_infra.models.errors.model_infra_error_context import (
@@ -97,6 +96,7 @@ from omnibase_infra.runtime.mixin_semver_cache import MixinSemverCache
97
96
  from omnibase_infra.runtime.models import ModelPolicyKey, ModelPolicyRegistration
98
97
  from omnibase_infra.runtime.util_version import normalize_version
99
98
  from omnibase_infra.types import PolicyTypeInput
99
+ from omnibase_infra.utils import validate_policy_type_value
100
100
 
101
101
  if TYPE_CHECKING:
102
102
  from omnibase_infra.runtime.protocol_policy import ProtocolPolicy
@@ -463,11 +463,13 @@ class RegistryPolicy(MixinPolicyValidation, MixinSemverCache):
463
463
  and string literals, normalizing them to their string representation while
464
464
  ensuring they match valid EnumPolicyType values.
465
465
 
466
+ Delegates validation to the shared ``validate_policy_type_value()`` utility,
467
+ which is the SINGLE SOURCE OF TRUTH for policy type validation in omnibase_infra.
468
+
466
469
  Validation Process:
467
- 1. If policy_type is EnumPolicyType instance, extract .value
468
- 2. If policy_type is string, validate against EnumPolicyType values
469
- 3. Raise PolicyRegistryError if string doesn't match any enum value
470
- 4. Return normalized string value
470
+ 1. Delegate to validate_policy_type_value() for validation and coercion
471
+ 2. Extract .value from the validated EnumPolicyType
472
+ 3. Return normalized string value
471
473
 
472
474
  This centralized validation ensures consistent policy type handling across
473
475
  all registry operations (register, get, list_keys, is_registered, unregister).
@@ -498,12 +500,14 @@ class RegistryPolicy(MixinPolicyValidation, MixinSemverCache):
498
500
  PolicyRegistryError: Invalid policy_type: 'invalid'.
499
501
  Must be one of: ['orchestrator', 'reducer']
500
502
  """
501
- if isinstance(policy_type, EnumPolicyType):
502
- return policy_type.value
503
-
504
- # Validate string against enum values
505
- valid_types = {e.value for e in EnumPolicyType}
506
- if policy_type not in valid_types:
503
+ try:
504
+ # Use shared validation utility (SINGLE SOURCE OF TRUTH)
505
+ validated_enum = validate_policy_type_value(policy_type)
506
+ return validated_enum.value
507
+ except ValueError as exc:
508
+ # Convert ValueError from shared utility to PolicyRegistryError
509
+ # for consistent error handling in the registry
510
+ valid_types = {pt.value for pt in EnumPolicyType}
507
511
  context = ModelInfraErrorContext.with_correlation(
508
512
  transport_type=EnumInfraTransportType.RUNTIME,
509
513
  operation="normalize_policy_type",
@@ -512,11 +516,9 @@ class RegistryPolicy(MixinPolicyValidation, MixinSemverCache):
512
516
  f"Invalid policy_type: {policy_type!r}. "
513
517
  f"Must be one of: {sorted(valid_types)}",
514
518
  policy_id=None,
515
- policy_type=policy_type,
519
+ policy_type=str(policy_type),
516
520
  context=context,
517
- )
518
-
519
- return policy_type
521
+ ) from exc
520
522
 
521
523
  @staticmethod
522
524
  def _normalize_version(version: str) -> str:
@@ -656,6 +658,10 @@ class RegistryPolicy(MixinPolicyValidation, MixinSemverCache):
656
658
  Partial version strings (e.g., "1", "1.0") are auto-normalized to
657
659
  "x.y.z" format by ModelPolicyRegistration.
658
660
 
661
+ .. deprecated::
662
+ This method is deprecated. Use ``register(ModelPolicyRegistration(...))``
663
+ directly for new code. This method will be removed in a future version.
664
+
659
665
  Note:
660
666
  For new code, prefer using register(ModelPolicyRegistration(...))
661
667
  directly. This is a convenience method for simple registrations.
@@ -684,6 +690,14 @@ class RegistryPolicy(MixinPolicyValidation, MixinSemverCache):
684
690
  ... version="1.0.0",
685
691
  ... )
686
692
  """
693
+ # Emit deprecation warning at runtime
694
+ warnings.warn(
695
+ "register_policy() is deprecated. Use register(ModelPolicyRegistration(...)) "
696
+ "instead. This method will be removed in a future version.",
697
+ DeprecationWarning,
698
+ stacklevel=2,
699
+ )
700
+
687
701
  # Version normalization is handled by ModelPolicyRegistration validator
688
702
  # which normalizes partial versions and v-prefixed versions automatically
689
703
  try: