omnibase_infra 0.3.1__py3-none-any.whl → 0.3.2__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 (72) 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/handlers/registration_storage/handler_registration_storage_postgres.py +29 -20
  6. omnibase_infra/mixins/__init__.py +14 -0
  7. omnibase_infra/mixins/mixin_postgres_error_response.py +314 -0
  8. omnibase_infra/mixins/mixin_postgres_op_executor.py +298 -0
  9. omnibase_infra/models/__init__.py +3 -0
  10. omnibase_infra/{nodes/effects/models → models}/model_backend_result.py +22 -6
  11. omnibase_infra/models/projection/__init__.py +11 -0
  12. omnibase_infra/models/projection/model_contract_projection.py +170 -0
  13. omnibase_infra/models/projection/model_topic_projection.py +148 -0
  14. omnibase_infra/nodes/contract_registry_reducer/__init__.py +5 -0
  15. omnibase_infra/nodes/contract_registry_reducer/contract_registration_event_router.py +689 -0
  16. omnibase_infra/nodes/effects/__init__.py +1 -1
  17. omnibase_infra/nodes/effects/models/__init__.py +6 -4
  18. omnibase_infra/nodes/effects/models/model_registry_response.py +1 -1
  19. omnibase_infra/nodes/effects/protocol_consul_client.py +1 -1
  20. omnibase_infra/nodes/effects/protocol_postgres_adapter.py +1 -1
  21. omnibase_infra/nodes/effects/registry_effect.py +1 -1
  22. omnibase_infra/nodes/node_contract_persistence_effect/__init__.py +101 -0
  23. omnibase_infra/nodes/node_contract_persistence_effect/contract.yaml +490 -0
  24. omnibase_infra/nodes/node_contract_persistence_effect/handlers/__init__.py +74 -0
  25. omnibase_infra/nodes/node_contract_persistence_effect/handlers/handler_postgres_cleanup_topics.py +217 -0
  26. omnibase_infra/nodes/node_contract_persistence_effect/handlers/handler_postgres_contract_upsert.py +242 -0
  27. omnibase_infra/nodes/node_contract_persistence_effect/handlers/handler_postgres_deactivate.py +194 -0
  28. omnibase_infra/nodes/node_contract_persistence_effect/handlers/handler_postgres_heartbeat.py +243 -0
  29. omnibase_infra/nodes/node_contract_persistence_effect/handlers/handler_postgres_mark_stale.py +208 -0
  30. omnibase_infra/nodes/node_contract_persistence_effect/handlers/handler_postgres_topic_update.py +298 -0
  31. omnibase_infra/nodes/node_contract_persistence_effect/models/__init__.py +15 -0
  32. omnibase_infra/nodes/node_contract_persistence_effect/models/model_persistence_result.py +52 -0
  33. omnibase_infra/nodes/node_contract_persistence_effect/node.py +114 -0
  34. omnibase_infra/nodes/node_contract_persistence_effect/registry/__init__.py +27 -0
  35. omnibase_infra/nodes/node_contract_persistence_effect/registry/registry_infra_contract_persistence_effect.py +220 -0
  36. omnibase_infra/nodes/node_registry_effect/models/__init__.py +2 -2
  37. omnibase_infra/projectors/__init__.py +6 -0
  38. omnibase_infra/projectors/projection_reader_contract.py +1301 -0
  39. omnibase_infra/runtime/__init__.py +5 -0
  40. omnibase_infra/runtime/contract_registration_event_router.py +500 -0
  41. omnibase_infra/runtime/db/__init__.py +4 -0
  42. omnibase_infra/runtime/db/models/__init__.py +15 -10
  43. omnibase_infra/runtime/db/models/model_db_operation.py +40 -0
  44. omnibase_infra/runtime/db/models/model_db_param.py +24 -0
  45. omnibase_infra/runtime/db/models/model_db_repository_contract.py +40 -0
  46. omnibase_infra/runtime/db/models/model_db_return.py +26 -0
  47. omnibase_infra/runtime/db/models/model_db_safety_policy.py +32 -0
  48. omnibase_infra/runtime/intent_execution_router.py +430 -0
  49. omnibase_infra/runtime/models/__init__.py +6 -0
  50. omnibase_infra/runtime/models/model_contract_registry_config.py +41 -0
  51. omnibase_infra/runtime/models/model_intent_execution_summary.py +79 -0
  52. omnibase_infra/runtime/models/model_runtime_config.py +8 -0
  53. omnibase_infra/runtime/protocols/__init__.py +16 -0
  54. omnibase_infra/runtime/protocols/protocol_intent_executor.py +107 -0
  55. omnibase_infra/runtime/request_response_wiring.py +785 -0
  56. omnibase_infra/runtime/service_kernel.py +295 -8
  57. omnibase_infra/services/registry_api/models/__init__.py +25 -0
  58. omnibase_infra/services/registry_api/models/model_contract_ref.py +44 -0
  59. omnibase_infra/services/registry_api/models/model_contract_view.py +81 -0
  60. omnibase_infra/services/registry_api/models/model_response_contracts.py +50 -0
  61. omnibase_infra/services/registry_api/models/model_response_topics.py +50 -0
  62. omnibase_infra/services/registry_api/models/model_topic_summary.py +57 -0
  63. omnibase_infra/services/registry_api/models/model_topic_view.py +63 -0
  64. omnibase_infra/services/registry_api/routes.py +205 -6
  65. omnibase_infra/services/registry_api/service.py +528 -1
  66. omnibase_infra/validation/infra_validators.py +3 -1
  67. omnibase_infra/validation/validation_exemptions.yaml +54 -0
  68. {omnibase_infra-0.3.1.dist-info → omnibase_infra-0.3.2.dist-info}/METADATA +3 -3
  69. {omnibase_infra-0.3.1.dist-info → omnibase_infra-0.3.2.dist-info}/RECORD +72 -34
  70. {omnibase_infra-0.3.1.dist-info → omnibase_infra-0.3.2.dist-info}/WHEEL +0 -0
  71. {omnibase_infra-0.3.1.dist-info → omnibase_infra-0.3.2.dist-info}/entry_points.txt +0 -0
  72. {omnibase_infra-0.3.1.dist-info → omnibase_infra-0.3.2.dist-info}/licenses/LICENSE +0 -0
