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.
- omnibase_infra/__init__.py +1 -1
- omnibase_infra/enums/__init__.py +3 -0
- omnibase_infra/enums/enum_consumer_group_purpose.py +9 -0
- omnibase_infra/enums/enum_postgres_error_code.py +188 -0
- omnibase_infra/errors/__init__.py +4 -0
- omnibase_infra/errors/error_infra.py +60 -0
- omnibase_infra/handlers/__init__.py +3 -0
- omnibase_infra/handlers/handler_slack_webhook.py +426 -0
- omnibase_infra/handlers/models/__init__.py +14 -0
- omnibase_infra/handlers/models/enum_alert_severity.py +36 -0
- omnibase_infra/handlers/models/model_slack_alert.py +24 -0
- omnibase_infra/handlers/models/model_slack_alert_payload.py +77 -0
- omnibase_infra/handlers/models/model_slack_alert_result.py +73 -0
- omnibase_infra/handlers/registration_storage/handler_registration_storage_postgres.py +29 -20
- omnibase_infra/mixins/__init__.py +14 -0
- omnibase_infra/mixins/mixin_node_introspection.py +42 -20
- omnibase_infra/mixins/mixin_postgres_error_response.py +314 -0
- omnibase_infra/mixins/mixin_postgres_op_executor.py +298 -0
- omnibase_infra/models/__init__.py +3 -0
- omnibase_infra/models/discovery/model_dependency_spec.py +1 -0
- omnibase_infra/models/discovery/model_discovered_capabilities.py +1 -1
- omnibase_infra/models/discovery/model_introspection_config.py +28 -1
- omnibase_infra/models/discovery/model_introspection_performance_metrics.py +1 -0
- omnibase_infra/models/discovery/model_introspection_task_config.py +1 -0
- omnibase_infra/{nodes/effects/models → models}/model_backend_result.py +22 -6
- omnibase_infra/models/projection/__init__.py +11 -0
- omnibase_infra/models/projection/model_contract_projection.py +170 -0
- omnibase_infra/models/projection/model_topic_projection.py +148 -0
- omnibase_infra/models/runtime/__init__.py +4 -0
- omnibase_infra/models/runtime/model_resolved_dependencies.py +116 -0
- omnibase_infra/nodes/contract_registry_reducer/__init__.py +5 -0
- omnibase_infra/nodes/contract_registry_reducer/contract.yaml +6 -5
- omnibase_infra/nodes/contract_registry_reducer/contract_registration_event_router.py +689 -0
- omnibase_infra/nodes/contract_registry_reducer/reducer.py +9 -26
- omnibase_infra/nodes/effects/__init__.py +1 -1
- omnibase_infra/nodes/effects/models/__init__.py +6 -4
- omnibase_infra/nodes/effects/models/model_registry_response.py +1 -1
- omnibase_infra/nodes/effects/protocol_consul_client.py +1 -1
- omnibase_infra/nodes/effects/protocol_postgres_adapter.py +1 -1
- omnibase_infra/nodes/effects/registry_effect.py +1 -1
- omnibase_infra/nodes/node_contract_persistence_effect/__init__.py +101 -0
- omnibase_infra/nodes/node_contract_persistence_effect/contract.yaml +490 -0
- omnibase_infra/nodes/node_contract_persistence_effect/handlers/__init__.py +74 -0
- omnibase_infra/nodes/node_contract_persistence_effect/handlers/handler_postgres_cleanup_topics.py +217 -0
- omnibase_infra/nodes/node_contract_persistence_effect/handlers/handler_postgres_contract_upsert.py +242 -0
- omnibase_infra/nodes/node_contract_persistence_effect/handlers/handler_postgres_deactivate.py +194 -0
- omnibase_infra/nodes/node_contract_persistence_effect/handlers/handler_postgres_heartbeat.py +243 -0
- omnibase_infra/nodes/node_contract_persistence_effect/handlers/handler_postgres_mark_stale.py +208 -0
- omnibase_infra/nodes/node_contract_persistence_effect/handlers/handler_postgres_topic_update.py +298 -0
- omnibase_infra/nodes/node_contract_persistence_effect/models/__init__.py +15 -0
- omnibase_infra/nodes/node_contract_persistence_effect/models/model_persistence_result.py +52 -0
- omnibase_infra/nodes/node_contract_persistence_effect/node.py +131 -0
- omnibase_infra/nodes/node_contract_persistence_effect/registry/__init__.py +27 -0
- omnibase_infra/nodes/node_contract_persistence_effect/registry/registry_infra_contract_persistence_effect.py +251 -0
- omnibase_infra/nodes/node_registration_orchestrator/models/model_postgres_intent_payload.py +8 -12
- omnibase_infra/nodes/node_registry_effect/models/__init__.py +2 -2
- omnibase_infra/nodes/node_slack_alerter_effect/__init__.py +33 -0
- omnibase_infra/nodes/node_slack_alerter_effect/contract.yaml +291 -0
- omnibase_infra/nodes/node_slack_alerter_effect/node.py +106 -0
- omnibase_infra/projectors/__init__.py +6 -0
- omnibase_infra/projectors/projection_reader_contract.py +1301 -0
- omnibase_infra/runtime/__init__.py +12 -0
- omnibase_infra/runtime/baseline_subscriptions.py +13 -6
- omnibase_infra/runtime/contract_dependency_resolver.py +455 -0
- omnibase_infra/runtime/contract_registration_event_router.py +500 -0
- omnibase_infra/runtime/db/__init__.py +4 -0
- omnibase_infra/runtime/db/models/__init__.py +15 -10
- omnibase_infra/runtime/db/models/model_db_operation.py +40 -0
- omnibase_infra/runtime/db/models/model_db_param.py +24 -0
- omnibase_infra/runtime/db/models/model_db_repository_contract.py +40 -0
- omnibase_infra/runtime/db/models/model_db_return.py +26 -0
- omnibase_infra/runtime/db/models/model_db_safety_policy.py +32 -0
- omnibase_infra/runtime/emit_daemon/event_registry.py +34 -22
- omnibase_infra/runtime/event_bus_subcontract_wiring.py +63 -23
- omnibase_infra/runtime/intent_execution_router.py +430 -0
- omnibase_infra/runtime/models/__init__.py +6 -0
- omnibase_infra/runtime/models/model_contract_registry_config.py +41 -0
- omnibase_infra/runtime/models/model_intent_execution_summary.py +79 -0
- omnibase_infra/runtime/models/model_runtime_config.py +8 -0
- omnibase_infra/runtime/protocols/__init__.py +16 -0
- omnibase_infra/runtime/protocols/protocol_intent_executor.py +107 -0
- omnibase_infra/runtime/publisher_topic_scoped.py +16 -11
- omnibase_infra/runtime/registry_policy.py +29 -15
- omnibase_infra/runtime/request_response_wiring.py +793 -0
- omnibase_infra/runtime/service_kernel.py +295 -8
- omnibase_infra/runtime/service_runtime_host_process.py +149 -5
- omnibase_infra/runtime/util_version.py +5 -1
- omnibase_infra/schemas/schema_latency_baseline.sql +135 -0
- omnibase_infra/services/contract_publisher/config.py +4 -4
- omnibase_infra/services/contract_publisher/service.py +8 -5
- omnibase_infra/services/observability/injection_effectiveness/__init__.py +67 -0
- omnibase_infra/services/observability/injection_effectiveness/config.py +295 -0
- omnibase_infra/services/observability/injection_effectiveness/consumer.py +1461 -0
- omnibase_infra/services/observability/injection_effectiveness/models/__init__.py +32 -0
- omnibase_infra/services/observability/injection_effectiveness/models/model_agent_match.py +79 -0
- omnibase_infra/services/observability/injection_effectiveness/models/model_context_utilization.py +118 -0
- omnibase_infra/services/observability/injection_effectiveness/models/model_latency_breakdown.py +107 -0
- omnibase_infra/services/observability/injection_effectiveness/models/model_pattern_utilization.py +46 -0
- omnibase_infra/services/observability/injection_effectiveness/writer_postgres.py +596 -0
- omnibase_infra/services/registry_api/models/__init__.py +25 -0
- omnibase_infra/services/registry_api/models/model_contract_ref.py +44 -0
- omnibase_infra/services/registry_api/models/model_contract_view.py +81 -0
- omnibase_infra/services/registry_api/models/model_response_contracts.py +50 -0
- omnibase_infra/services/registry_api/models/model_response_topics.py +50 -0
- omnibase_infra/services/registry_api/models/model_topic_summary.py +57 -0
- omnibase_infra/services/registry_api/models/model_topic_view.py +63 -0
- omnibase_infra/services/registry_api/routes.py +205 -6
- omnibase_infra/services/registry_api/service.py +528 -1
- omnibase_infra/utils/__init__.py +7 -0
- omnibase_infra/utils/util_db_error_context.py +292 -0
- omnibase_infra/validation/infra_validators.py +3 -1
- omnibase_infra/validation/validation_exemptions.yaml +65 -0
- {omnibase_infra-0.3.1.dist-info → omnibase_infra-0.4.0.dist-info}/METADATA +3 -3
- {omnibase_infra-0.3.1.dist-info → omnibase_infra-0.4.0.dist-info}/RECORD +117 -58
- {omnibase_infra-0.3.1.dist-info → omnibase_infra-0.4.0.dist-info}/WHEEL +0 -0
- {omnibase_infra-0.3.1.dist-info → omnibase_infra-0.4.0.dist-info}/entry_points.txt +0 -0
- {omnibase_infra-0.3.1.dist-info → omnibase_infra-0.4.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Contract Projection Model.
|
|
4
|
+
|
|
5
|
+
Provides the Pydantic model for contract projections stored in PostgreSQL.
|
|
6
|
+
Used by the Registry API to query registered contracts and their metadata.
|
|
7
|
+
|
|
8
|
+
The contracts table stores registered ONEX contracts with full YAML content
|
|
9
|
+
for replay capability and Kafka position tracking for exactly-once semantics.
|
|
10
|
+
|
|
11
|
+
Related Tickets:
|
|
12
|
+
- OMN-1845: Create ProjectionReaderContract for contract/topic queries
|
|
13
|
+
- OMN-1653: Contract registry state materialization
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
from datetime import datetime
|
|
19
|
+
|
|
20
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class ModelContractProjection(BaseModel):
|
|
24
|
+
"""Contract projection for Registry API queries.
|
|
25
|
+
|
|
26
|
+
Represents a registered ONEX contract stored in PostgreSQL. This model
|
|
27
|
+
maps to the contracts table created by migration 005.
|
|
28
|
+
|
|
29
|
+
Primary Key:
|
|
30
|
+
contract_id - derived natural key: node_name:major.minor.patch
|
|
31
|
+
|
|
32
|
+
Attributes:
|
|
33
|
+
contract_id: Derived natural key (e.g., "my-node:1.0.0")
|
|
34
|
+
node_name: ONEX node name from contract metadata
|
|
35
|
+
version_major: Semantic version major component
|
|
36
|
+
version_minor: Semantic version minor component
|
|
37
|
+
version_patch: Semantic version patch component
|
|
38
|
+
contract_hash: SHA-256 hash of contract YAML for change detection
|
|
39
|
+
contract_yaml: Full contract YAML content for replay capability
|
|
40
|
+
registered_at: Timestamp when contract was first registered
|
|
41
|
+
deregistered_at: Timestamp when contract was deregistered (None if active)
|
|
42
|
+
last_seen_at: Timestamp of most recent heartbeat or registration event
|
|
43
|
+
is_active: Whether contract is currently active (soft delete)
|
|
44
|
+
last_event_topic: Kafka topic of last processed event (for dedupe)
|
|
45
|
+
last_event_partition: Kafka partition of last processed event (for dedupe)
|
|
46
|
+
last_event_offset: Kafka offset of last processed event (for dedupe)
|
|
47
|
+
created_at: Timestamp when row was created
|
|
48
|
+
updated_at: Timestamp when row was last updated
|
|
49
|
+
|
|
50
|
+
Example:
|
|
51
|
+
>>> from datetime import datetime, UTC
|
|
52
|
+
>>> now = datetime.now(UTC)
|
|
53
|
+
>>> projection = ModelContractProjection(
|
|
54
|
+
... contract_id="node-registry-effect:1.0.0",
|
|
55
|
+
... node_name="node-registry-effect",
|
|
56
|
+
... version_major=1,
|
|
57
|
+
... version_minor=0,
|
|
58
|
+
... version_patch=0,
|
|
59
|
+
... contract_hash="abc123...",
|
|
60
|
+
... contract_yaml="name: node-registry-effect\\n...",
|
|
61
|
+
... registered_at=now,
|
|
62
|
+
... last_seen_at=now,
|
|
63
|
+
... is_active=True,
|
|
64
|
+
... )
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
model_config = ConfigDict(
|
|
68
|
+
frozen=True,
|
|
69
|
+
extra="forbid",
|
|
70
|
+
from_attributes=True,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
# Identity
|
|
74
|
+
# ONEX_EXCLUDE: pattern_validator - contract_id is a derived natural key (name:version), not UUID
|
|
75
|
+
contract_id: str = Field(
|
|
76
|
+
...,
|
|
77
|
+
min_length=1,
|
|
78
|
+
description="Derived natural key: node_name:major.minor.patch",
|
|
79
|
+
)
|
|
80
|
+
# ONEX_EXCLUDE: pattern_validator - node_name is the contract name, not an entity reference
|
|
81
|
+
node_name: str = Field(
|
|
82
|
+
...,
|
|
83
|
+
min_length=1,
|
|
84
|
+
description="ONEX node name from contract metadata",
|
|
85
|
+
)
|
|
86
|
+
version_major: int = Field(
|
|
87
|
+
...,
|
|
88
|
+
ge=0,
|
|
89
|
+
description="Semantic version major component",
|
|
90
|
+
)
|
|
91
|
+
version_minor: int = Field(
|
|
92
|
+
...,
|
|
93
|
+
ge=0,
|
|
94
|
+
description="Semantic version minor component",
|
|
95
|
+
)
|
|
96
|
+
version_patch: int = Field(
|
|
97
|
+
...,
|
|
98
|
+
ge=0,
|
|
99
|
+
description="Semantic version patch component",
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
# Contract content
|
|
103
|
+
contract_hash: str = Field(
|
|
104
|
+
...,
|
|
105
|
+
min_length=1,
|
|
106
|
+
description="SHA-256 hash of contract YAML for change detection",
|
|
107
|
+
)
|
|
108
|
+
contract_yaml: str = Field(
|
|
109
|
+
...,
|
|
110
|
+
description="Full contract YAML content for replay capability",
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
# Lifecycle
|
|
114
|
+
registered_at: datetime = Field(
|
|
115
|
+
...,
|
|
116
|
+
description="Timestamp when contract was first registered",
|
|
117
|
+
)
|
|
118
|
+
deregistered_at: datetime | None = Field(
|
|
119
|
+
default=None,
|
|
120
|
+
description="Timestamp when contract was deregistered (None if active)",
|
|
121
|
+
)
|
|
122
|
+
last_seen_at: datetime = Field(
|
|
123
|
+
...,
|
|
124
|
+
description="Timestamp of most recent heartbeat or registration event",
|
|
125
|
+
)
|
|
126
|
+
is_active: bool = Field(
|
|
127
|
+
default=True,
|
|
128
|
+
description="Whether contract is currently active (soft delete)",
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
# Kafka position tracking (for exactly-once semantics)
|
|
132
|
+
last_event_topic: str | None = Field(
|
|
133
|
+
default=None,
|
|
134
|
+
description="Kafka topic of last processed event (for dedupe)",
|
|
135
|
+
)
|
|
136
|
+
last_event_partition: int | None = Field(
|
|
137
|
+
default=None,
|
|
138
|
+
description="Kafka partition of last processed event (for dedupe)",
|
|
139
|
+
)
|
|
140
|
+
last_event_offset: int | None = Field(
|
|
141
|
+
default=None,
|
|
142
|
+
description="Kafka offset of last processed event (for dedupe)",
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
# Audit timestamps
|
|
146
|
+
created_at: datetime | None = Field(
|
|
147
|
+
default=None,
|
|
148
|
+
description="Timestamp when row was created",
|
|
149
|
+
)
|
|
150
|
+
updated_at: datetime | None = Field(
|
|
151
|
+
default=None,
|
|
152
|
+
description="Timestamp when row was last updated",
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
@property
|
|
156
|
+
def version_string(self) -> str:
|
|
157
|
+
"""Return semantic version as string.
|
|
158
|
+
|
|
159
|
+
Returns:
|
|
160
|
+
Semantic version string (e.g., "1.0.0")
|
|
161
|
+
|
|
162
|
+
Example:
|
|
163
|
+
>>> proj = ModelContractProjection(version_major=1, version_minor=2, version_patch=3, ...)
|
|
164
|
+
>>> proj.version_string
|
|
165
|
+
'1.2.3'
|
|
166
|
+
"""
|
|
167
|
+
return f"{self.version_major}.{self.version_minor}.{self.version_patch}"
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
__all__: list[str] = ["ModelContractProjection"]
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Topic Projection Model.
|
|
4
|
+
|
|
5
|
+
Provides the Pydantic model for topic projections stored in PostgreSQL.
|
|
6
|
+
Used by the Registry API to query topic suffixes referenced by contracts
|
|
7
|
+
for routing discovery.
|
|
8
|
+
|
|
9
|
+
Topics use 5-segment naming (e.g., onex.evt.platform.contract-registered.v1)
|
|
10
|
+
and store SUFFIXES only - environment prefix is applied at runtime.
|
|
11
|
+
|
|
12
|
+
Related Tickets:
|
|
13
|
+
- OMN-1845: Create ProjectionReaderContract for contract/topic queries
|
|
14
|
+
- OMN-1653: Contract registry state materialization
|
|
15
|
+
- OMN-1709: Topic orphan handling documentation
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
from datetime import datetime
|
|
21
|
+
from typing import Literal
|
|
22
|
+
|
|
23
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
24
|
+
|
|
25
|
+
# Valid direction values for topic routing
|
|
26
|
+
TopicDirection = Literal["publish", "subscribe"]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class ModelTopicProjection(BaseModel):
|
|
30
|
+
"""Topic projection for Registry API queries.
|
|
31
|
+
|
|
32
|
+
Represents a topic suffix referenced by contracts for routing discovery.
|
|
33
|
+
This model maps to the topics table created by migration 005.
|
|
34
|
+
|
|
35
|
+
Primary Key:
|
|
36
|
+
(topic_suffix, direction) - composite key allowing same topic with
|
|
37
|
+
both publish and subscribe directions
|
|
38
|
+
|
|
39
|
+
Topic Orphan Handling (OMN-1709):
|
|
40
|
+
When all contracts referencing a topic are deregistered, the topic
|
|
41
|
+
record remains with an empty contract_ids list. This is intentional:
|
|
42
|
+
- Preserves topic routing history for auditing and debugging
|
|
43
|
+
- Allows topic reactivation if a new contract references the same topic
|
|
44
|
+
- Avoids complex cascading deletes during high-volume deregistration
|
|
45
|
+
|
|
46
|
+
Attributes:
|
|
47
|
+
topic_suffix: Topic suffix without environment prefix
|
|
48
|
+
direction: Whether contracts publish to or subscribe from this topic
|
|
49
|
+
contract_ids: List of contract_id strings that reference this topic
|
|
50
|
+
first_seen_at: Timestamp when topic was first seen in any contract
|
|
51
|
+
last_seen_at: Timestamp when topic was last seen in any contract
|
|
52
|
+
is_active: Whether topic is currently referenced by any active contract
|
|
53
|
+
created_at: Timestamp when row was created
|
|
54
|
+
updated_at: Timestamp when row was last updated
|
|
55
|
+
|
|
56
|
+
Example:
|
|
57
|
+
>>> from datetime import datetime, UTC
|
|
58
|
+
>>> now = datetime.now(UTC)
|
|
59
|
+
>>> projection = ModelTopicProjection(
|
|
60
|
+
... topic_suffix="onex.evt.platform.contract-registered.v1",
|
|
61
|
+
... direction="publish",
|
|
62
|
+
... contract_ids=["node-registry-effect:1.0.0"],
|
|
63
|
+
... first_seen_at=now,
|
|
64
|
+
... last_seen_at=now,
|
|
65
|
+
... is_active=True,
|
|
66
|
+
... )
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
model_config = ConfigDict(
|
|
70
|
+
frozen=True,
|
|
71
|
+
extra="forbid",
|
|
72
|
+
from_attributes=True,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
# Identity (composite primary key)
|
|
76
|
+
topic_suffix: str = Field(
|
|
77
|
+
...,
|
|
78
|
+
min_length=1,
|
|
79
|
+
description=(
|
|
80
|
+
"Topic suffix without environment prefix, "
|
|
81
|
+
"e.g., onex.evt.platform.contract-registered.v1"
|
|
82
|
+
),
|
|
83
|
+
)
|
|
84
|
+
direction: TopicDirection = Field(
|
|
85
|
+
...,
|
|
86
|
+
description="Whether contracts publish to or subscribe from this topic",
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
# Contract references (JSONB array in database)
|
|
90
|
+
contract_ids: list[str] = Field(
|
|
91
|
+
default_factory=list,
|
|
92
|
+
description="List of contract_id strings that reference this topic",
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
# Lifecycle
|
|
96
|
+
first_seen_at: datetime = Field(
|
|
97
|
+
...,
|
|
98
|
+
description="Timestamp when topic was first seen in any contract",
|
|
99
|
+
)
|
|
100
|
+
last_seen_at: datetime = Field(
|
|
101
|
+
...,
|
|
102
|
+
description="Timestamp when topic was last seen in any contract",
|
|
103
|
+
)
|
|
104
|
+
is_active: bool = Field(
|
|
105
|
+
default=True,
|
|
106
|
+
description="Whether topic is currently referenced by any active contract",
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
# Audit timestamps
|
|
110
|
+
created_at: datetime | None = Field(
|
|
111
|
+
default=None,
|
|
112
|
+
description="Timestamp when row was created",
|
|
113
|
+
)
|
|
114
|
+
updated_at: datetime | None = Field(
|
|
115
|
+
default=None,
|
|
116
|
+
description="Timestamp when row was last updated",
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
@property
|
|
120
|
+
def contract_count(self) -> int:
|
|
121
|
+
"""Return number of contracts referencing this topic.
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
Count of contract IDs
|
|
125
|
+
|
|
126
|
+
Example:
|
|
127
|
+
>>> proj = ModelTopicProjection(contract_ids=["a:1.0.0", "b:1.0.0"], ...)
|
|
128
|
+
>>> proj.contract_count
|
|
129
|
+
2
|
|
130
|
+
"""
|
|
131
|
+
return len(self.contract_ids)
|
|
132
|
+
|
|
133
|
+
@property
|
|
134
|
+
def is_orphaned(self) -> bool:
|
|
135
|
+
"""Check if topic is orphaned (no contracts reference it).
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
True if contract_ids is empty and topic is inactive
|
|
139
|
+
|
|
140
|
+
Example:
|
|
141
|
+
>>> proj = ModelTopicProjection(contract_ids=[], is_active=False, ...)
|
|
142
|
+
>>> proj.is_orphaned
|
|
143
|
+
True
|
|
144
|
+
"""
|
|
145
|
+
return len(self.contract_ids) == 0 and not self.is_active
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
__all__: list[str] = ["ModelTopicProjection", "TopicDirection"]
|
|
@@ -26,6 +26,9 @@ from omnibase_infra.models.runtime.model_plugin_load_context import (
|
|
|
26
26
|
from omnibase_infra.models.runtime.model_plugin_load_summary import (
|
|
27
27
|
ModelPluginLoadSummary,
|
|
28
28
|
)
|
|
29
|
+
from omnibase_infra.models.runtime.model_resolved_dependencies import (
|
|
30
|
+
ModelResolvedDependencies,
|
|
31
|
+
)
|
|
29
32
|
|
|
30
33
|
# ModelContractLoadResult and ModelRuntimeContractConfig are exported from
|
|
31
34
|
# omnibase_infra.runtime.models (canonical location for runtime loader models)
|
|
@@ -45,5 +48,6 @@ __all__ = [
|
|
|
45
48
|
"ModelLoadedHandler",
|
|
46
49
|
"ModelPluginLoadContext",
|
|
47
50
|
"ModelPluginLoadSummary",
|
|
51
|
+
"ModelResolvedDependencies",
|
|
48
52
|
"ModelRuntimeContractConfig",
|
|
49
53
|
]
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Model for resolved protocol dependencies.
|
|
4
|
+
|
|
5
|
+
This module provides ModelResolvedDependencies, a container for protocol
|
|
6
|
+
instances resolved from the container service_registry at node creation time.
|
|
7
|
+
|
|
8
|
+
Part of OMN-1732: Runtime dependency injection for zero-code nodes.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ModelResolvedDependencies(BaseModel):
|
|
19
|
+
"""Container for resolved protocol dependencies.
|
|
20
|
+
|
|
21
|
+
Holds protocol instances resolved from ModelONEXContainer.service_registry
|
|
22
|
+
for injection into node constructors. This model is immutable after creation.
|
|
23
|
+
|
|
24
|
+
The protocols dict maps protocol class names to their resolved instances:
|
|
25
|
+
- Key: Protocol class name (e.g., "ProtocolPostgresAdapter")
|
|
26
|
+
- Value: Resolved instance from container
|
|
27
|
+
|
|
28
|
+
Example:
|
|
29
|
+
>>> resolved = ModelResolvedDependencies(
|
|
30
|
+
... protocols={
|
|
31
|
+
... "ProtocolPostgresAdapter": postgres_adapter,
|
|
32
|
+
... "ProtocolCircuitBreakerAware": circuit_breaker,
|
|
33
|
+
... }
|
|
34
|
+
... )
|
|
35
|
+
>>> adapter = resolved.get("ProtocolPostgresAdapter")
|
|
36
|
+
|
|
37
|
+
.. versionadded:: 0.x.x
|
|
38
|
+
Part of OMN-1732 runtime dependency injection.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
model_config = ConfigDict(
|
|
42
|
+
frozen=True,
|
|
43
|
+
extra="forbid",
|
|
44
|
+
arbitrary_types_allowed=True, # Required for protocol instances
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
# ONEX_EXCLUDE: any_type - dict[str, Any] required for heterogeneous protocol instances
|
|
48
|
+
# resolved from container.service_registry. Type varies by protocol (ProtocolPostgresAdapter,
|
|
49
|
+
# ProtocolCircuitBreakerAware, etc.). Cannot use Union as protocols are open-ended.
|
|
50
|
+
protocols: dict[str, Any] = Field(
|
|
51
|
+
default_factory=dict,
|
|
52
|
+
description="Map of protocol class names to resolved instances",
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
# ONEX_EXCLUDE: any_type - returns heterogeneous protocol instance from protocols dict
|
|
56
|
+
def get(self, protocol_name: str) -> Any:
|
|
57
|
+
"""Get a resolved protocol by name.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
protocol_name: The protocol class name (e.g., "ProtocolPostgresAdapter")
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
The resolved protocol instance.
|
|
64
|
+
|
|
65
|
+
Raises:
|
|
66
|
+
KeyError: If protocol_name is not in the resolved protocols.
|
|
67
|
+
|
|
68
|
+
Example:
|
|
69
|
+
>>> adapter = resolved.get("ProtocolPostgresAdapter")
|
|
70
|
+
"""
|
|
71
|
+
if protocol_name not in self.protocols:
|
|
72
|
+
raise KeyError(
|
|
73
|
+
f"Protocol '{protocol_name}' not found in resolved dependencies. "
|
|
74
|
+
f"Available: {list(self.protocols.keys())}"
|
|
75
|
+
)
|
|
76
|
+
return self.protocols[protocol_name]
|
|
77
|
+
|
|
78
|
+
# ONEX_EXCLUDE: any_type - returns heterogeneous protocol instance, default can be any type
|
|
79
|
+
def get_optional(self, protocol_name: str, default: Any = None) -> Any:
|
|
80
|
+
"""Get a resolved protocol by name, returning default if not found.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
protocol_name: The protocol class name
|
|
84
|
+
default: Value to return if protocol not found
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
The resolved protocol instance or default.
|
|
88
|
+
"""
|
|
89
|
+
return self.protocols.get(protocol_name, default)
|
|
90
|
+
|
|
91
|
+
def has(self, protocol_name: str) -> bool:
|
|
92
|
+
"""Check if a protocol is available.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
protocol_name: The protocol class name
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
True if protocol is resolved, False otherwise.
|
|
99
|
+
"""
|
|
100
|
+
return protocol_name in self.protocols
|
|
101
|
+
|
|
102
|
+
def __len__(self) -> int:
|
|
103
|
+
"""Return number of resolved protocols."""
|
|
104
|
+
return len(self.protocols)
|
|
105
|
+
|
|
106
|
+
def __bool__(self) -> bool:
|
|
107
|
+
"""Return True if any protocols are resolved.
|
|
108
|
+
|
|
109
|
+
Warning:
|
|
110
|
+
**Non-standard __bool__ behavior**: Returns True only when
|
|
111
|
+
at least one protocol is resolved.
|
|
112
|
+
"""
|
|
113
|
+
return len(self.protocols) > 0
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
__all__ = ["ModelResolvedDependencies"]
|
|
@@ -9,9 +9,13 @@ the ONEX declarative pattern.
|
|
|
9
9
|
Exports:
|
|
10
10
|
NodeContractRegistryReducer: Declarative reducer node shell.
|
|
11
11
|
ContractRegistryReducer: Pure function reducer class.
|
|
12
|
+
ContractRegistrationEventRouter: Event router for Kafka messages.
|
|
12
13
|
ModelContractRegistryState: Immutable state model for the reducer.
|
|
13
14
|
"""
|
|
14
15
|
|
|
16
|
+
from omnibase_infra.nodes.contract_registry_reducer.contract_registration_event_router import (
|
|
17
|
+
ContractRegistrationEventRouter,
|
|
18
|
+
)
|
|
15
19
|
from omnibase_infra.nodes.contract_registry_reducer.models import (
|
|
16
20
|
ModelContractRegistryState,
|
|
17
21
|
)
|
|
@@ -23,6 +27,7 @@ from omnibase_infra.nodes.contract_registry_reducer.reducer import (
|
|
|
23
27
|
)
|
|
24
28
|
|
|
25
29
|
__all__ = [
|
|
30
|
+
"ContractRegistrationEventRouter",
|
|
26
31
|
"ContractRegistryReducer",
|
|
27
32
|
"ModelContractRegistryState",
|
|
28
33
|
"NodeContractRegistryReducer",
|
|
@@ -38,19 +38,20 @@ description: |
|
|
|
38
38
|
are separated.
|
|
39
39
|
# Event Consumption Configuration
|
|
40
40
|
# ================================
|
|
41
|
-
# Topics
|
|
41
|
+
# Topics are realm-agnostic: onex.{category}.{domain}.{event-name}.v{version}
|
|
42
42
|
# Categories: evt (external events), int (internal events), cmd (commands)
|
|
43
|
+
# Note: Environment/realm is enforced via envelope identity, not topic naming.
|
|
43
44
|
consumed_events:
|
|
44
|
-
- topic: "
|
|
45
|
+
- topic: "onex.evt.platform.contract-registered.v1"
|
|
45
46
|
event_type: "ModelContractRegisteredEvent"
|
|
46
47
|
description: "Contract registration from nodes on startup"
|
|
47
|
-
- topic: "
|
|
48
|
+
- topic: "onex.evt.platform.contract-deregistered.v1"
|
|
48
49
|
event_type: "ModelContractDeregisteredEvent"
|
|
49
50
|
description: "Explicit contract deregistration on graceful shutdown"
|
|
50
|
-
- topic: "
|
|
51
|
+
- topic: "onex.evt.platform.node-heartbeat.v1"
|
|
51
52
|
event_type: "ModelNodeHeartbeatEvent"
|
|
52
53
|
description: "Heartbeat for liveness tracking and last_seen_at updates"
|
|
53
|
-
- topic: "
|
|
54
|
+
- topic: "onex.int.platform.runtime-tick.v1"
|
|
54
55
|
event_type: "ModelRuntimeTick"
|
|
55
56
|
internal: true
|
|
56
57
|
description: "Periodic tick for staleness computation - marks contracts as stale/inactive"
|