omnibase_infra 0.2.5__py3-none-any.whl → 0.2.7__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/constants_topic_patterns.py +26 -0
- omnibase_infra/enums/__init__.py +3 -0
- omnibase_infra/enums/enum_consumer_group_purpose.py +92 -0
- omnibase_infra/enums/enum_handler_source_mode.py +16 -2
- omnibase_infra/errors/__init__.py +4 -0
- omnibase_infra/errors/error_binding_resolution.py +128 -0
- omnibase_infra/event_bus/configs/kafka_event_bus_config.yaml +0 -2
- omnibase_infra/event_bus/event_bus_inmemory.py +64 -10
- omnibase_infra/event_bus/event_bus_kafka.py +105 -47
- omnibase_infra/event_bus/mixin_kafka_broadcast.py +3 -7
- omnibase_infra/event_bus/mixin_kafka_dlq.py +12 -6
- omnibase_infra/event_bus/models/config/model_kafka_event_bus_config.py +0 -81
- omnibase_infra/event_bus/testing/__init__.py +26 -0
- omnibase_infra/event_bus/testing/adapter_protocol_event_publisher_inmemory.py +418 -0
- omnibase_infra/event_bus/testing/model_publisher_metrics.py +64 -0
- omnibase_infra/handlers/handler_consul.py +2 -0
- omnibase_infra/handlers/mixins/__init__.py +5 -0
- omnibase_infra/handlers/mixins/mixin_consul_service.py +274 -10
- omnibase_infra/handlers/mixins/mixin_consul_topic_index.py +585 -0
- omnibase_infra/handlers/models/model_filesystem_config.py +4 -4
- omnibase_infra/migrations/001_create_event_ledger.sql +166 -0
- omnibase_infra/migrations/001_drop_event_ledger.sql +18 -0
- omnibase_infra/mixins/mixin_node_introspection.py +189 -19
- omnibase_infra/models/__init__.py +8 -0
- omnibase_infra/models/bindings/__init__.py +59 -0
- omnibase_infra/models/bindings/constants.py +144 -0
- omnibase_infra/models/bindings/model_binding_resolution_result.py +103 -0
- omnibase_infra/models/bindings/model_operation_binding.py +44 -0
- omnibase_infra/models/bindings/model_operation_bindings_subcontract.py +152 -0
- omnibase_infra/models/bindings/model_parsed_binding.py +52 -0
- omnibase_infra/models/discovery/model_introspection_config.py +25 -17
- omnibase_infra/models/dispatch/__init__.py +8 -0
- omnibase_infra/models/dispatch/model_debug_trace_snapshot.py +114 -0
- omnibase_infra/models/dispatch/model_materialized_dispatch.py +141 -0
- omnibase_infra/models/handlers/model_handler_source_config.py +1 -1
- omnibase_infra/models/model_node_identity.py +126 -0
- omnibase_infra/models/projection/model_snapshot_topic_config.py +3 -2
- omnibase_infra/models/registration/__init__.py +9 -0
- omnibase_infra/models/registration/model_event_bus_topic_entry.py +59 -0
- omnibase_infra/models/registration/model_node_event_bus_config.py +99 -0
- omnibase_infra/models/registration/model_node_introspection_event.py +11 -0
- omnibase_infra/models/runtime/__init__.py +9 -0
- omnibase_infra/models/validation/model_coverage_metrics.py +2 -2
- omnibase_infra/nodes/__init__.py +9 -0
- omnibase_infra/nodes/contract_registry_reducer/__init__.py +29 -0
- omnibase_infra/nodes/contract_registry_reducer/contract.yaml +255 -0
- omnibase_infra/nodes/contract_registry_reducer/models/__init__.py +38 -0
- omnibase_infra/nodes/contract_registry_reducer/models/model_contract_registry_state.py +266 -0
- omnibase_infra/nodes/contract_registry_reducer/models/model_payload_cleanup_topic_references.py +55 -0
- omnibase_infra/nodes/contract_registry_reducer/models/model_payload_deactivate_contract.py +58 -0
- omnibase_infra/nodes/contract_registry_reducer/models/model_payload_mark_stale.py +49 -0
- omnibase_infra/nodes/contract_registry_reducer/models/model_payload_update_heartbeat.py +71 -0
- omnibase_infra/nodes/contract_registry_reducer/models/model_payload_update_topic.py +66 -0
- omnibase_infra/nodes/contract_registry_reducer/models/model_payload_upsert_contract.py +92 -0
- omnibase_infra/nodes/contract_registry_reducer/node.py +121 -0
- omnibase_infra/nodes/contract_registry_reducer/reducer.py +784 -0
- omnibase_infra/nodes/contract_registry_reducer/registry/__init__.py +9 -0
- omnibase_infra/nodes/contract_registry_reducer/registry/registry_infra_contract_registry_reducer.py +101 -0
- omnibase_infra/nodes/handlers/consul/contract.yaml +85 -0
- omnibase_infra/nodes/handlers/db/contract.yaml +72 -0
- omnibase_infra/nodes/handlers/graph/contract.yaml +127 -0
- omnibase_infra/nodes/handlers/http/contract.yaml +74 -0
- omnibase_infra/nodes/handlers/intent/contract.yaml +66 -0
- omnibase_infra/nodes/handlers/mcp/contract.yaml +69 -0
- omnibase_infra/nodes/handlers/vault/contract.yaml +91 -0
- omnibase_infra/nodes/node_ledger_projection_compute/__init__.py +50 -0
- omnibase_infra/nodes/node_ledger_projection_compute/contract.yaml +104 -0
- omnibase_infra/nodes/node_ledger_projection_compute/node.py +284 -0
- omnibase_infra/nodes/node_ledger_projection_compute/registry/__init__.py +29 -0
- omnibase_infra/nodes/node_ledger_projection_compute/registry/registry_infra_ledger_projection.py +118 -0
- omnibase_infra/nodes/node_ledger_write_effect/__init__.py +82 -0
- omnibase_infra/nodes/node_ledger_write_effect/contract.yaml +200 -0
- omnibase_infra/nodes/node_ledger_write_effect/handlers/__init__.py +22 -0
- omnibase_infra/nodes/node_ledger_write_effect/handlers/handler_ledger_append.py +372 -0
- omnibase_infra/nodes/node_ledger_write_effect/handlers/handler_ledger_query.py +597 -0
- omnibase_infra/nodes/node_ledger_write_effect/models/__init__.py +31 -0
- omnibase_infra/nodes/node_ledger_write_effect/models/model_ledger_append_result.py +54 -0
- omnibase_infra/nodes/node_ledger_write_effect/models/model_ledger_entry.py +92 -0
- omnibase_infra/nodes/node_ledger_write_effect/models/model_ledger_query.py +53 -0
- omnibase_infra/nodes/node_ledger_write_effect/models/model_ledger_query_result.py +41 -0
- omnibase_infra/nodes/node_ledger_write_effect/node.py +89 -0
- omnibase_infra/nodes/node_ledger_write_effect/protocols/__init__.py +13 -0
- omnibase_infra/nodes/node_ledger_write_effect/protocols/protocol_ledger_persistence.py +127 -0
- omnibase_infra/nodes/node_ledger_write_effect/registry/__init__.py +9 -0
- omnibase_infra/nodes/node_ledger_write_effect/registry/registry_infra_ledger_write.py +121 -0
- omnibase_infra/nodes/node_registration_orchestrator/registry/registry_infra_node_registration_orchestrator.py +7 -5
- omnibase_infra/nodes/reducers/models/__init__.py +7 -2
- omnibase_infra/nodes/reducers/models/model_payload_consul_register.py +11 -0
- omnibase_infra/nodes/reducers/models/model_payload_ledger_append.py +133 -0
- omnibase_infra/nodes/reducers/registration_reducer.py +1 -0
- omnibase_infra/protocols/__init__.py +3 -0
- omnibase_infra/protocols/protocol_dispatch_engine.py +152 -0
- omnibase_infra/runtime/__init__.py +60 -0
- omnibase_infra/runtime/binding_resolver.py +753 -0
- omnibase_infra/runtime/constants_security.py +70 -0
- omnibase_infra/runtime/contract_loaders/__init__.py +9 -0
- omnibase_infra/runtime/contract_loaders/operation_bindings_loader.py +789 -0
- omnibase_infra/runtime/emit_daemon/__init__.py +97 -0
- omnibase_infra/runtime/emit_daemon/cli.py +844 -0
- omnibase_infra/runtime/emit_daemon/client.py +811 -0
- omnibase_infra/runtime/emit_daemon/config.py +535 -0
- omnibase_infra/runtime/emit_daemon/daemon.py +812 -0
- omnibase_infra/runtime/emit_daemon/event_registry.py +477 -0
- omnibase_infra/runtime/emit_daemon/model_daemon_request.py +139 -0
- omnibase_infra/runtime/emit_daemon/model_daemon_response.py +191 -0
- omnibase_infra/runtime/emit_daemon/queue.py +618 -0
- omnibase_infra/runtime/event_bus_subcontract_wiring.py +466 -0
- omnibase_infra/runtime/handler_source_resolver.py +43 -2
- omnibase_infra/runtime/kafka_contract_source.py +984 -0
- omnibase_infra/runtime/models/__init__.py +13 -0
- omnibase_infra/runtime/models/model_contract_load_result.py +224 -0
- omnibase_infra/runtime/models/model_runtime_contract_config.py +268 -0
- omnibase_infra/runtime/models/model_runtime_scheduler_config.py +4 -3
- omnibase_infra/runtime/models/model_security_config.py +109 -0
- omnibase_infra/runtime/publisher_topic_scoped.py +294 -0
- omnibase_infra/runtime/runtime_contract_config_loader.py +406 -0
- omnibase_infra/runtime/service_kernel.py +76 -6
- omnibase_infra/runtime/service_message_dispatch_engine.py +558 -15
- omnibase_infra/runtime/service_runtime_host_process.py +770 -20
- omnibase_infra/runtime/transition_notification_publisher.py +3 -2
- omnibase_infra/runtime/util_wiring.py +206 -62
- omnibase_infra/services/mcp/service_mcp_tool_sync.py +27 -9
- omnibase_infra/services/session/config_consumer.py +25 -8
- omnibase_infra/services/session/config_store.py +2 -2
- omnibase_infra/services/session/consumer.py +1 -1
- omnibase_infra/topics/__init__.py +45 -0
- omnibase_infra/topics/platform_topic_suffixes.py +140 -0
- omnibase_infra/topics/util_topic_composition.py +95 -0
- omnibase_infra/types/typed_dict/__init__.py +9 -1
- omnibase_infra/types/typed_dict/typed_dict_envelope_build_params.py +115 -0
- omnibase_infra/utils/__init__.py +9 -0
- omnibase_infra/utils/util_consumer_group.py +232 -0
- omnibase_infra/validation/infra_validators.py +18 -1
- omnibase_infra/validation/validation_exemptions.yaml +192 -0
- {omnibase_infra-0.2.5.dist-info → omnibase_infra-0.2.7.dist-info}/METADATA +3 -3
- {omnibase_infra-0.2.5.dist-info → omnibase_infra-0.2.7.dist-info}/RECORD +139 -52
- {omnibase_infra-0.2.5.dist-info → omnibase_infra-0.2.7.dist-info}/entry_points.txt +1 -0
- {omnibase_infra-0.2.5.dist-info → omnibase_infra-0.2.7.dist-info}/WHEEL +0 -0
- {omnibase_infra-0.2.5.dist-info → omnibase_infra-0.2.7.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Deactivate contract intent payload model.
|
|
4
|
+
|
|
5
|
+
Related:
|
|
6
|
+
- OMN-1653: Contract Registry Reducer implementation
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
from typing import Literal
|
|
13
|
+
from uuid import UUID
|
|
14
|
+
|
|
15
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ModelPayloadDeactivateContract(BaseModel):
|
|
19
|
+
"""Payload for PostgreSQL deactivate contract intents.
|
|
20
|
+
|
|
21
|
+
Used when a contract-deregistered event is processed to mark the
|
|
22
|
+
contract as inactive (soft delete).
|
|
23
|
+
|
|
24
|
+
Note: contract_id is a derived natural key (node_name:major.minor.patch),
|
|
25
|
+
not a UUID. This is intentional per the contract registry design.
|
|
26
|
+
|
|
27
|
+
Attributes:
|
|
28
|
+
intent_type: Routing discriminator. Always "postgres.deactivate_contract".
|
|
29
|
+
correlation_id: Correlation ID for distributed tracing.
|
|
30
|
+
contract_id: Contract to deactivate.
|
|
31
|
+
node_name: Contract node name.
|
|
32
|
+
reason: Deregistration reason (shutdown, upgrade, manual).
|
|
33
|
+
deactivated_at: Deactivation timestamp.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
model_config = ConfigDict(frozen=True, extra="forbid", from_attributes=True)
|
|
37
|
+
|
|
38
|
+
intent_type: Literal["postgres.deactivate_contract"] = Field(
|
|
39
|
+
default="postgres.deactivate_contract",
|
|
40
|
+
description="Routing discriminator for intent dispatch.",
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
correlation_id: UUID = Field(
|
|
44
|
+
..., description="Correlation ID for distributed tracing."
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
# ONEX_EXCLUDE: pattern_validator - contract_id is a derived natural key (name:version), not UUID
|
|
48
|
+
contract_id: str = Field(..., description="Contract to deactivate.")
|
|
49
|
+
|
|
50
|
+
# ONEX_EXCLUDE: pattern_validator - node_name is the contract name, not an entity reference
|
|
51
|
+
node_name: str = Field(..., description="Contract node name.")
|
|
52
|
+
|
|
53
|
+
reason: str = Field(..., description="Deregistration reason.")
|
|
54
|
+
|
|
55
|
+
deactivated_at: datetime = Field(..., description="Deactivation timestamp.")
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
__all__ = ["ModelPayloadDeactivateContract"]
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Mark stale intent payload model.
|
|
4
|
+
|
|
5
|
+
Related:
|
|
6
|
+
- OMN-1653: Contract Registry Reducer implementation
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
from typing import Literal
|
|
13
|
+
from uuid import UUID
|
|
14
|
+
|
|
15
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ModelPayloadMarkStale(BaseModel):
|
|
19
|
+
"""Payload for PostgreSQL mark stale intents.
|
|
20
|
+
|
|
21
|
+
Used when a runtime-tick event is processed to batch mark
|
|
22
|
+
contracts as stale if they haven't been seen within the threshold.
|
|
23
|
+
|
|
24
|
+
Attributes:
|
|
25
|
+
intent_type: Routing discriminator. Always "postgres.mark_stale".
|
|
26
|
+
correlation_id: Correlation ID for distributed tracing.
|
|
27
|
+
stale_cutoff: Contracts with last_seen_at before this are stale.
|
|
28
|
+
checked_at: When staleness check was performed.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
model_config = ConfigDict(frozen=True, extra="forbid", from_attributes=True)
|
|
32
|
+
|
|
33
|
+
intent_type: Literal["postgres.mark_stale"] = Field(
|
|
34
|
+
default="postgres.mark_stale",
|
|
35
|
+
description="Routing discriminator for intent dispatch.",
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
correlation_id: UUID = Field(
|
|
39
|
+
..., description="Correlation ID for distributed tracing."
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
stale_cutoff: datetime = Field(
|
|
43
|
+
..., description="Contracts older than this are marked stale."
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
checked_at: datetime = Field(..., description="When check was performed.")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
__all__ = ["ModelPayloadMarkStale"]
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Update heartbeat intent payload model.
|
|
4
|
+
|
|
5
|
+
Related:
|
|
6
|
+
- OMN-1653: Contract Registry Reducer implementation
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
from typing import Literal
|
|
13
|
+
from uuid import UUID
|
|
14
|
+
|
|
15
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ModelPayloadUpdateHeartbeat(BaseModel):
|
|
19
|
+
"""Payload for PostgreSQL update heartbeat intents.
|
|
20
|
+
|
|
21
|
+
Used when a node-heartbeat event is processed to update the
|
|
22
|
+
last_seen_at timestamp for a contract.
|
|
23
|
+
|
|
24
|
+
Note: contract_id is a derived natural key (node_name:major.minor.patch),
|
|
25
|
+
not a UUID. This is intentional per the contract registry design.
|
|
26
|
+
|
|
27
|
+
Attributes:
|
|
28
|
+
intent_type: Routing discriminator. Always "postgres.update_heartbeat".
|
|
29
|
+
correlation_id: Correlation ID for distributed tracing.
|
|
30
|
+
contract_id: Contract to update.
|
|
31
|
+
node_name: Contract node name.
|
|
32
|
+
source_node_id: String representation of heartbeating node's UUID (optional).
|
|
33
|
+
last_seen_at: New heartbeat timestamp.
|
|
34
|
+
uptime_seconds: Node uptime in seconds (optional).
|
|
35
|
+
sequence_number: Heartbeat sequence number (optional).
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
model_config = ConfigDict(frozen=True, extra="forbid", from_attributes=True)
|
|
39
|
+
|
|
40
|
+
intent_type: Literal["postgres.update_heartbeat"] = Field(
|
|
41
|
+
default="postgres.update_heartbeat",
|
|
42
|
+
description="Routing discriminator for intent dispatch.",
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
correlation_id: UUID = Field(
|
|
46
|
+
..., description="Correlation ID for distributed tracing."
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# ONEX_EXCLUDE: pattern_validator - contract_id is a derived natural key (name:version), not UUID
|
|
50
|
+
contract_id: str = Field(..., description="Contract to update.")
|
|
51
|
+
|
|
52
|
+
# ONEX_EXCLUDE: pattern_validator - node_name is the contract name, not an entity reference
|
|
53
|
+
node_name: str = Field(..., description="Contract node name.")
|
|
54
|
+
|
|
55
|
+
source_node_id: str | None = Field(
|
|
56
|
+
default=None,
|
|
57
|
+
description="Source node ID as string (UUID string representation, optional).",
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
last_seen_at: datetime = Field(..., description="Heartbeat timestamp.")
|
|
61
|
+
|
|
62
|
+
uptime_seconds: float | None = Field(
|
|
63
|
+
default=None, ge=0, description="Node uptime in seconds."
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
sequence_number: int | None = Field(
|
|
67
|
+
default=None, ge=0, description="Heartbeat sequence number."
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
__all__ = ["ModelPayloadUpdateHeartbeat"]
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Update topic intent payload model.
|
|
4
|
+
|
|
5
|
+
Related:
|
|
6
|
+
- OMN-1653: Contract Registry Reducer implementation
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
from typing import Literal
|
|
13
|
+
from uuid import UUID
|
|
14
|
+
|
|
15
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ModelPayloadUpdateTopic(BaseModel):
|
|
19
|
+
"""Payload for PostgreSQL update topic intents.
|
|
20
|
+
|
|
21
|
+
Used when a contract-registered event is processed to update
|
|
22
|
+
the topic routing table with producer/consumer information.
|
|
23
|
+
|
|
24
|
+
Note: contract_id is a derived natural key (node_name:major.minor.patch),
|
|
25
|
+
not a UUID. This is intentional per the contract registry design.
|
|
26
|
+
|
|
27
|
+
Attributes:
|
|
28
|
+
intent_type: Routing discriminator. Always "postgres.update_topic".
|
|
29
|
+
correlation_id: Correlation ID for distributed tracing.
|
|
30
|
+
topic_suffix: Topic suffix (e.g., onex.evt.platform.contract-registered.v1).
|
|
31
|
+
direction: Whether this contract publishes or subscribes to the topic.
|
|
32
|
+
contract_id: Contract that uses this topic.
|
|
33
|
+
node_name: Contract node name.
|
|
34
|
+
event_type: Event type name (optional).
|
|
35
|
+
last_seen_at: When topic usage was last seen.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
model_config = ConfigDict(frozen=True, extra="forbid", from_attributes=True)
|
|
39
|
+
|
|
40
|
+
intent_type: Literal["postgres.update_topic"] = Field(
|
|
41
|
+
default="postgres.update_topic",
|
|
42
|
+
description="Routing discriminator for intent dispatch.",
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
correlation_id: UUID = Field(
|
|
46
|
+
..., description="Correlation ID for distributed tracing."
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
topic_suffix: str = Field(..., description="Topic suffix.")
|
|
50
|
+
|
|
51
|
+
direction: Literal["publish", "subscribe"] = Field(
|
|
52
|
+
..., description="Topic direction."
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
# ONEX_EXCLUDE: pattern_validator - contract_id is a derived natural key (name:version), not UUID
|
|
56
|
+
contract_id: str = Field(..., description="Contract using this topic.")
|
|
57
|
+
|
|
58
|
+
# ONEX_EXCLUDE: pattern_validator - node_name is the contract name, not an entity reference
|
|
59
|
+
node_name: str = Field(..., description="Contract node name.")
|
|
60
|
+
|
|
61
|
+
event_type: str | None = Field(default=None, description="Event type name.")
|
|
62
|
+
|
|
63
|
+
last_seen_at: datetime = Field(..., description="Last seen timestamp.")
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
__all__ = ["ModelPayloadUpdateTopic"]
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Upsert contract intent payload model.
|
|
4
|
+
|
|
5
|
+
Related:
|
|
6
|
+
- OMN-1653: Contract Registry Reducer implementation
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
from typing import Literal
|
|
13
|
+
from uuid import UUID
|
|
14
|
+
|
|
15
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
16
|
+
|
|
17
|
+
from omnibase_core.types import JsonType
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ModelPayloadUpsertContract(BaseModel):
|
|
21
|
+
"""Payload for PostgreSQL upsert contract intents.
|
|
22
|
+
|
|
23
|
+
Used when a contract-registered event is processed to insert or update
|
|
24
|
+
the contract record in the contracts table.
|
|
25
|
+
|
|
26
|
+
Note: contract_id is a derived natural key (node_name:major.minor.patch),
|
|
27
|
+
not a UUID. This is intentional per the contract registry design.
|
|
28
|
+
|
|
29
|
+
Serialization Note:
|
|
30
|
+
The contract_yaml field accepts both dict (parsed) and str (raw YAML).
|
|
31
|
+
The Effect layer (PostgresAdapter) is responsible for serializing dict
|
|
32
|
+
to YAML string before INSERT, as the PostgreSQL column is TEXT type.
|
|
33
|
+
|
|
34
|
+
Attributes:
|
|
35
|
+
intent_type: Routing discriminator. Always "postgres.upsert_contract".
|
|
36
|
+
correlation_id: Correlation ID for distributed tracing.
|
|
37
|
+
contract_id: Derived contract identity (node_name:major.minor.patch).
|
|
38
|
+
node_name: Contract node name from event.
|
|
39
|
+
version_major: Semantic version major component.
|
|
40
|
+
version_minor: Semantic version minor component.
|
|
41
|
+
version_patch: Semantic version patch component.
|
|
42
|
+
contract_hash: Hash of the contract YAML for change detection.
|
|
43
|
+
contract_yaml: Full contract YAML for storage and replay. Accepts dict
|
|
44
|
+
(parsed) or str (raw). Effect layer serializes dict to YAML string
|
|
45
|
+
before INSERT.
|
|
46
|
+
source_node_id: UUID of the node that emitted the event (optional).
|
|
47
|
+
is_active: Whether the contract is currently active.
|
|
48
|
+
registered_at: Timestamp when contract was registered.
|
|
49
|
+
last_seen_at: Last heartbeat/registration timestamp.
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
model_config = ConfigDict(frozen=True, extra="forbid", from_attributes=True)
|
|
53
|
+
|
|
54
|
+
intent_type: Literal["postgres.upsert_contract"] = Field(
|
|
55
|
+
default="postgres.upsert_contract",
|
|
56
|
+
description="Routing discriminator for intent dispatch.",
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
correlation_id: UUID = Field(
|
|
60
|
+
..., description="Correlation ID for distributed tracing."
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
# ONEX_EXCLUDE: pattern_validator - contract_id is a derived natural key (name:version), not UUID
|
|
64
|
+
contract_id: str = Field(
|
|
65
|
+
..., description="Contract identity: node_name:major.minor.patch"
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
# ONEX_EXCLUDE: pattern_validator - node_name is the contract name, not an entity reference
|
|
69
|
+
node_name: str = Field(..., description="Contract node name.")
|
|
70
|
+
|
|
71
|
+
version_major: int = Field(..., ge=0, description="Semantic version major.")
|
|
72
|
+
version_minor: int = Field(..., ge=0, description="Semantic version minor.")
|
|
73
|
+
version_patch: int = Field(..., ge=0, description="Semantic version patch.")
|
|
74
|
+
|
|
75
|
+
contract_hash: str = Field(..., description="Hash of contract YAML.")
|
|
76
|
+
|
|
77
|
+
contract_yaml: JsonType = Field(
|
|
78
|
+
..., description="Full contract YAML (dict or raw string)."
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
source_node_id: str | None = Field(
|
|
82
|
+
default=None, description="Source node UUID (optional)."
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
is_active: bool = Field(default=True, description="Whether contract is active.")
|
|
86
|
+
|
|
87
|
+
registered_at: datetime = Field(..., description="Registration timestamp.")
|
|
88
|
+
|
|
89
|
+
last_seen_at: datetime = Field(..., description="Last heartbeat timestamp.")
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
__all__ = ["ModelPayloadUpsertContract"]
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Contract Registry Reducer - FSM-driven declarative reducer.
|
|
4
|
+
|
|
5
|
+
This reducer follows the ONEX declarative pattern:
|
|
6
|
+
- DECLARATIVE reducer driven by contract.yaml
|
|
7
|
+
- Zero custom routing logic - all behavior from FSM state_machine
|
|
8
|
+
- Lightweight shell that delegates to NodeReducer base class
|
|
9
|
+
- Used for ONEX-compliant runtime execution via RuntimeHostProcess
|
|
10
|
+
- Pattern: "Contract-driven, FSM state transitions"
|
|
11
|
+
|
|
12
|
+
Extends NodeReducer from omnibase_core for FSM-driven state management.
|
|
13
|
+
All state transition logic is 100% driven by contract.yaml, not Python code.
|
|
14
|
+
|
|
15
|
+
Purpose:
|
|
16
|
+
This reducer projects contract registration events to PostgreSQL:
|
|
17
|
+
1. Receives contract registration events from Kafka
|
|
18
|
+
2. Validates and deduplicates events using Kafka offset tracking
|
|
19
|
+
3. Emits PostgreSQL upsert intents for the contract_registry table
|
|
20
|
+
4. Processes heartbeat events to update last_seen timestamps
|
|
21
|
+
5. Handles deregistration events to mark contracts as inactive
|
|
22
|
+
|
|
23
|
+
FSM Pattern:
|
|
24
|
+
1. Receive contract event (trigger: contract_registered, heartbeat, deregistered)
|
|
25
|
+
2. Check idempotency via Kafka offset (skip duplicates)
|
|
26
|
+
3. Emit PostgreSQL intent for persistence
|
|
27
|
+
4. Update state with processed event tracking
|
|
28
|
+
|
|
29
|
+
Design Decisions:
|
|
30
|
+
- 100% Contract-Driven: All FSM logic in YAML, not Python
|
|
31
|
+
- Zero Custom Methods: Base class handles everything
|
|
32
|
+
- Declarative Execution: State transitions defined in state_machine
|
|
33
|
+
- Pure Function Pattern: (state, event) -> (new_state, intents)
|
|
34
|
+
|
|
35
|
+
Related Modules:
|
|
36
|
+
- contract.yaml: FSM state machine and intent emission configuration
|
|
37
|
+
- models/: State model for idempotency and statistics tracking
|
|
38
|
+
- OMN-1653: Contract registry reducer implementation
|
|
39
|
+
|
|
40
|
+
Testing Notes:
|
|
41
|
+
- Unit tests: tests/unit/nodes/contract_registry_reducer/
|
|
42
|
+
- Integration tests: Required before production
|
|
43
|
+
* Intent emission through RuntimeHostProcess
|
|
44
|
+
* End-to-end contract workflow with PostgreSQL mocks
|
|
45
|
+
* Kafka offset-based idempotency verification
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
from __future__ import annotations
|
|
49
|
+
|
|
50
|
+
from typing import TYPE_CHECKING
|
|
51
|
+
|
|
52
|
+
from omnibase_core.nodes.node_reducer import NodeReducer
|
|
53
|
+
|
|
54
|
+
if TYPE_CHECKING:
|
|
55
|
+
# Import needed for string annotation in class definition
|
|
56
|
+
from omnibase_infra.nodes.contract_registry_reducer.models.model_contract_registry_state import (
|
|
57
|
+
ModelContractRegistryState,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class NodeContractRegistryReducer(
|
|
62
|
+
NodeReducer["ModelContractRegistryState", "ModelContractRegistryState"]
|
|
63
|
+
):
|
|
64
|
+
"""Contract registry reducer - FSM state transitions driven by contract.yaml.
|
|
65
|
+
|
|
66
|
+
This is a purely declarative reducer. All behavior is defined in contract.yaml.
|
|
67
|
+
No custom Python logic is required - the base NodeReducer class handles all
|
|
68
|
+
FSM-driven state transitions via the contract configuration.
|
|
69
|
+
|
|
70
|
+
This reducer processes contract registration workflows by:
|
|
71
|
+
1. Receiving contract events (registration, heartbeat, deregistration)
|
|
72
|
+
2. Executing FSM transitions defined in contract.yaml
|
|
73
|
+
3. Emitting PostgreSQL upsert intents for the contract_registry table
|
|
74
|
+
4. Tracking processed events for idempotency via Kafka offsets
|
|
75
|
+
|
|
76
|
+
All state transition logic, intent emission, and validation are driven
|
|
77
|
+
entirely by the contract.yaml FSM configuration.
|
|
78
|
+
|
|
79
|
+
Example YAML Contract (state_machine section):
|
|
80
|
+
```yaml
|
|
81
|
+
state_machine:
|
|
82
|
+
state_machine_name: contract_registry_fsm
|
|
83
|
+
initial_state: idle
|
|
84
|
+
states:
|
|
85
|
+
- state_name: idle
|
|
86
|
+
description: "Waiting for contract events"
|
|
87
|
+
- state_name: processing
|
|
88
|
+
description: "Processing contract event"
|
|
89
|
+
entry_actions:
|
|
90
|
+
- emit_postgres_upsert_intent
|
|
91
|
+
transitions:
|
|
92
|
+
- from_state: idle
|
|
93
|
+
to_state: processing
|
|
94
|
+
trigger: contract_received
|
|
95
|
+
conditions:
|
|
96
|
+
- expression: "node_id is_present"
|
|
97
|
+
required: true
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Usage:
|
|
101
|
+
```python
|
|
102
|
+
from omnibase_core.models.container import ModelONEXContainer
|
|
103
|
+
from omnibase_core.models.reducer import ModelReducerInput
|
|
104
|
+
from omnibase_core.enums import EnumReductionType
|
|
105
|
+
|
|
106
|
+
# Create and initialize
|
|
107
|
+
container = ModelONEXContainer()
|
|
108
|
+
reducer = NodeContractRegistryReducer(container)
|
|
109
|
+
|
|
110
|
+
# Process input via FSM
|
|
111
|
+
input_data = ModelReducerInput(
|
|
112
|
+
data=contract_event,
|
|
113
|
+
reduction_type=EnumReductionType.MERGE,
|
|
114
|
+
metadata=ModelReducerMetadata(trigger="contract_registered"),
|
|
115
|
+
)
|
|
116
|
+
result = await reducer.process(input_data)
|
|
117
|
+
```
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
__all__ = ["NodeContractRegistryReducer"]
|