omnibase_infra 0.2.7__py3-none-any.whl → 0.2.9__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 (79) 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/event_bus/adapters/__init__.py +31 -0
  5. omnibase_infra/event_bus/adapters/adapter_protocol_event_publisher_kafka.py +517 -0
  6. omnibase_infra/mixins/mixin_async_circuit_breaker.py +113 -1
  7. omnibase_infra/models/__init__.py +9 -0
  8. omnibase_infra/models/event_bus/__init__.py +22 -0
  9. omnibase_infra/models/event_bus/model_consumer_retry_config.py +367 -0
  10. omnibase_infra/models/event_bus/model_dlq_config.py +177 -0
  11. omnibase_infra/models/event_bus/model_idempotency_config.py +131 -0
  12. omnibase_infra/models/event_bus/model_offset_policy_config.py +107 -0
  13. omnibase_infra/models/resilience/model_circuit_breaker_config.py +15 -0
  14. omnibase_infra/models/validation/__init__.py +8 -0
  15. omnibase_infra/models/validation/model_declarative_node_validation_result.py +139 -0
  16. omnibase_infra/models/validation/model_declarative_node_violation.py +169 -0
  17. omnibase_infra/nodes/architecture_validator/__init__.py +28 -7
  18. omnibase_infra/nodes/architecture_validator/constants.py +36 -0
  19. omnibase_infra/nodes/architecture_validator/handlers/__init__.py +28 -0
  20. omnibase_infra/nodes/architecture_validator/handlers/contract.yaml +120 -0
  21. omnibase_infra/nodes/architecture_validator/handlers/handler_architecture_validation.py +359 -0
  22. omnibase_infra/nodes/architecture_validator/node.py +1 -0
  23. omnibase_infra/nodes/architecture_validator/node_architecture_validator.py +48 -336
  24. omnibase_infra/nodes/node_ledger_projection_compute/__init__.py +16 -2
  25. omnibase_infra/nodes/node_ledger_projection_compute/contract.yaml +14 -4
  26. omnibase_infra/nodes/node_ledger_projection_compute/handlers/__init__.py +18 -0
  27. omnibase_infra/nodes/node_ledger_projection_compute/handlers/contract.yaml +53 -0
  28. omnibase_infra/nodes/node_ledger_projection_compute/handlers/handler_ledger_projection.py +354 -0
  29. omnibase_infra/nodes/node_ledger_projection_compute/node.py +20 -256
  30. omnibase_infra/nodes/node_registry_effect/node.py +20 -73
  31. omnibase_infra/protocols/protocol_dispatch_engine.py +90 -0
  32. omnibase_infra/runtime/__init__.py +11 -0
  33. omnibase_infra/runtime/baseline_subscriptions.py +150 -0
  34. omnibase_infra/runtime/event_bus_subcontract_wiring.py +455 -24
  35. omnibase_infra/runtime/kafka_contract_source.py +13 -5
  36. omnibase_infra/runtime/service_message_dispatch_engine.py +112 -0
  37. omnibase_infra/runtime/service_runtime_host_process.py +6 -11
  38. omnibase_infra/services/__init__.py +36 -0
  39. omnibase_infra/services/contract_publisher/__init__.py +95 -0
  40. omnibase_infra/services/contract_publisher/config.py +199 -0
  41. omnibase_infra/services/contract_publisher/errors.py +243 -0
  42. omnibase_infra/services/contract_publisher/models/__init__.py +28 -0
  43. omnibase_infra/services/contract_publisher/models/model_contract_error.py +67 -0
  44. omnibase_infra/services/contract_publisher/models/model_infra_error.py +62 -0
  45. omnibase_infra/services/contract_publisher/models/model_publish_result.py +112 -0
  46. omnibase_infra/services/contract_publisher/models/model_publish_stats.py +79 -0
  47. omnibase_infra/services/contract_publisher/service.py +617 -0
  48. omnibase_infra/services/contract_publisher/sources/__init__.py +52 -0
  49. omnibase_infra/services/contract_publisher/sources/model_discovered.py +155 -0
  50. omnibase_infra/services/contract_publisher/sources/protocol.py +101 -0
  51. omnibase_infra/services/contract_publisher/sources/source_composite.py +309 -0
  52. omnibase_infra/services/contract_publisher/sources/source_filesystem.py +174 -0
  53. omnibase_infra/services/contract_publisher/sources/source_package.py +221 -0
  54. omnibase_infra/services/observability/__init__.py +40 -0
  55. omnibase_infra/services/observability/agent_actions/__init__.py +64 -0
  56. omnibase_infra/services/observability/agent_actions/config.py +209 -0
  57. omnibase_infra/services/observability/agent_actions/consumer.py +1320 -0
  58. omnibase_infra/services/observability/agent_actions/models/__init__.py +87 -0
  59. omnibase_infra/services/observability/agent_actions/models/model_agent_action.py +142 -0
  60. omnibase_infra/services/observability/agent_actions/models/model_detection_failure.py +125 -0
  61. omnibase_infra/services/observability/agent_actions/models/model_envelope.py +85 -0
  62. omnibase_infra/services/observability/agent_actions/models/model_execution_log.py +159 -0
  63. omnibase_infra/services/observability/agent_actions/models/model_performance_metric.py +130 -0
  64. omnibase_infra/services/observability/agent_actions/models/model_routing_decision.py +138 -0
  65. omnibase_infra/services/observability/agent_actions/models/model_transformation_event.py +124 -0
  66. omnibase_infra/services/observability/agent_actions/tests/__init__.py +20 -0
  67. omnibase_infra/services/observability/agent_actions/tests/test_consumer.py +1154 -0
  68. omnibase_infra/services/observability/agent_actions/tests/test_models.py +645 -0
  69. omnibase_infra/services/observability/agent_actions/tests/test_writer.py +709 -0
  70. omnibase_infra/services/observability/agent_actions/writer_postgres.py +926 -0
  71. omnibase_infra/validation/__init__.py +12 -0
  72. omnibase_infra/validation/contracts/declarative_node.validation.yaml +143 -0
  73. omnibase_infra/validation/validation_exemptions.yaml +93 -0
  74. omnibase_infra/validation/validator_declarative_node.py +850 -0
  75. {omnibase_infra-0.2.7.dist-info → omnibase_infra-0.2.9.dist-info}/METADATA +3 -3
  76. {omnibase_infra-0.2.7.dist-info → omnibase_infra-0.2.9.dist-info}/RECORD +79 -27
  77. {omnibase_infra-0.2.7.dist-info → omnibase_infra-0.2.9.dist-info}/WHEEL +0 -0
  78. {omnibase_infra-0.2.7.dist-info → omnibase_infra-0.2.9.dist-info}/entry_points.txt +0 -0
  79. {omnibase_infra-0.2.7.dist-info → omnibase_infra-0.2.9.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,174 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2025 OmniNode Team
3
+ """Filesystem Contract Source.
4
+
5
+ Discovers contracts from a directory tree by globbing for contract.yaml files.
6
+ This is the primary source for local development and CI/CD environments.
7
+
8
+ Discovery Pattern:
9
+ Globs for **/contract.yaml under the configured root directory.
10
+
11
+ .. versionadded:: 0.3.0
12
+ Created as part of OMN-1752 (ContractPublisher extraction).
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import logging
18
+ from pathlib import Path
19
+
20
+ from omnibase_infra.services.contract_publisher.errors import (
21
+ ContractSourceNotConfiguredError,
22
+ )
23
+ from omnibase_infra.services.contract_publisher.sources.model_discovered import (
24
+ ModelDiscoveredContract,
25
+ )
26
+
27
+ logger = logging.getLogger(__name__)
28
+
29
+
30
+ class SourceContractFilesystem:
31
+ """Filesystem-based contract source.
32
+
33
+ Recursively scans a directory for contract.yaml files and returns
34
+ them as ModelDiscoveredContract instances.
35
+
36
+ Discovery:
37
+ Uses Path.glob("**/contract.yaml") to find all contract files
38
+ under the root directory.
39
+
40
+ Error Handling:
41
+ - If root doesn't exist: Raises ContractSourceNotConfiguredError
42
+ - If root is not a directory: Raises ContractSourceNotConfiguredError
43
+ - If file read fails: Logs warning, skips file, continues
44
+
45
+ Attributes:
46
+ _root: Root directory for discovery
47
+
48
+ Example:
49
+ >>> source = SourceContractFilesystem(Path("/app/contracts"))
50
+ >>> contracts = await source.discover_contracts()
51
+ >>> for contract in contracts:
52
+ ... print(f"Found: {contract.ref}")
53
+
54
+ .. versionadded:: 0.3.0
55
+ """
56
+
57
+ __slots__ = ("_root",)
58
+
59
+ def __init__(self, root: Path) -> None:
60
+ """Initialize filesystem source.
61
+
62
+ Args:
63
+ root: Root directory for contract discovery
64
+ """
65
+ self._root = root
66
+
67
+ @property
68
+ def source_type(self) -> str:
69
+ """Return source type identifier.
70
+
71
+ Returns:
72
+ "filesystem"
73
+ """
74
+ return "filesystem"
75
+
76
+ @property
77
+ def source_description(self) -> str:
78
+ """Return human-readable source description.
79
+
80
+ Returns:
81
+ Description including the root path
82
+ """
83
+ return f"filesystem: {self._root}"
84
+
85
+ @property
86
+ def root(self) -> Path:
87
+ """Return the root directory.
88
+
89
+ Returns:
90
+ Root directory Path
91
+ """
92
+ return self._root
93
+
94
+ async def discover_contracts(self) -> list[ModelDiscoveredContract]:
95
+ """Discover all contracts from the filesystem.
96
+
97
+ Globs for **/contract.yaml under the root directory and reads
98
+ each file's contents.
99
+
100
+ Returns:
101
+ List of discovered contracts with origin="filesystem"
102
+
103
+ Raises:
104
+ ContractSourceNotConfiguredError: If the filesystem root does not
105
+ exist or is not a directory. This indicates a configuration
106
+ problem that should be fixed rather than silently ignored.
107
+
108
+ Note:
109
+ Individual file read failures are logged and skipped.
110
+
111
+ Note:
112
+ This method is ``async`` for protocol consistency with
113
+ :class:`ProtocolContractPublisherSource`. The underlying file I/O
114
+ is synchronous, which is acceptable for this use case as contract
115
+ discovery is an infrequent startup operation.
116
+ """
117
+ if not self._root.exists():
118
+ logger.warning(
119
+ "Filesystem source root does not exist: %s",
120
+ self._root,
121
+ )
122
+ raise ContractSourceNotConfiguredError(
123
+ mode="filesystem",
124
+ missing_field="filesystem_root",
125
+ message=f"Filesystem root does not exist: {self._root}",
126
+ )
127
+
128
+ if not self._root.is_dir():
129
+ logger.warning(
130
+ "Filesystem source root is not a directory: %s",
131
+ self._root,
132
+ )
133
+ raise ContractSourceNotConfiguredError(
134
+ mode="filesystem",
135
+ missing_field="filesystem_root",
136
+ message=f"Filesystem root is not a directory: {self._root}",
137
+ )
138
+
139
+ contracts: list[ModelDiscoveredContract] = []
140
+
141
+ # Glob for contract.yaml files
142
+ for contract_path in self._root.glob("**/contract.yaml"):
143
+ try:
144
+ text = contract_path.read_text(encoding="utf-8")
145
+ contract = ModelDiscoveredContract(
146
+ origin="filesystem",
147
+ ref=contract_path,
148
+ text=text,
149
+ )
150
+ contracts.append(contract)
151
+
152
+ logger.debug(
153
+ "Discovered contract: %s",
154
+ contract_path,
155
+ )
156
+
157
+ except (OSError, UnicodeDecodeError) as e:
158
+ logger.warning(
159
+ "Failed to read contract file %s: %s",
160
+ contract_path,
161
+ e,
162
+ )
163
+ # Continue with other files
164
+
165
+ logger.info(
166
+ "Filesystem discovery complete: found %d contracts in %s",
167
+ len(contracts),
168
+ self._root,
169
+ )
170
+
171
+ return contracts
172
+
173
+
174
+ __all__ = ["SourceContractFilesystem"]
@@ -0,0 +1,221 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2025 OmniNode Team
3
+ """Package Resource Contract Source.
4
+
5
+ Discovers contracts from installed Python package resources using
6
+ importlib.resources. This is the primary source for containerized
7
+ deployments where contracts ship with the wheel.
8
+
9
+ Discovery Pattern:
10
+ Traverses package resources looking for contract.yaml files.
11
+
12
+ .. versionadded:: 0.3.0
13
+ Created as part of OMN-1752 (ContractPublisher extraction).
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import logging
19
+ from importlib import resources
20
+ from importlib.resources.abc import Traversable
21
+
22
+ from omnibase_infra.services.contract_publisher.errors import (
23
+ ContractSourceNotConfiguredError,
24
+ )
25
+ from omnibase_infra.services.contract_publisher.sources.model_discovered import (
26
+ ModelDiscoveredContract,
27
+ )
28
+
29
+ logger = logging.getLogger(__name__)
30
+
31
+
32
+ class SourceContractPackage:
33
+ """Package resource-based contract source.
34
+
35
+ Discovers contracts from installed Python package resources using
36
+ importlib.resources API. Recursively traverses the package looking
37
+ for contract.yaml files.
38
+
39
+ Requirements:
40
+ - The package must be installed (importable)
41
+ - Contract files must be named "contract.yaml"
42
+ - Package must include resources (MANIFEST.in or package_data)
43
+
44
+ Attributes:
45
+ _package_module: Fully qualified module name (e.g., "myapp.contracts")
46
+
47
+ Example:
48
+ >>> source = SourceContractPackage("myapp.contracts.handlers")
49
+ >>> contracts = await source.discover_contracts()
50
+ >>> for contract in contracts:
51
+ ... print(f"Found: {contract.ref}")
52
+
53
+ .. versionadded:: 0.3.0
54
+ """
55
+
56
+ __slots__ = ("_package_module",)
57
+
58
+ def __init__(self, package_module: str) -> None:
59
+ """Initialize package source.
60
+
61
+ Args:
62
+ package_module: Fully qualified module name for contract discovery
63
+ (e.g., "myapp.contracts" or "myapp.contracts.handlers")
64
+ """
65
+ self._package_module = package_module
66
+
67
+ @property
68
+ def source_type(self) -> str:
69
+ """Return source type identifier.
70
+
71
+ Returns:
72
+ "package"
73
+ """
74
+ return "package"
75
+
76
+ @property
77
+ def source_description(self) -> str:
78
+ """Return human-readable source description.
79
+
80
+ Returns:
81
+ Description including the package module
82
+ """
83
+ return f"package: {self._package_module}"
84
+
85
+ @property
86
+ def package_module(self) -> str:
87
+ """Return the package module name.
88
+
89
+ Returns:
90
+ Package module name
91
+ """
92
+ return self._package_module
93
+
94
+ async def discover_contracts(self) -> list[ModelDiscoveredContract]:
95
+ """Discover all contracts from the package.
96
+
97
+ Uses importlib.resources to traverse the package and find
98
+ contract.yaml files.
99
+
100
+ Returns:
101
+ List of discovered contracts with origin="package"
102
+
103
+ Raises:
104
+ ContractSourceNotConfiguredError: If the package is not found
105
+ (not installed) or is invalid for resource discovery.
106
+
107
+ Note:
108
+ Individual resource read failures during traversal are logged
109
+ and skipped, but the discovery continues.
110
+
111
+ Note:
112
+ This method is ``async`` for protocol consistency with
113
+ :class:`ProtocolContractPublisherSource`. The underlying package
114
+ resource traversal is synchronous, which is acceptable for this
115
+ use case as contract discovery is an infrequent startup operation.
116
+ """
117
+ contracts: list[ModelDiscoveredContract] = []
118
+
119
+ try:
120
+ # Get the package root as a Traversable
121
+ package_root = resources.files(self._package_module)
122
+
123
+ # Recursively discover contracts
124
+ self._discover_recursive(package_root, "", contracts)
125
+
126
+ except ModuleNotFoundError:
127
+ logger.warning(
128
+ "Package not found: %s",
129
+ self._package_module,
130
+ )
131
+ raise ContractSourceNotConfiguredError(
132
+ mode="package",
133
+ missing_field="package_module",
134
+ message=f"Package not found: {self._package_module}",
135
+ )
136
+
137
+ except TypeError as e:
138
+ # resources.files() can raise TypeError for invalid packages
139
+ logger.warning(
140
+ "Invalid package for resource discovery: %s - %s",
141
+ self._package_module,
142
+ e,
143
+ )
144
+ raise ContractSourceNotConfiguredError(
145
+ mode="package",
146
+ missing_field="package_module",
147
+ message=f"Invalid package for resource discovery: {self._package_module} - {e}",
148
+ )
149
+
150
+ logger.info(
151
+ "Package discovery complete: found %d contracts in %s",
152
+ len(contracts),
153
+ self._package_module,
154
+ )
155
+
156
+ return contracts
157
+
158
+ def _discover_recursive(
159
+ self,
160
+ traversable: Traversable,
161
+ path_prefix: str,
162
+ contracts: list[ModelDiscoveredContract],
163
+ ) -> None:
164
+ """Recursively discover contracts from a Traversable.
165
+
166
+ Args:
167
+ traversable: Current package resource to traverse
168
+ path_prefix: Path prefix for building resource paths
169
+ contracts: List to append discovered contracts to
170
+ """
171
+ try:
172
+ # Check if this is a directory
173
+ if not traversable.is_dir():
174
+ return
175
+
176
+ # Iterate children
177
+ for child in traversable.iterdir():
178
+ child_name = child.name
179
+ child_path = (
180
+ f"{path_prefix}/{child_name}" if path_prefix else child_name
181
+ )
182
+
183
+ if child.is_file() and child_name == "contract.yaml":
184
+ # Found a contract file
185
+ try:
186
+ text = child.read_text(encoding="utf-8")
187
+ resource_path = f"{self._package_module}:{child_path}"
188
+
189
+ contract = ModelDiscoveredContract(
190
+ origin="package",
191
+ ref=resource_path,
192
+ text=text,
193
+ )
194
+ contracts.append(contract)
195
+
196
+ logger.debug(
197
+ "Discovered contract: %s",
198
+ resource_path,
199
+ )
200
+
201
+ except OSError as e:
202
+ logger.warning(
203
+ "Failed to read package resource %s: %s",
204
+ child_path,
205
+ e,
206
+ )
207
+
208
+ elif child.is_dir():
209
+ # Recurse into subdirectory
210
+ self._discover_recursive(child, child_path, contracts)
211
+
212
+ except OSError as e:
213
+ logger.warning(
214
+ "Error traversing package %s at %s: %s",
215
+ self._package_module,
216
+ path_prefix,
217
+ e,
218
+ )
219
+
220
+
221
+ __all__ = ["SourceContractPackage"]
@@ -0,0 +1,40 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2025 OmniNode Team
3
+ """Observability services for agent telemetry and monitoring.
4
+
5
+ This module provides infrastructure for collecting, processing, and persisting
6
+ agent observability data including actions, routing decisions, and performance
7
+ metrics.
8
+
9
+ Submodules:
10
+ - agent_actions: Consumer and writer for agent action events
11
+
12
+ Example:
13
+ >>> from omnibase_infra.services.observability import (
14
+ ... AgentActionsConsumer,
15
+ ... ConfigAgentActionsConsumer,
16
+ ... WriterAgentActionsPostgres,
17
+ ... )
18
+ >>>
19
+ >>> config = ConfigAgentActionsConsumer(
20
+ ... kafka_bootstrap_servers="localhost:9092",
21
+ ... postgres_dsn="postgresql://postgres:secret@localhost:5432/omninode_bridge",
22
+ ... )
23
+ >>> consumer = AgentActionsConsumer(config)
24
+ >>>
25
+ >>> # Run consumer
26
+ >>> await consumer.start()
27
+ >>> await consumer.run()
28
+ """
29
+
30
+ from omnibase_infra.services.observability.agent_actions import (
31
+ AgentActionsConsumer,
32
+ ConfigAgentActionsConsumer,
33
+ WriterAgentActionsPostgres,
34
+ )
35
+
36
+ __all__ = [
37
+ "AgentActionsConsumer",
38
+ "ConfigAgentActionsConsumer",
39
+ "WriterAgentActionsPostgres",
40
+ ]
@@ -0,0 +1,64 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2025 OmniNode Team
3
+ """Agent actions observability consumer and writer.
4
+
5
+ This module provides infrastructure for consuming agent action events from
6
+ Kafka and persisting them to PostgreSQL for observability and analytics.
7
+
8
+ Moved from omniclaude as part of OMN-1743 layer-correction cleanup.
9
+
10
+ Components:
11
+ - AgentActionsConsumer: Async Kafka consumer with per-partition offset tracking
12
+ - ConfigAgentActionsConsumer: Configuration for the consumer
13
+ - WriterAgentActionsPostgres: PostgreSQL writer for observability events
14
+
15
+ Topics consumed:
16
+ - agent-actions
17
+ - agent-routing-decisions
18
+ - agent-transformation-events
19
+ - router-performance-metrics
20
+ - agent-detection-failures
21
+ - agent-execution-logs
22
+
23
+ Example:
24
+ >>> from omnibase_infra.services.observability.agent_actions import (
25
+ ... AgentActionsConsumer,
26
+ ... ConfigAgentActionsConsumer,
27
+ ... WriterAgentActionsPostgres,
28
+ ... )
29
+ >>>
30
+ >>> config = ConfigAgentActionsConsumer(
31
+ ... kafka_bootstrap_servers="localhost:9092",
32
+ ... postgres_dsn="postgresql://postgres:secret@localhost:5432/omninode_bridge",
33
+ ... )
34
+ >>> consumer = AgentActionsConsumer(config)
35
+ >>>
36
+ >>> # Run consumer
37
+ >>> await consumer.start()
38
+ >>> await consumer.run()
39
+
40
+ # Or run as module:
41
+ # python -m omnibase_infra.services.observability.agent_actions.consumer
42
+ """
43
+
44
+ from omnibase_infra.services.observability.agent_actions.config import (
45
+ ConfigAgentActionsConsumer,
46
+ )
47
+ from omnibase_infra.services.observability.agent_actions.consumer import (
48
+ AgentActionsConsumer,
49
+ ConsumerMetrics,
50
+ EnumHealthStatus,
51
+ mask_dsn_password,
52
+ )
53
+ from omnibase_infra.services.observability.agent_actions.writer_postgres import (
54
+ WriterAgentActionsPostgres,
55
+ )
56
+
57
+ __all__ = [
58
+ "AgentActionsConsumer",
59
+ "ConfigAgentActionsConsumer",
60
+ "ConsumerMetrics",
61
+ "EnumHealthStatus",
62
+ "WriterAgentActionsPostgres",
63
+ "mask_dsn_password",
64
+ ]