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,114 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Debug trace snapshot model.
|
|
4
|
+
|
|
5
|
+
This module defines the serializable trace metadata snapshot that replaces
|
|
6
|
+
live envelope references in the dispatch contract.
|
|
7
|
+
|
|
8
|
+
Design Rationale:
|
|
9
|
+
The dispatch boundary is a **serialization boundary**. Anything crossing
|
|
10
|
+
this boundary must be:
|
|
11
|
+
- Loggable (observability)
|
|
12
|
+
- Replayable (debugging)
|
|
13
|
+
- Transportable (Kafka, distributed dispatch)
|
|
14
|
+
- Inspectable offline (audit pipelines)
|
|
15
|
+
|
|
16
|
+
Live Python object references violate all of these requirements.
|
|
17
|
+
This snapshot model provides the trace metadata handlers need for
|
|
18
|
+
debugging without creating dependencies on internal envelope types.
|
|
19
|
+
|
|
20
|
+
Warning:
|
|
21
|
+
This model exists solely for debugging and observability.
|
|
22
|
+
It must **never** be used for business logic.
|
|
23
|
+
|
|
24
|
+
The data in this snapshot is:
|
|
25
|
+
- Non-authoritative (may not reflect the complete envelope state)
|
|
26
|
+
- Metadata-only (does not include payload content)
|
|
27
|
+
- Immutable (cannot be used to modify the original envelope)
|
|
28
|
+
|
|
29
|
+
.. versionadded:: 0.2.8
|
|
30
|
+
Added as part of OMN-1518 - Strict JSON-safe dispatch contract.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
from __future__ import annotations
|
|
34
|
+
|
|
35
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class ModelDebugTraceSnapshot(BaseModel):
|
|
39
|
+
"""Serializable, non-authoritative trace snapshot.
|
|
40
|
+
|
|
41
|
+
This model captures trace metadata from the original envelope for
|
|
42
|
+
debugging and observability purposes. It replaces live envelope
|
|
43
|
+
references to maintain transport-safe dispatch contracts.
|
|
44
|
+
|
|
45
|
+
All fields are optional because:
|
|
46
|
+
1. Not all envelopes have all metadata fields
|
|
47
|
+
2. Extraction may fail gracefully without blocking dispatch
|
|
48
|
+
3. Debug data should never cause handler failures
|
|
49
|
+
|
|
50
|
+
Attributes:
|
|
51
|
+
event_type: The event type identifier (e.g., "UserCreated").
|
|
52
|
+
correlation_id: Correlation ID for distributed tracing (serialized UUID).
|
|
53
|
+
trace_id: Trace ID for span correlation (serialized UUID).
|
|
54
|
+
causation_id: Causation ID linking to parent event (serialized UUID).
|
|
55
|
+
topic: The Kafka/event topic this message was received on.
|
|
56
|
+
timestamp: When the event was created (ISO 8601 format).
|
|
57
|
+
partition_key: The partition key for Kafka routing.
|
|
58
|
+
|
|
59
|
+
Example:
|
|
60
|
+
>>> snapshot = ModelDebugTraceSnapshot(
|
|
61
|
+
... correlation_id="550e8400-e29b-41d4-a716-446655440000",
|
|
62
|
+
... trace_id="660e8400-e29b-41d4-a716-446655440001",
|
|
63
|
+
... topic="dev.user.events.v1",
|
|
64
|
+
... timestamp="2025-01-27T12:00:00Z",
|
|
65
|
+
... )
|
|
66
|
+
>>> snapshot.model_dump()
|
|
67
|
+
{'event_type': None, 'correlation_id': '550e8400-...', ...}
|
|
68
|
+
|
|
69
|
+
Warning:
|
|
70
|
+
This snapshot is **non-authoritative**. It exists solely for
|
|
71
|
+
debugging and observability. Do not use it for business logic.
|
|
72
|
+
|
|
73
|
+
.. versionadded:: 0.2.8
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
model_config = ConfigDict(
|
|
77
|
+
frozen=True,
|
|
78
|
+
extra="forbid",
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
event_type: str | None = Field(
|
|
82
|
+
default=None,
|
|
83
|
+
description="Event type identifier (e.g., 'UserCreated').",
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
correlation_id: str | None = Field(
|
|
87
|
+
default=None,
|
|
88
|
+
description="Correlation ID for distributed tracing (serialized UUID).",
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
trace_id: str | None = Field(
|
|
92
|
+
default=None,
|
|
93
|
+
description="Trace ID for span correlation (serialized UUID).",
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
causation_id: str | None = Field(
|
|
97
|
+
default=None,
|
|
98
|
+
description="Causation ID linking to parent event (serialized UUID).",
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
topic: str | None = Field(
|
|
102
|
+
default=None,
|
|
103
|
+
description="Event topic this message was received on.",
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
timestamp: str | None = Field(
|
|
107
|
+
default=None,
|
|
108
|
+
description="Event creation timestamp (ISO 8601 format).",
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
partition_key: str | None = Field(
|
|
112
|
+
default=None,
|
|
113
|
+
description="Partition key for Kafka routing.",
|
|
114
|
+
)
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Materialized dispatch message model.
|
|
4
|
+
|
|
5
|
+
This module defines the canonical runtime contract for dispatched messages.
|
|
6
|
+
All handlers receive a materialized dict that conforms to this shape.
|
|
7
|
+
|
|
8
|
+
Design Rationale:
|
|
9
|
+
The dispatch boundary is a **serialization boundary**. This model enforces
|
|
10
|
+
that all data crossing the dispatch layer is transport-safe:
|
|
11
|
+
- JSON-serializable (can be logged, replayed, transported to Kafka)
|
|
12
|
+
- Deterministic (same input produces same serialized output)
|
|
13
|
+
- Inspectable (can be examined offline without Python runtime)
|
|
14
|
+
|
|
15
|
+
Handlers that need rich Pydantic models should hydrate them locally:
|
|
16
|
+
``ModelFoo.model_validate(dispatch["payload"])``
|
|
17
|
+
|
|
18
|
+
This separation keeps the runtime decoupled from handler internals and
|
|
19
|
+
enables distributed dispatch, event replay, and observability tooling.
|
|
20
|
+
|
|
21
|
+
.. versionadded:: 0.2.6
|
|
22
|
+
Added as part of OMN-1518 - Declarative operation bindings.
|
|
23
|
+
|
|
24
|
+
.. versionchanged:: 0.2.8
|
|
25
|
+
Changed to strict JSON-safe contract:
|
|
26
|
+
- Removed arbitrary_types_allowed
|
|
27
|
+
- Changed payload/bindings to JsonType
|
|
28
|
+
- Renamed __debug_original_envelope to __debug_trace (serialized snapshot)
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
from __future__ import annotations
|
|
32
|
+
|
|
33
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
34
|
+
|
|
35
|
+
from omnibase_core.types import JsonType
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class ModelMaterializedDispatch(BaseModel):
|
|
39
|
+
"""Canonical dispatch message shape (strictly JSON-safe).
|
|
40
|
+
|
|
41
|
+
This is the runtime contract for all handlers. After materialization,
|
|
42
|
+
every handler receives a dict that conforms to this structure:
|
|
43
|
+
|
|
44
|
+
- ``payload``: The event payload as a JSON-safe dict (required)
|
|
45
|
+
- ``__bindings``: Resolved binding parameters (always present, may be empty)
|
|
46
|
+
- ``__debug_trace``: Serialized trace metadata snapshot (debug only)
|
|
47
|
+
|
|
48
|
+
The double-underscore prefix on ``__bindings`` and ``__debug_trace``
|
|
49
|
+
signals that these are infrastructure-level fields, not business data.
|
|
50
|
+
|
|
51
|
+
Transport Safety:
|
|
52
|
+
All fields are JSON-serializable. This enables:
|
|
53
|
+
- Event replay from logs or Kafka
|
|
54
|
+
- Distributed dispatch across processes
|
|
55
|
+
- Observability tooling (logging, tracing, dashboards)
|
|
56
|
+
- Offline inspection and debugging
|
|
57
|
+
|
|
58
|
+
Handler Hydration:
|
|
59
|
+
Handlers that need typed Pydantic models should hydrate locally:
|
|
60
|
+
|
|
61
|
+
>>> payload = dispatch["payload"]
|
|
62
|
+
>>> event = UserCreatedEvent.model_validate(payload)
|
|
63
|
+
|
|
64
|
+
This keeps the dispatch boundary clean and transport-safe.
|
|
65
|
+
|
|
66
|
+
Warning:
|
|
67
|
+
``__debug_trace`` is provided ONLY for debugging and observability.
|
|
68
|
+
It is a serialized snapshot of trace metadata, NOT the live envelope.
|
|
69
|
+
|
|
70
|
+
**DO NOT**:
|
|
71
|
+
- Use ``__debug_trace`` for business logic
|
|
72
|
+
- Assume ``__debug_trace`` reflects complete envelope state
|
|
73
|
+
- Depend on specific fields being present
|
|
74
|
+
|
|
75
|
+
Example:
|
|
76
|
+
>>> materialized = {
|
|
77
|
+
... "payload": {"user_id": "123", "action": "login"},
|
|
78
|
+
... "__bindings": {"user_id": "123", "timestamp": "2025-01-27T12:00:00Z"},
|
|
79
|
+
... "__debug_trace": {
|
|
80
|
+
... "correlation_id": "550e8400-e29b-41d4-a716-446655440000",
|
|
81
|
+
... "topic": "dev.user.events.v1",
|
|
82
|
+
... },
|
|
83
|
+
... }
|
|
84
|
+
>>> validated = ModelMaterializedDispatch.model_validate(materialized)
|
|
85
|
+
>>> validated.payload
|
|
86
|
+
{'user_id': '123', 'action': 'login'}
|
|
87
|
+
|
|
88
|
+
Attributes:
|
|
89
|
+
payload: The event payload as a JSON-safe dict. Handlers that need
|
|
90
|
+
typed models should call ``model_validate()`` on this dict.
|
|
91
|
+
Primitives are wrapped under ``{"_raw": value}`` to maintain
|
|
92
|
+
dict structure (this is a last-resort escape hatch).
|
|
93
|
+
bindings: Resolved binding parameters from contract.yaml operation_bindings.
|
|
94
|
+
Always present (empty dict if no bindings configured). All values
|
|
95
|
+
are JSON-safe (UUIDs and datetimes are serialized to strings).
|
|
96
|
+
debug_trace: Serialized trace metadata snapshot for debugging.
|
|
97
|
+
Contains correlation_id, trace_id, topic, etc. as strings.
|
|
98
|
+
This is NOT authoritative data and should NOT be used for
|
|
99
|
+
business logic. Excluded from repr() to prevent log bloat.
|
|
100
|
+
|
|
101
|
+
.. versionadded:: 0.2.6
|
|
102
|
+
|
|
103
|
+
.. versionchanged:: 0.2.8
|
|
104
|
+
Changed to strict JSON-safe contract. See module docstring.
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
model_config = ConfigDict(
|
|
108
|
+
frozen=True,
|
|
109
|
+
populate_by_name=True,
|
|
110
|
+
extra="forbid",
|
|
111
|
+
# NOTE: arbitrary_types_allowed is intentionally NOT set (defaults to False).
|
|
112
|
+
# This enforces that all data crossing the dispatch boundary is JSON-safe.
|
|
113
|
+
# See module docstring for design rationale.
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
payload: JsonType = Field(
|
|
117
|
+
...,
|
|
118
|
+
description=(
|
|
119
|
+
"Event payload as JSON-safe dict. "
|
|
120
|
+
"Handlers should hydrate typed models via model_validate()."
|
|
121
|
+
),
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
bindings: dict[str, JsonType] = Field(
|
|
125
|
+
default_factory=dict,
|
|
126
|
+
alias="__bindings",
|
|
127
|
+
description=(
|
|
128
|
+
"Resolved binding parameters. Always present, may be empty dict. "
|
|
129
|
+
"Values are JSON-safe (UUIDs/datetimes serialized to strings)."
|
|
130
|
+
),
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
debug_trace: dict[str, str | None] | None = Field(
|
|
134
|
+
default=None,
|
|
135
|
+
alias="__debug_trace",
|
|
136
|
+
description=(
|
|
137
|
+
"Serialized trace metadata snapshot for debugging only. "
|
|
138
|
+
"NOT authoritative. Do NOT use for business logic."
|
|
139
|
+
),
|
|
140
|
+
repr=False, # Prevent log bloat when stringifying model
|
|
141
|
+
)
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Node Identity Model for ONEX Infrastructure.
|
|
4
|
+
|
|
5
|
+
This module provides a typed Pydantic model for uniquely identifying ONEX nodes
|
|
6
|
+
within the infrastructure. The identity encapsulates the environment, service,
|
|
7
|
+
node name, and version - the four dimensions required to uniquely identify
|
|
8
|
+
a node instance.
|
|
9
|
+
|
|
10
|
+
The model is immutable (frozen) to ensure identity stability throughout a node's
|
|
11
|
+
lifecycle. Once created, a node identity cannot be modified.
|
|
12
|
+
|
|
13
|
+
.. versionadded:: 0.2.6
|
|
14
|
+
Created as part of OMN-1602 typed node identity for introspection.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from pydantic import BaseModel, ConfigDict, Field, ValidationInfo, field_validator
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class ModelNodeIdentity(BaseModel):
|
|
23
|
+
"""Typed identity for ONEX infrastructure nodes.
|
|
24
|
+
|
|
25
|
+
This model uniquely identifies a node within the ONEX infrastructure using
|
|
26
|
+
four dimensions: environment, service, node name, and version. The same
|
|
27
|
+
node identity can be used with different purposes (e.g., introspection,
|
|
28
|
+
registration, heartbeat) - purpose is passed separately to operations.
|
|
29
|
+
|
|
30
|
+
All fields are required and must be non-empty strings without whitespace-only
|
|
31
|
+
values. The model is frozen to ensure identity immutability.
|
|
32
|
+
|
|
33
|
+
Attributes:
|
|
34
|
+
env: Environment identifier (e.g., "dev", "staging", "prod").
|
|
35
|
+
Determines which infrastructure deployment the node belongs to.
|
|
36
|
+
service: Service name from the node's contract (e.g., "omniintelligence",
|
|
37
|
+
"omnibridge"). Groups related nodes under a common service boundary.
|
|
38
|
+
node_name: Node name from the contract (e.g., "claude_hook_event_effect",
|
|
39
|
+
"registration_orchestrator"). Uniquely identifies the node within
|
|
40
|
+
its service.
|
|
41
|
+
version: Version string for the node (e.g., "v1", "v2.0.0").
|
|
42
|
+
Enables version-aware routing and registration. While any non-empty
|
|
43
|
+
string is accepted, semver-style prefixed with 'v' is recommended
|
|
44
|
+
for consistency (e.g., 'v1', 'v1.0.0', 'v2.1.3').
|
|
45
|
+
|
|
46
|
+
Example:
|
|
47
|
+
>>> identity = ModelNodeIdentity(
|
|
48
|
+
... env="dev",
|
|
49
|
+
... service="omniintelligence",
|
|
50
|
+
... node_name="claude_hook_event_effect",
|
|
51
|
+
... version="v1",
|
|
52
|
+
... )
|
|
53
|
+
>>> identity.env
|
|
54
|
+
'dev'
|
|
55
|
+
>>> identity.service
|
|
56
|
+
'omniintelligence'
|
|
57
|
+
|
|
58
|
+
The model is immutable - attempting to modify raises an error:
|
|
59
|
+
|
|
60
|
+
>>> identity.env = "prod" # doctest: +SKIP
|
|
61
|
+
Traceback (most recent call last):
|
|
62
|
+
...
|
|
63
|
+
pydantic_core._pydantic_core.ValidationError: ...
|
|
64
|
+
|
|
65
|
+
Empty or whitespace-only values are rejected:
|
|
66
|
+
|
|
67
|
+
>>> ModelNodeIdentity(env="", service="svc", node_name="node", version="v1")
|
|
68
|
+
Traceback (most recent call last):
|
|
69
|
+
...
|
|
70
|
+
pydantic_core._pydantic_core.ValidationError: ...
|
|
71
|
+
|
|
72
|
+
Note:
|
|
73
|
+
The `purpose` field is intentionally NOT included in this model.
|
|
74
|
+
Purpose (e.g., "introspection", "registration") is passed separately
|
|
75
|
+
to operations because the same node identity can be used for multiple
|
|
76
|
+
purposes.
|
|
77
|
+
|
|
78
|
+
.. versionadded:: 0.2.6
|
|
79
|
+
Created as part of OMN-1602.
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
model_config = ConfigDict(
|
|
83
|
+
frozen=True,
|
|
84
|
+
extra="forbid",
|
|
85
|
+
strict=True,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
env: str = Field(
|
|
89
|
+
description="Environment identifier (e.g., 'dev', 'staging', 'prod')",
|
|
90
|
+
)
|
|
91
|
+
service: str = Field(
|
|
92
|
+
description="Service name from the node's contract (e.g., 'omniintelligence')",
|
|
93
|
+
)
|
|
94
|
+
node_name: str = Field( # pattern-ok: canonical identifier, not a foreign key reference
|
|
95
|
+
description="Node name from the contract (e.g., 'claude_hook_event_effect')",
|
|
96
|
+
)
|
|
97
|
+
version: str = Field(
|
|
98
|
+
description="Version string for the node (e.g., 'v1', 'v2.0.0')",
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
@field_validator("env", "service", "node_name", "version", mode="after")
|
|
102
|
+
@classmethod
|
|
103
|
+
def _validate_non_empty(cls, v: str, info: ValidationInfo) -> str:
|
|
104
|
+
"""Validate that string fields are non-empty and not whitespace-only.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
v: The string value to validate.
|
|
108
|
+
info: Pydantic validation context containing field name.
|
|
109
|
+
|
|
110
|
+
Returns:
|
|
111
|
+
The validated string value.
|
|
112
|
+
|
|
113
|
+
Raises:
|
|
114
|
+
ValueError: If the value is empty or contains only whitespace.
|
|
115
|
+
"""
|
|
116
|
+
field_name = info.field_name
|
|
117
|
+
if not v:
|
|
118
|
+
msg = f"'{field_name}' must not be empty"
|
|
119
|
+
raise ValueError(msg)
|
|
120
|
+
if not v.strip():
|
|
121
|
+
msg = f"'{field_name}' must not contain only whitespace"
|
|
122
|
+
raise ValueError(msg)
|
|
123
|
+
return v
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
__all__: list[str] = ["ModelNodeIdentity"]
|
|
@@ -58,6 +58,7 @@ import yaml
|
|
|
58
58
|
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
|
|
59
59
|
|
|
60
60
|
from omnibase_infra.enums import EnumInfraTransportType
|
|
61
|
+
from omnibase_infra.topics import SUFFIX_REGISTRATION_SNAPSHOTS
|
|
61
62
|
|
|
62
63
|
if TYPE_CHECKING:
|
|
63
64
|
from omnibase_infra.errors.error_infra import ProtocolConfigurationError
|
|
@@ -154,7 +155,7 @@ class ModelSnapshotTopicConfig(BaseModel):
|
|
|
154
155
|
|
|
155
156
|
# Topic identity
|
|
156
157
|
topic: str = Field(
|
|
157
|
-
default=
|
|
158
|
+
default=SUFFIX_REGISTRATION_SNAPSHOTS,
|
|
158
159
|
min_length=1,
|
|
159
160
|
max_length=255,
|
|
160
161
|
description="Full Kafka topic name for registration snapshots",
|
|
@@ -442,7 +443,7 @@ class ModelSnapshotTopicConfig(BaseModel):
|
|
|
442
443
|
Default configuration instance with environment overrides
|
|
443
444
|
"""
|
|
444
445
|
base_config = cls(
|
|
445
|
-
topic=
|
|
446
|
+
topic=SUFFIX_REGISTRATION_SNAPSHOTS,
|
|
446
447
|
partition_count=12,
|
|
447
448
|
replication_factor=3,
|
|
448
449
|
cleanup_policy="compact",
|
|
@@ -18,12 +18,18 @@ from omnibase_infra.models.registration.events import (
|
|
|
18
18
|
ModelNodeRegistrationInitiated,
|
|
19
19
|
ModelNodeRegistrationRejected,
|
|
20
20
|
)
|
|
21
|
+
from omnibase_infra.models.registration.model_event_bus_topic_entry import (
|
|
22
|
+
ModelEventBusTopicEntry,
|
|
23
|
+
)
|
|
21
24
|
from omnibase_infra.models.registration.model_introspection_metrics import (
|
|
22
25
|
ModelIntrospectionMetrics,
|
|
23
26
|
)
|
|
24
27
|
from omnibase_infra.models.registration.model_node_capabilities import (
|
|
25
28
|
ModelNodeCapabilities,
|
|
26
29
|
)
|
|
30
|
+
from omnibase_infra.models.registration.model_node_event_bus_config import (
|
|
31
|
+
ModelNodeEventBusConfig,
|
|
32
|
+
)
|
|
27
33
|
from omnibase_infra.models.registration.model_node_heartbeat_event import (
|
|
28
34
|
ModelNodeHeartbeatEvent,
|
|
29
35
|
)
|
|
@@ -39,6 +45,9 @@ from omnibase_infra.models.registration.model_node_registration_record import (
|
|
|
39
45
|
)
|
|
40
46
|
|
|
41
47
|
__all__ = [
|
|
48
|
+
# Event bus configuration
|
|
49
|
+
"ModelEventBusTopicEntry",
|
|
50
|
+
"ModelNodeEventBusConfig",
|
|
42
51
|
# Metrics
|
|
43
52
|
"ModelIntrospectionMetrics",
|
|
44
53
|
# Decision events (C1 Orchestrator output)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Event Bus Topic Entry Model.
|
|
4
|
+
|
|
5
|
+
This module provides the model for a single topic entry in the event bus
|
|
6
|
+
configuration, containing the environment-qualified topic string and
|
|
7
|
+
optional tooling metadata.
|
|
8
|
+
|
|
9
|
+
Key Design Decisions:
|
|
10
|
+
1. Topics stored as environment-qualified strings (e.g., "dev.onex.evt.intent-classified.v1")
|
|
11
|
+
2. Metadata fields (event_type, message_category, description) are tooling-only
|
|
12
|
+
3. Routing uses ONLY the topic string - never metadata fields
|
|
13
|
+
4. Model is frozen (immutable) with extra="forbid" for safety
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class ModelEventBusTopicEntry(BaseModel):
|
|
22
|
+
"""Single topic entry with optional metadata.
|
|
23
|
+
|
|
24
|
+
IMPORTANT: Routing depends ONLY on the `topic` string.
|
|
25
|
+
Metadata fields (event_type, message_category, description) are
|
|
26
|
+
tooling-facing only and are never used for routing decisions.
|
|
27
|
+
|
|
28
|
+
Attributes:
|
|
29
|
+
topic: Environment-qualified topic string (e.g., "dev.onex.evt...").
|
|
30
|
+
This is the ONLY field used for routing.
|
|
31
|
+
event_type: Optional event model name. Tooling metadata only.
|
|
32
|
+
message_category: Message category (EVENT, COMMAND, INTENT).
|
|
33
|
+
Tooling metadata only. Defaults to "EVENT".
|
|
34
|
+
description: Optional human-readable description. Tooling metadata only.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
38
|
+
|
|
39
|
+
topic: str = Field(
|
|
40
|
+
...,
|
|
41
|
+
description="Environment-qualified topic string (e.g., 'dev.onex.evt.intent-classified.v1'). "
|
|
42
|
+
"This is the ONLY field used for routing.",
|
|
43
|
+
)
|
|
44
|
+
event_type: str | None = Field(
|
|
45
|
+
default=None,
|
|
46
|
+
description="Optional event model name. Tooling metadata only - never used for routing.",
|
|
47
|
+
)
|
|
48
|
+
message_category: str = Field(
|
|
49
|
+
default="EVENT",
|
|
50
|
+
description="Message category (EVENT, COMMAND, INTENT). "
|
|
51
|
+
"Tooling metadata only - never used for routing.",
|
|
52
|
+
)
|
|
53
|
+
description: str | None = Field(
|
|
54
|
+
default=None,
|
|
55
|
+
description="Optional human-readable description. Tooling metadata only.",
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
__all__ = ["ModelEventBusTopicEntry"]
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Node Event Bus Configuration Model.
|
|
4
|
+
|
|
5
|
+
This module provides the model for a node's resolved event bus configuration,
|
|
6
|
+
containing lists of topics the node subscribes to and publishes to.
|
|
7
|
+
|
|
8
|
+
Key Design Decisions:
|
|
9
|
+
1. Topics stored as environment-qualified strings (e.g., "dev.onex.evt.intent-classified.v1")
|
|
10
|
+
2. Metadata fields are tooling-only; routing uses ONLY topic strings
|
|
11
|
+
3. Property methods extract topic strings only for routing lookups
|
|
12
|
+
4. Model is frozen (immutable) with extra="forbid" for safety
|
|
13
|
+
|
|
14
|
+
Example:
|
|
15
|
+
>>> from omnibase_infra.models.registration import (
|
|
16
|
+
... ModelEventBusTopicEntry,
|
|
17
|
+
... ModelNodeEventBusConfig,
|
|
18
|
+
... )
|
|
19
|
+
>>> entry = ModelEventBusTopicEntry(
|
|
20
|
+
... topic="dev.onex.evt.intent-classified.v1",
|
|
21
|
+
... event_type="ModelIntentClassified",
|
|
22
|
+
... )
|
|
23
|
+
>>> config = ModelNodeEventBusConfig(subscribe_topics=[entry])
|
|
24
|
+
>>> config.subscribe_topic_strings
|
|
25
|
+
['dev.onex.evt.intent-classified.v1']
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
from __future__ import annotations
|
|
29
|
+
|
|
30
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
31
|
+
|
|
32
|
+
from omnibase_infra.models.registration.model_event_bus_topic_entry import (
|
|
33
|
+
ModelEventBusTopicEntry,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class ModelNodeEventBusConfig(BaseModel):
|
|
38
|
+
"""Resolved event bus configuration for registry storage.
|
|
39
|
+
|
|
40
|
+
This model holds the resolved, environment-qualified topic strings
|
|
41
|
+
that a node subscribes to and publishes to. It is designed for
|
|
42
|
+
storage in the registry to enable dynamic topic-based routing.
|
|
43
|
+
|
|
44
|
+
The property methods (subscribe_topic_strings, publish_topic_strings)
|
|
45
|
+
extract only the topic strings for routing lookups, ignoring all
|
|
46
|
+
metadata fields.
|
|
47
|
+
|
|
48
|
+
Attributes:
|
|
49
|
+
subscribe_topics: List of topics the node subscribes to.
|
|
50
|
+
publish_topics: List of topics the node publishes to.
|
|
51
|
+
|
|
52
|
+
Example:
|
|
53
|
+
>>> config = ModelNodeEventBusConfig(
|
|
54
|
+
... subscribe_topics=[
|
|
55
|
+
... ModelEventBusTopicEntry(topic="dev.onex.evt.input.v1"),
|
|
56
|
+
... ],
|
|
57
|
+
... publish_topics=[
|
|
58
|
+
... ModelEventBusTopicEntry(topic="dev.onex.evt.output.v1"),
|
|
59
|
+
... ],
|
|
60
|
+
... )
|
|
61
|
+
>>> config.subscribe_topic_strings
|
|
62
|
+
['dev.onex.evt.input.v1']
|
|
63
|
+
>>> config.publish_topic_strings
|
|
64
|
+
['dev.onex.evt.output.v1']
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
model_config = ConfigDict(frozen=True, extra="forbid")
|
|
68
|
+
|
|
69
|
+
subscribe_topics: list[ModelEventBusTopicEntry] = Field(
|
|
70
|
+
default_factory=list,
|
|
71
|
+
description="List of topics the node subscribes to.",
|
|
72
|
+
)
|
|
73
|
+
publish_topics: list[ModelEventBusTopicEntry] = Field(
|
|
74
|
+
default_factory=list,
|
|
75
|
+
description="List of topics the node publishes to.",
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
@property
|
|
79
|
+
def subscribe_topic_strings(self) -> list[str]:
|
|
80
|
+
"""Extract topic strings only, for routing lookups.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
List of environment-qualified topic strings from subscribe_topics.
|
|
84
|
+
Metadata fields are ignored.
|
|
85
|
+
"""
|
|
86
|
+
return [entry.topic for entry in self.subscribe_topics]
|
|
87
|
+
|
|
88
|
+
@property
|
|
89
|
+
def publish_topic_strings(self) -> list[str]:
|
|
90
|
+
"""Extract topic strings only, for routing lookups.
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
List of environment-qualified topic strings from publish_topics.
|
|
94
|
+
Metadata fields are ignored.
|
|
95
|
+
"""
|
|
96
|
+
return [entry.topic for entry in self.publish_topics]
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
__all__ = ["ModelNodeEventBusConfig"]
|
|
@@ -26,6 +26,9 @@ from omnibase_infra.models.discovery.model_introspection_performance_metrics imp
|
|
|
26
26
|
from omnibase_infra.models.registration.model_node_capabilities import (
|
|
27
27
|
ModelNodeCapabilities,
|
|
28
28
|
)
|
|
29
|
+
from omnibase_infra.models.registration.model_node_event_bus_config import (
|
|
30
|
+
ModelNodeEventBusConfig,
|
|
31
|
+
)
|
|
29
32
|
from omnibase_infra.models.registration.model_node_metadata import ModelNodeMetadata
|
|
30
33
|
from omnibase_infra.utils import (
|
|
31
34
|
validate_endpoint_urls_dict,
|
|
@@ -63,6 +66,8 @@ class ModelNodeIntrospectionEvent(BaseModel):
|
|
|
63
66
|
deployment_id: Deployment/release identifier.
|
|
64
67
|
epoch: Registration epoch for ordering.
|
|
65
68
|
performance_metrics: Optional metrics from introspection operation.
|
|
69
|
+
event_bus: Resolved event bus topic configuration for registry-driven routing.
|
|
70
|
+
If None, node is NOT included in dynamic topic routing lookups.
|
|
66
71
|
|
|
67
72
|
Example:
|
|
68
73
|
>>> from uuid import uuid4
|
|
@@ -179,6 +184,12 @@ class ModelNodeIntrospectionEvent(BaseModel):
|
|
|
179
184
|
default=None,
|
|
180
185
|
description="Performance metrics from introspection operation",
|
|
181
186
|
)
|
|
187
|
+
event_bus: ModelNodeEventBusConfig | None = Field(
|
|
188
|
+
default=None,
|
|
189
|
+
description="Resolved event bus topic configuration. "
|
|
190
|
+
"Contains environment-qualified topic strings for registry-driven routing. "
|
|
191
|
+
"If None, node is NOT included in dynamic topic routing lookups.",
|
|
192
|
+
)
|
|
182
193
|
|
|
183
194
|
|
|
184
195
|
__all__ = ["ModelNodeIntrospectionEvent"]
|
|
@@ -27,7 +27,15 @@ from omnibase_infra.models.runtime.model_plugin_load_summary import (
|
|
|
27
27
|
ModelPluginLoadSummary,
|
|
28
28
|
)
|
|
29
29
|
|
|
30
|
+
# ModelContractLoadResult and ModelRuntimeContractConfig are exported from
|
|
31
|
+
# omnibase_infra.runtime.models (canonical location for runtime loader models)
|
|
32
|
+
from omnibase_infra.runtime.models import (
|
|
33
|
+
ModelContractLoadResult,
|
|
34
|
+
ModelRuntimeContractConfig,
|
|
35
|
+
)
|
|
36
|
+
|
|
30
37
|
__all__ = [
|
|
38
|
+
"ModelContractLoadResult",
|
|
31
39
|
"ModelContractSecurityConfig",
|
|
32
40
|
"ModelDiscoveryError",
|
|
33
41
|
"ModelDiscoveryResult",
|
|
@@ -37,4 +45,5 @@ __all__ = [
|
|
|
37
45
|
"ModelLoadedHandler",
|
|
38
46
|
"ModelPluginLoadContext",
|
|
39
47
|
"ModelPluginLoadSummary",
|
|
48
|
+
"ModelRuntimeContractConfig",
|
|
40
49
|
]
|
|
@@ -13,7 +13,7 @@ and IDE support.
|
|
|
13
13
|
|
|
14
14
|
from __future__ import annotations
|
|
15
15
|
|
|
16
|
-
from collections.abc import Mapping
|
|
16
|
+
from collections.abc import Collection, Mapping
|
|
17
17
|
from uuid import uuid4
|
|
18
18
|
|
|
19
19
|
from pydantic import BaseModel, ConfigDict, Field
|
|
@@ -90,7 +90,7 @@ class ModelCoverageMetrics(BaseModel):
|
|
|
90
90
|
cls,
|
|
91
91
|
total: int,
|
|
92
92
|
registered: int,
|
|
93
|
-
unmapped:
|
|
93
|
+
unmapped: Collection[str],
|
|
94
94
|
) -> ModelCoverageMetrics:
|
|
95
95
|
"""Create coverage metrics from raw counts.
|
|
96
96
|
|