omnibase_infra 0.2.8__py3-none-any.whl → 0.3.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 (88) hide show
  1. omnibase_infra/__init__.py +1 -1
  2. omnibase_infra/enums/__init__.py +4 -0
  3. omnibase_infra/enums/enum_declarative_node_violation.py +102 -0
  4. omnibase_infra/errors/__init__.py +18 -0
  5. omnibase_infra/errors/repository/__init__.py +78 -0
  6. omnibase_infra/errors/repository/errors_repository.py +424 -0
  7. omnibase_infra/event_bus/adapters/__init__.py +31 -0
  8. omnibase_infra/event_bus/adapters/adapter_protocol_event_publisher_kafka.py +517 -0
  9. omnibase_infra/mixins/mixin_async_circuit_breaker.py +113 -1
  10. omnibase_infra/models/__init__.py +9 -0
  11. omnibase_infra/models/event_bus/__init__.py +22 -0
  12. omnibase_infra/models/event_bus/model_consumer_retry_config.py +367 -0
  13. omnibase_infra/models/event_bus/model_dlq_config.py +177 -0
  14. omnibase_infra/models/event_bus/model_idempotency_config.py +131 -0
  15. omnibase_infra/models/event_bus/model_offset_policy_config.py +107 -0
  16. omnibase_infra/models/resilience/model_circuit_breaker_config.py +15 -0
  17. omnibase_infra/models/validation/__init__.py +8 -0
  18. omnibase_infra/models/validation/model_declarative_node_validation_result.py +139 -0
  19. omnibase_infra/models/validation/model_declarative_node_violation.py +169 -0
  20. omnibase_infra/nodes/architecture_validator/__init__.py +28 -7
  21. omnibase_infra/nodes/architecture_validator/constants.py +36 -0
  22. omnibase_infra/nodes/architecture_validator/handlers/__init__.py +28 -0
  23. omnibase_infra/nodes/architecture_validator/handlers/contract.yaml +120 -0
  24. omnibase_infra/nodes/architecture_validator/handlers/handler_architecture_validation.py +359 -0
  25. omnibase_infra/nodes/architecture_validator/node.py +1 -0
  26. omnibase_infra/nodes/architecture_validator/node_architecture_validator.py +48 -336
  27. omnibase_infra/nodes/contract_registry_reducer/reducer.py +12 -2
  28. omnibase_infra/nodes/node_ledger_projection_compute/__init__.py +16 -2
  29. omnibase_infra/nodes/node_ledger_projection_compute/contract.yaml +14 -4
  30. omnibase_infra/nodes/node_ledger_projection_compute/handlers/__init__.py +18 -0
  31. omnibase_infra/nodes/node_ledger_projection_compute/handlers/contract.yaml +53 -0
  32. omnibase_infra/nodes/node_ledger_projection_compute/handlers/handler_ledger_projection.py +354 -0
  33. omnibase_infra/nodes/node_ledger_projection_compute/node.py +20 -256
  34. omnibase_infra/nodes/node_registry_effect/node.py +20 -73
  35. omnibase_infra/protocols/protocol_dispatch_engine.py +90 -0
  36. omnibase_infra/runtime/__init__.py +11 -0
  37. omnibase_infra/runtime/baseline_subscriptions.py +150 -0
  38. omnibase_infra/runtime/db/__init__.py +73 -0
  39. omnibase_infra/runtime/db/models/__init__.py +41 -0
  40. omnibase_infra/runtime/db/models/model_repository_runtime_config.py +211 -0
  41. omnibase_infra/runtime/db/postgres_repository_runtime.py +545 -0
  42. omnibase_infra/runtime/event_bus_subcontract_wiring.py +455 -24
  43. omnibase_infra/runtime/kafka_contract_source.py +13 -5
  44. omnibase_infra/runtime/service_message_dispatch_engine.py +112 -0
  45. omnibase_infra/runtime/service_runtime_host_process.py +6 -11
  46. omnibase_infra/services/__init__.py +36 -0
  47. omnibase_infra/services/contract_publisher/__init__.py +95 -0
  48. omnibase_infra/services/contract_publisher/config.py +199 -0
  49. omnibase_infra/services/contract_publisher/errors.py +243 -0
  50. omnibase_infra/services/contract_publisher/models/__init__.py +28 -0
  51. omnibase_infra/services/contract_publisher/models/model_contract_error.py +67 -0
  52. omnibase_infra/services/contract_publisher/models/model_infra_error.py +62 -0
  53. omnibase_infra/services/contract_publisher/models/model_publish_result.py +112 -0
  54. omnibase_infra/services/contract_publisher/models/model_publish_stats.py +79 -0
  55. omnibase_infra/services/contract_publisher/service.py +617 -0
  56. omnibase_infra/services/contract_publisher/sources/__init__.py +52 -0
  57. omnibase_infra/services/contract_publisher/sources/model_discovered.py +155 -0
  58. omnibase_infra/services/contract_publisher/sources/protocol.py +101 -0
  59. omnibase_infra/services/contract_publisher/sources/source_composite.py +309 -0
  60. omnibase_infra/services/contract_publisher/sources/source_filesystem.py +174 -0
  61. omnibase_infra/services/contract_publisher/sources/source_package.py +221 -0
  62. omnibase_infra/services/observability/__init__.py +40 -0
  63. omnibase_infra/services/observability/agent_actions/__init__.py +64 -0
  64. omnibase_infra/services/observability/agent_actions/config.py +209 -0
  65. omnibase_infra/services/observability/agent_actions/consumer.py +1320 -0
  66. omnibase_infra/services/observability/agent_actions/models/__init__.py +87 -0
  67. omnibase_infra/services/observability/agent_actions/models/model_agent_action.py +142 -0
  68. omnibase_infra/services/observability/agent_actions/models/model_detection_failure.py +125 -0
  69. omnibase_infra/services/observability/agent_actions/models/model_envelope.py +85 -0
  70. omnibase_infra/services/observability/agent_actions/models/model_execution_log.py +159 -0
  71. omnibase_infra/services/observability/agent_actions/models/model_performance_metric.py +130 -0
  72. omnibase_infra/services/observability/agent_actions/models/model_routing_decision.py +138 -0
  73. omnibase_infra/services/observability/agent_actions/models/model_transformation_event.py +124 -0
  74. omnibase_infra/services/observability/agent_actions/tests/__init__.py +20 -0
  75. omnibase_infra/services/observability/agent_actions/tests/test_consumer.py +1154 -0
  76. omnibase_infra/services/observability/agent_actions/tests/test_models.py +645 -0
  77. omnibase_infra/services/observability/agent_actions/tests/test_writer.py +709 -0
  78. omnibase_infra/services/observability/agent_actions/writer_postgres.py +926 -0
  79. omnibase_infra/validation/__init__.py +12 -0
  80. omnibase_infra/validation/contracts/declarative_node.validation.yaml +143 -0
  81. omnibase_infra/validation/infra_validators.py +4 -1
  82. omnibase_infra/validation/validation_exemptions.yaml +111 -0
  83. omnibase_infra/validation/validator_declarative_node.py +850 -0
  84. {omnibase_infra-0.2.8.dist-info → omnibase_infra-0.3.0.dist-info}/METADATA +2 -2
  85. {omnibase_infra-0.2.8.dist-info → omnibase_infra-0.3.0.dist-info}/RECORD +88 -30
  86. {omnibase_infra-0.2.8.dist-info → omnibase_infra-0.3.0.dist-info}/WHEEL +0 -0
  87. {omnibase_infra-0.2.8.dist-info → omnibase_infra-0.3.0.dist-info}/entry_points.txt +0 -0
  88. {omnibase_infra-0.2.8.dist-info → omnibase_infra-0.3.0.dist-info}/licenses/LICENSE +0 -0