@@ -8,12 +8,15 @@ by orchestrators to query current entity state.
8
8
 
9
9
  Exports:
10
10
  ModelCapabilityFields: Container for capability fields in projection persistence
11
+ ModelContractProjection: Contract projection for Registry API queries
11
12
  ModelRegistrationProjection: Registration projection for orchestrator state queries
12
13
  ModelRegistrationSnapshot: Compacted snapshot for read optimization
13
14
  ModelSequenceInfo: Sequence information for projection ordering and idempotency
14
15
  ModelSnapshotTopicConfig: Kafka topic configuration for snapshot publishing
16
+ ModelTopicProjection: Topic projection for Registry API queries
15
17
 
16
18
  Related Tickets:
19
+ - OMN-1845: Create ProjectionReaderContract for contract/topic queries
17
20
  - OMN-1134: Registry Projection Extensions for Capabilities
18
21
  - OMN-947 (F2): Snapshot Publishing
19
22
  - OMN-944 (F1): Implement Registration Projection Schema
@@ -23,6 +26,9 @@ Related Tickets:
23
26
  from omnibase_infra.models.projection.model_capability_fields import (
24
27
  ModelCapabilityFields,
25
28
  )
29
+ from omnibase_infra.models.projection.model_contract_projection import (
30
+ ModelContractProjection,
31
+ )
26
32
  from omnibase_infra.models.projection.model_registration_projection import (
27
33
  ModelRegistrationProjection,
28
34
  )
@@ -33,11 +39,16 @@ from omnibase_infra.models.projection.model_sequence_info import ModelSequenceIn
33
39
  from omnibase_infra.models.projection.model_snapshot_topic_config import (
34
40
  ModelSnapshotTopicConfig,
35
41
  )
42
+ from omnibase_infra.models.projection.model_topic_projection import (
43
+ ModelTopicProjection,
44
+ )
36
45
 
37
46
  __all__ = [
38
47
  "ModelCapabilityFields",
48
+ "ModelContractProjection",
39
49
  "ModelRegistrationProjection",
40
50
  "ModelRegistrationSnapshot",
41
51
  "ModelSequenceInfo",
42
52
  "ModelSnapshotTopicConfig",
53
+ "ModelTopicProjection",
43
54
  ]
@@ -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"]
@@ -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",