@@ -76,7 +76,7 @@ See Also
76
76
  - Runtime kernel: omnibase_infra.runtime.service_kernel
77
77
  """
78
78
 
79
- __version__ = "0.2.8"
79
+ __version__ = "0.3.0"
80
80
 
81
81
  from . import (
82
82
  enums,
@@ -57,6 +57,9 @@ from omnibase_infra.enums.enum_circuit_state import EnumCircuitState
57
57
  from omnibase_infra.enums.enum_confirmation_event_type import EnumConfirmationEventType
58
58
  from omnibase_infra.enums.enum_consumer_group_purpose import EnumConsumerGroupPurpose
59
59
  from omnibase_infra.enums.enum_contract_type import EnumContractType
60
+ from omnibase_infra.enums.enum_declarative_node_violation import (
61
+ EnumDeclarativeNodeViolation,
62
+ )
60
63
  from omnibase_infra.enums.enum_dedupe_strategy import EnumDedupeStrategy
61
64
  from omnibase_infra.enums.enum_dispatch_status import EnumDispatchStatus
62
65
  from omnibase_infra.enums.enum_environment import EnumEnvironment
@@ -101,6 +104,7 @@ __all__: list[str] = [
101
104
  "EnumConfirmationEventType",
102
105
  "EnumConsumerGroupPurpose",
103
106
  "EnumContractType",
107
+ "EnumDeclarativeNodeViolation",
104
108
  "EnumDedupeStrategy",
105
109
  "EnumDispatchStatus",
106
110
  "EnumEnvironment",
@@ -0,0 +1,102 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2025 OmniNode Team
3
+ """Enum for declarative node violation categories.
4
+
5
+ Defines the specific violation types detected by the declarative node validator.
6
+ Following the ONEX declarative pattern policy:
7
+ - Node classes MUST only extend base classes without custom logic
8
+ - Only __init__ with super().__init__(container) is allowed
9
+ - No custom methods, properties, or instance variables
10
+ """
11
+
12
+ from enum import Enum
13
+
14
+
15
+ class EnumDeclarativeNodeViolation(str, Enum):
16
+ """Violation types for declarative node pattern enforcement.
17
+
18
+ These violation types correspond to the ONEX declarative node policy:
19
+ Nodes must be contract-driven with no custom Python logic.
20
+
21
+ Attributes:
22
+ CUSTOM_METHOD: Node class contains custom method (not __init__).
23
+ CUSTOM_PROPERTY: Node class contains property definition.
24
+ INIT_CUSTOM_LOGIC: __init__ contains logic beyond super().__init__().
25
+ INSTANCE_VARIABLE: __init__ creates custom instance variables.
26
+ CLASS_VARIABLE: Node class defines class-level variables.
27
+ SYNTAX_ERROR: File has Python syntax error, cannot validate.
28
+ NO_NODE_CLASS: File named node.py but contains no node class.
29
+
30
+ Policy Summary:
31
+ - ALLOWED: ``class MyNode(NodeEffect): pass``
32
+ - ALLOWED: ``def __init__(self, container): super().__init__(container)``
33
+ - BLOCKED: ``def compute(self, data): ...``
34
+ - BLOCKED: ``@property def my_prop(self): ...``
35
+ - BLOCKED: ``self._custom_var = value`` in __init__
36
+ """
37
+
38
+ CUSTOM_METHOD = "custom_method"
39
+ CUSTOM_PROPERTY = "custom_property"
40
+ INIT_CUSTOM_LOGIC = "init_custom_logic"
41
+ INSTANCE_VARIABLE = "instance_variable"
42
+ CLASS_VARIABLE = "class_variable"
43
+ SYNTAX_ERROR = "syntax_error"
44
+ NO_NODE_CLASS = "no_node_class"
45
+
46
+ @property
47
+ def is_exemptable(self) -> bool:
48
+ """Check if this violation type can be exempted.
49
+
50
+ Some violations like SYNTAX_ERROR cannot be exempted because
51
+ they indicate fundamental issues with the source file.
52
+
53
+ Returns:
54
+ True if the violation type can be exempted via decorator or comment.
55
+ """
56
+ return self not in {
57
+ EnumDeclarativeNodeViolation.SYNTAX_ERROR,
58
+ EnumDeclarativeNodeViolation.NO_NODE_CLASS,
59
+ }
60
+
61
+ @property
62
+ def suggestion(self) -> str:
63
+ """Get the suggested fix for this violation type.
64
+
65
+ Returns:
66
+ Human-readable suggestion for fixing the violation.
67
+ """
68
+ suggestions = {
69
+ EnumDeclarativeNodeViolation.CUSTOM_METHOD: (
70
+ "Move business logic to a Handler class. Node classes must be "
71
+ "declarative - all behavior should be defined in contract.yaml "
72
+ "and implemented by handlers."
73
+ ),
74
+ EnumDeclarativeNodeViolation.CUSTOM_PROPERTY: (
75
+ "Remove property from node class. Node classes should not have "
76
+ "custom properties - use container dependency injection instead."
77
+ ),
78
+ EnumDeclarativeNodeViolation.INIT_CUSTOM_LOGIC: (
79
+ "Remove custom logic from __init__. The __init__ method should "
80
+ "only call super().__init__(container). All initialization should "
81
+ "be handled by the base class and contract.yaml."
82
+ ),
83
+ EnumDeclarativeNodeViolation.INSTANCE_VARIABLE: (
84
+ "Remove instance variable assignment from __init__. Node classes "
85
+ "should not store state - use container injection and handlers."
86
+ ),
87
+ EnumDeclarativeNodeViolation.CLASS_VARIABLE: (
88
+ "Remove class variable from node class. Configuration should be "
89
+ "in contract.yaml, not Python code."
90
+ ),
91
+ EnumDeclarativeNodeViolation.SYNTAX_ERROR: (
92
+ "Fix the Python syntax error before validation can proceed."
93
+ ),
94
+ EnumDeclarativeNodeViolation.NO_NODE_CLASS: (
95
+ "File is named node.py but does not contain a Node class. "
96
+ "Either add a Node class or rename the file."
97
+ ),
98
+ }
99
+ return suggestions.get(self, "Make the node class declarative.")
100
+
101
+
102
+ __all__ = ["EnumDeclarativeNodeViolation"]
@@ -23,6 +23,11 @@ Exports:
23
23
  ChainPropagationError: Correlation/causation chain validation errors
24
24
  ArchitectureViolationError: Architecture validation errors (blocks startup)
25
25
  BindingResolutionError: Binding resolution errors (declarative operation bindings)
26
+ RepositoryError: Base error for repository operations
27
+ RepositoryContractError: Contract-level errors (bad op_name, missing params)
28
+ RepositoryValidationError: Validation errors (type mismatch, constraints)
29
+ RepositoryExecutionError: Execution errors (asyncpg, connection issues)
30
+ RepositoryTimeoutError: Query timeout exceeded
26
31
 
27
32
  Correlation ID Assignment:
28
33
  All infrastructure errors support correlation_id for distributed tracing.
@@ -117,6 +122,13 @@ from omnibase_infra.errors.error_infra import (
117
122
  from omnibase_infra.errors.error_message_type_registry import MessageTypeRegistryError
118
123
  from omnibase_infra.errors.error_policy_registry import PolicyRegistryError
119
124
  from omnibase_infra.errors.error_vault import InfraVaultError
125
+ from omnibase_infra.errors.repository import (
126
+ RepositoryContractError,
127
+ RepositoryError,
128
+ RepositoryExecutionError,
129
+ RepositoryTimeoutError,
130
+ RepositoryValidationError,
131
+ )
120
132
  from omnibase_infra.models.errors.model_infra_error_context import (
121
133
  ModelInfraErrorContext,
122
134
  )
@@ -150,6 +162,12 @@ __all__: list[str] = [
150
162
  "ModelTimeoutErrorContext",
151
163
  "PolicyRegistryError",
152
164
  "ProtocolConfigurationError",
165
+ # Repository errors
166
+ "RepositoryContractError",
167
+ "RepositoryError",
168
+ "RepositoryExecutionError",
169
+ "RepositoryTimeoutError",
170
+ "RepositoryValidationError",
153
171
  # Error classes
154
172
  "RuntimeHostError",
155
173
  "SecretResolutionError",
@@ -0,0 +1,78 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2025 OmniNode Team
3
+ """Repository Error Classes Module.
4
+
5
+ This module provides error classes specific to repository operations,
6
+ enabling typed exception handling for the PostgresRepositoryRuntime.
7
+
8
+ Error Hierarchy:
9
+ RuntimeHostError (from omnibase_infra.errors)
10
+ └── RepositoryError (base repository error)
11
+ ├── RepositoryContractError (contract-level errors)
12
+ ├── RepositoryValidationError (validation errors)
13
+ ├── RepositoryExecutionError (execution errors)
14
+ └── RepositoryTimeoutError (query timeout errors)
15
+
16
+ Exports:
17
+ RepositoryError: Base error for all repository operations
18
+ RepositoryContractError: Bad op_name, missing params, forbidden op
19
+ RepositoryValidationError: Param type mismatch, constraint violation
20
+ RepositoryExecutionError: asyncpg errors, connection issues
21
+ RepositoryTimeoutError: Query timeout exceeded
22
+
23
+ Common Fields (all exceptions):
24
+ op_name: str | None - Operation name from repository contract
25
+ table: str | None - Target table for the operation
26
+ retriable: bool - Whether the operation can be retried
27
+ sql_fingerprint: str | None - SQL fingerprint for query tracking
28
+
29
+ Example Usage::
30
+
31
+ from omnibase_infra.errors.repository import (
32
+ RepositoryContractError,
33
+ RepositoryExecutionError,
34
+ RepositoryTimeoutError,
35
+ RepositoryValidationError,
36
+ )
37
+ from omnibase_infra.models.errors import ModelInfraErrorContext
38
+ from omnibase_infra.enums import EnumInfraTransportType
39
+
40
+ # Contract error - unknown operation
41
+ context = ModelInfraErrorContext.with_correlation(
42
+ transport_type=EnumInfraTransportType.DATABASE,
43
+ operation="execute_operation",
44
+ )
45
+ raise RepositoryContractError(
46
+ "Unknown operation 'invalid_op'",
47
+ op_name="invalid_op",
48
+ table="users",
49
+ context=context,
50
+ )
51
+
52
+ # Check retriability in error handling
53
+ try:
54
+ result = await runtime.execute("find_all", {})
55
+ except RepositoryError as e:
56
+ if e.retriable:
57
+ # Can retry with backoff
58
+ pass
59
+ else:
60
+ # Non-retriable, propagate
61
+ raise
62
+ """
63
+
64
+ from omnibase_infra.errors.repository.errors_repository import (
65
+ RepositoryContractError,
66
+ RepositoryError,
67
+ RepositoryExecutionError,
68
+ RepositoryTimeoutError,
69
+ RepositoryValidationError,
70
+ )
71
+
72
+ __all__ = [
73
+ "RepositoryContractError",
74
+ "RepositoryError",
75
+ "RepositoryExecutionError",
76
+ "RepositoryTimeoutError",
77
+ "RepositoryValidationError",
78
+ ]
@@ -0,0 +1,424 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2025 OmniNode Team
3
+ """Repository Error Classes for PostgresRepositoryRuntime.
4
+
5
+ This module defines error classes specific to repository operations,
6
+ providing granular error handling for contract-driven database access.
7
+
8
+ Error Hierarchy:
9
+ RuntimeHostError (from error_infra)
10
+ └── RepositoryError (base repository error)
11
+ ├── RepositoryContractError (contract-level errors)
12
+ ├── RepositoryValidationError (validation errors)
13
+ ├── RepositoryExecutionError (execution errors)
14
+ └── RepositoryTimeoutError (query timeout errors)
15
+
16
+ All errors:
17
+ - Extend RuntimeHostError for infrastructure consistency
18
+ - Include repository-specific fields: op_name, table, retriable
19
+ - Support optional sql_fingerprint for query tracking
20
+ - Use EnumCoreErrorCode for error classification
21
+ - Support correlation IDs for distributed tracing
22
+
23
+ Retriability Guidelines:
24
+ - RepositoryContractError: NOT retriable (contract/configuration issue)
25
+ - RepositoryValidationError: NOT retriable (data validation issue)
26
+ - RepositoryExecutionError: Generally retriable (transient failures)
27
+ - RepositoryTimeoutError: Retriable (timeout may be transient)
28
+
29
+ Example::
30
+
31
+ from omnibase_infra.errors.repository import (
32
+ RepositoryContractError,
33
+ RepositoryExecutionError,
34
+ RepositoryTimeoutError,
35
+ RepositoryValidationError,
36
+ )
37
+ from omnibase_infra.models.errors import ModelInfraErrorContext
38
+ from omnibase_infra.enums import EnumInfraTransportType
39
+
40
+ # Contract error - unknown operation
41
+ context = ModelInfraErrorContext.with_correlation(
42
+ transport_type=EnumInfraTransportType.DATABASE,
43
+ operation="execute_operation",
44
+ )
45
+ raise RepositoryContractError(
46
+ "Unknown operation 'invalid_op' not defined in contract",
47
+ op_name="invalid_op",
48
+ table="users",
49
+ context=context,
50
+ )
51
+
52
+ # Execution error with SQL fingerprint
53
+ raise RepositoryExecutionError(
54
+ "Connection pool exhausted",
55
+ op_name="find_by_id",
56
+ table="users",
57
+ sql_fingerprint="SELECT * FROM users WHERE id = $1",
58
+ context=context,
59
+ ) from e
60
+ """
61
+
62
+ from omnibase_core.enums import EnumCoreErrorCode
63
+ from omnibase_infra.errors.error_infra import RuntimeHostError
64
+ from omnibase_infra.models.errors.model_infra_error_context import (
65
+ ModelInfraErrorContext,
66
+ )
67
+
68
+
69
+ class RepositoryError(RuntimeHostError):
70
+ """Base error class for all repository operations.
71
+
72
+ Provides common structured fields for repository-specific errors:
73
+ - op_name: The operation name from the repository contract
74
+ - table: The target table for the operation
75
+ - retriable: Whether the operation can be retried
76
+ - sql_fingerprint: Optional SQL fingerprint for query tracking
77
+
78
+ Subclasses set default retriability based on error category:
79
+ - Contract errors: NOT retriable
80
+ - Validation errors: NOT retriable
81
+ - Execution errors: Generally retriable
82
+ - Timeout errors: Retriable
83
+
84
+ Example:
85
+ >>> context = ModelInfraErrorContext.with_correlation(
86
+ ... transport_type=EnumInfraTransportType.DATABASE,
87
+ ... operation="execute_operation",
88
+ ... )
89
+ >>> raise RepositoryError(
90
+ ... "Repository operation failed",
91
+ ... op_name="find_by_id",
92
+ ... table="users",
93
+ ... context=context,
94
+ ... )
95
+ """
96
+
97
+ # Default retriability for base class (conservative: not retriable)
98
+ _default_retriable: bool = False
99
+
100
+ def __init__(
101
+ self,
102
+ message: str,
103
+ *,
104
+ op_name: str | None = None,
105
+ table: str | None = None,
106
+ retriable: bool | None = None,
107
+ sql_fingerprint: str | None = None,
108
+ error_code: EnumCoreErrorCode | None = None,
109
+ context: ModelInfraErrorContext | None = None,
110
+ **extra_context: object,
111
+ ) -> None:
112
+ """Initialize RepositoryError with repository-specific fields.
113
+
114
+ Args:
115
+ message: Human-readable error message
116
+ op_name: Operation name from the repository contract
117
+ table: Target table for the operation
118
+ retriable: Whether the operation can be retried. If None, uses
119
+ class default (_default_retriable)
120
+ sql_fingerprint: SQL fingerprint for query tracking (sanitized)
121
+ error_code: Error code (defaults to DATABASE_OPERATION_ERROR)
122
+ context: Bundled infrastructure context
123
+ **extra_context: Additional context information
124
+ """
125
+ # Add repository-specific fields to extra_context
126
+ if op_name is not None:
127
+ extra_context["op_name"] = op_name
128
+ if table is not None:
129
+ extra_context["table"] = table
130
+ if sql_fingerprint is not None:
131
+ extra_context["sql_fingerprint"] = sql_fingerprint
132
+
133
+ # Resolve retriability: explicit > class default
134
+ resolved_retriable = (
135
+ retriable if retriable is not None else self._default_retriable
136
+ )
137
+ extra_context["retriable"] = resolved_retriable
138
+
139
+ # Store as instance attributes for programmatic access
140
+ self.op_name = op_name
141
+ self.table = table
142
+ self.retriable = resolved_retriable
143
+ self.sql_fingerprint = sql_fingerprint
144
+
145
+ super().__init__(
146
+ message=message,
147
+ error_code=error_code or EnumCoreErrorCode.DATABASE_OPERATION_ERROR,
148
+ context=context,
149
+ **extra_context,
150
+ )
151
+
152
+
153
+ class RepositoryContractError(RepositoryError):
154
+ """Raised for contract-level errors in repository operations.
155
+
156
+ Used when:
157
+ - Operation name (op_name) is not defined in the contract
158
+ - Required parameters are missing for the operation
159
+ - Operation is explicitly forbidden in the contract
160
+ - Contract schema validation fails
161
+
162
+ Contract errors are NOT retriable - they indicate a configuration
163
+ or programming error that requires code or contract changes to fix.
164
+
165
+ Example:
166
+ >>> context = ModelInfraErrorContext.with_correlation(
167
+ ... transport_type=EnumInfraTransportType.DATABASE,
168
+ ... operation="execute_operation",
169
+ ... )
170
+ >>> raise RepositoryContractError(
171
+ ... "Operation 'drop_table' is forbidden in contract",
172
+ ... op_name="drop_table",
173
+ ... table="users",
174
+ ... context=context,
175
+ ... )
176
+ """
177
+
178
+ _default_retriable: bool = False
179
+
180
+ def __init__(
181
+ self,
182
+ message: str,
183
+ *,
184
+ op_name: str | None = None,
185
+ table: str | None = None,
186
+ retriable: bool | None = None,
187
+ sql_fingerprint: str | None = None,
188
+ context: ModelInfraErrorContext | None = None,
189
+ **extra_context: object,
190
+ ) -> None:
191
+ """Initialize RepositoryContractError.
192
+
193
+ Args:
194
+ message: Human-readable error message
195
+ op_name: Operation name that caused the contract error
196
+ table: Target table (if applicable)
197
+ retriable: Override default (False). Contract errors are
198
+ generally NOT retriable.
199
+ sql_fingerprint: SQL fingerprint (if applicable)
200
+ context: Bundled infrastructure context
201
+ **extra_context: Additional context information
202
+ """
203
+ super().__init__(
204
+ message=message,
205
+ op_name=op_name,
206
+ table=table,
207
+ retriable=retriable,
208
+ sql_fingerprint=sql_fingerprint,
209
+ error_code=EnumCoreErrorCode.INVALID_CONFIGURATION,
210
+ context=context,
211
+ **extra_context,
212
+ )
213
+
214
+
215
+ class RepositoryValidationError(RepositoryError):
216
+ """Raised for validation errors in repository operations.
217
+
218
+ Used when:
219
+ - Parameter type mismatches (e.g., string passed for int column)
220
+ - Constraint violations (e.g., null for non-nullable column)
221
+ - Value out of allowed range
222
+ - Invalid data format
223
+
224
+ Validation errors are NOT retriable - they indicate invalid input
225
+ data that must be corrected before retrying.
226
+
227
+ Example:
228
+ >>> context = ModelInfraErrorContext.with_correlation(
229
+ ... transport_type=EnumInfraTransportType.DATABASE,
230
+ ... operation="execute_operation",
231
+ ... )
232
+ >>> raise RepositoryValidationError(
233
+ ... "Parameter 'user_id' expected int, got str",
234
+ ... op_name="find_by_id",
235
+ ... table="users",
236
+ ... context=context,
237
+ ... param_name="user_id",
238
+ ... expected_type="int",
239
+ ... actual_type="str",
240
+ ... )
241
+ """
242
+
243
+ _default_retriable: bool = False
244
+
245
+ def __init__(
246
+ self,
247
+ message: str,
248
+ *,
249
+ op_name: str | None = None,
250
+ table: str | None = None,
251
+ retriable: bool | None = None,
252
+ sql_fingerprint: str | None = None,
253
+ context: ModelInfraErrorContext | None = None,
254
+ **extra_context: object,
255
+ ) -> None:
256
+ """Initialize RepositoryValidationError.
257
+
258
+ Args:
259
+ message: Human-readable error message
260
+ op_name: Operation name that triggered validation
261
+ table: Target table (if applicable)
262
+ retriable: Override default (False). Validation errors are
263
+ generally NOT retriable.
264
+ sql_fingerprint: SQL fingerprint (if applicable)
265
+ context: Bundled infrastructure context
266
+ **extra_context: Additional context (param_name, expected_type, etc.)
267
+ """
268
+ super().__init__(
269
+ message=message,
270
+ op_name=op_name,
271
+ table=table,
272
+ retriable=retriable,
273
+ sql_fingerprint=sql_fingerprint,
274
+ error_code=EnumCoreErrorCode.VALIDATION_ERROR,
275
+ context=context,
276
+ **extra_context,
277
+ )
278
+
279
+
280
+ class RepositoryExecutionError(RepositoryError):
281
+ """Raised for execution errors in repository operations.
282
+
283
+ Used when:
284
+ - asyncpg errors during query execution
285
+ - Connection pool exhaustion
286
+ - Database connection lost mid-operation
287
+ - Deadlock detected
288
+ - Serialization failures
289
+
290
+ Execution errors are generally retriable - they often indicate
291
+ transient failures that may succeed on retry with backoff.
292
+
293
+ Example:
294
+ >>> context = ModelInfraErrorContext.with_correlation(
295
+ ... transport_type=EnumInfraTransportType.DATABASE,
296
+ ... operation="execute_operation",
297
+ ... )
298
+ >>> try:
299
+ ... result = await pool.execute(sql, *params)
300
+ ... except asyncpg.PostgresError as e:
301
+ ... raise RepositoryExecutionError(
302
+ ... f"Query execution failed: {e}",
303
+ ... op_name="create_user",
304
+ ... table="users",
305
+ ... sql_fingerprint="INSERT INTO users (...) VALUES (...)",
306
+ ... context=context,
307
+ ... ) from e
308
+ """
309
+
310
+ _default_retriable: bool = True
311
+
312
+ def __init__(
313
+ self,
314
+ message: str,
315
+ *,
316
+ op_name: str | None = None,
317
+ table: str | None = None,
318
+ retriable: bool | None = None,
319
+ sql_fingerprint: str | None = None,
320
+ context: ModelInfraErrorContext | None = None,
321
+ **extra_context: object,
322
+ ) -> None:
323
+ """Initialize RepositoryExecutionError.
324
+
325
+ Args:
326
+ message: Human-readable error message
327
+ op_name: Operation name that failed during execution
328
+ table: Target table (if applicable)
329
+ retriable: Override default (True). Set False for non-retriable
330
+ execution errors (e.g., constraint violations from DB).
331
+ sql_fingerprint: SQL fingerprint for query tracking
332
+ context: Bundled infrastructure context
333
+ **extra_context: Additional context (asyncpg error details, etc.)
334
+ """
335
+ super().__init__(
336
+ message=message,
337
+ op_name=op_name,
338
+ table=table,
339
+ retriable=retriable,
340
+ sql_fingerprint=sql_fingerprint,
341
+ error_code=EnumCoreErrorCode.DATABASE_OPERATION_ERROR,
342
+ context=context,
343
+ **extra_context,
344
+ )
345
+
346
+
347
+ class RepositoryTimeoutError(RepositoryError):
348
+ """Raised when a repository query exceeds its timeout.
349
+
350
+ Used when:
351
+ - Query exceeds statement_timeout
352
+ - Connection acquisition times out
353
+ - Transaction times out
354
+
355
+ Timeout errors are retriable - the same query may succeed
356
+ under different load conditions or with adjusted timeouts.
357
+
358
+ Example:
359
+ >>> context = ModelInfraErrorContext.with_correlation(
360
+ ... transport_type=EnumInfraTransportType.DATABASE,
361
+ ... operation="execute_operation",
362
+ ... )
363
+ >>> raise RepositoryTimeoutError(
364
+ ... "Query exceeded 30s timeout",
365
+ ... op_name="complex_report",
366
+ ... table="analytics",
367
+ ... timeout_seconds=30.0,
368
+ ... sql_fingerprint="SELECT ... FROM analytics ...",
369
+ ... context=context,
370
+ ... )
371
+ """
372
+
373
+ _default_retriable: bool = True
374
+
375
+ def __init__(
376
+ self,
377
+ message: str,
378
+ *,
379
+ op_name: str | None = None,
380
+ table: str | None = None,
381
+ retriable: bool | None = None,
382
+ sql_fingerprint: str | None = None,
383
+ timeout_seconds: float | None = None,
384
+ context: ModelInfraErrorContext | None = None,
385
+ **extra_context: object,
386
+ ) -> None:
387
+ """Initialize RepositoryTimeoutError.
388
+
389
+ Args:
390
+ message: Human-readable error message
391
+ op_name: Operation name that timed out
392
+ table: Target table (if applicable)
393
+ retriable: Override default (True). Timeout errors are
394
+ generally retriable.
395
+ sql_fingerprint: SQL fingerprint for query tracking
396
+ timeout_seconds: The timeout value that was exceeded
397
+ context: Bundled infrastructure context
398
+ **extra_context: Additional context information
399
+ """
400
+ if timeout_seconds is not None:
401
+ extra_context["timeout_seconds"] = timeout_seconds
402
+
403
+ # Store for programmatic access
404
+ self.timeout_seconds = timeout_seconds
405
+
406
+ super().__init__(
407
+ message=message,
408
+ op_name=op_name,
409
+ table=table,
410
+ retriable=retriable,
411
+ sql_fingerprint=sql_fingerprint,
412
+ error_code=EnumCoreErrorCode.TIMEOUT_ERROR,
413
+ context=context,
414
+ **extra_context,
415
+ )
416
+
417
+
418
+ __all__ = [
419
+ "RepositoryContractError",
420
+ "RepositoryError",
421
+ "RepositoryExecutionError",
422
+ "RepositoryTimeoutError",
423
+ "RepositoryValidationError",
424
+ ]