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.
Files changed (139) hide show
  1. omnibase_infra/constants_topic_patterns.py +26 -0
  2. omnibase_infra/enums/__init__.py +3 -0
  3. omnibase_infra/enums/enum_consumer_group_purpose.py +92 -0
  4. omnibase_infra/enums/enum_handler_source_mode.py +16 -2
  5. omnibase_infra/errors/__init__.py +4 -0
  6. omnibase_infra/errors/error_binding_resolution.py +128 -0
  7. omnibase_infra/event_bus/configs/kafka_event_bus_config.yaml +0 -2
  8. omnibase_infra/event_bus/event_bus_inmemory.py +64 -10
  9. omnibase_infra/event_bus/event_bus_kafka.py +105 -47
  10. omnibase_infra/event_bus/mixin_kafka_broadcast.py +3 -7
  11. omnibase_infra/event_bus/mixin_kafka_dlq.py +12 -6
  12. omnibase_infra/event_bus/models/config/model_kafka_event_bus_config.py +0 -81
  13. omnibase_infra/event_bus/testing/__init__.py +26 -0
  14. omnibase_infra/event_bus/testing/adapter_protocol_event_publisher_inmemory.py +418 -0
  15. omnibase_infra/event_bus/testing/model_publisher_metrics.py +64 -0
  16. omnibase_infra/handlers/handler_consul.py +2 -0
  17. omnibase_infra/handlers/mixins/__init__.py +5 -0
  18. omnibase_infra/handlers/mixins/mixin_consul_service.py +274 -10
  19. omnibase_infra/handlers/mixins/mixin_consul_topic_index.py +585 -0
  20. omnibase_infra/handlers/models/model_filesystem_config.py +4 -4
  21. omnibase_infra/migrations/001_create_event_ledger.sql +166 -0
  22. omnibase_infra/migrations/001_drop_event_ledger.sql +18 -0
  23. omnibase_infra/mixins/mixin_node_introspection.py +189 -19
  24. omnibase_infra/models/__init__.py +8 -0
  25. omnibase_infra/models/bindings/__init__.py +59 -0
  26. omnibase_infra/models/bindings/constants.py +144 -0
  27. omnibase_infra/models/bindings/model_binding_resolution_result.py +103 -0
  28. omnibase_infra/models/bindings/model_operation_binding.py +44 -0
  29. omnibase_infra/models/bindings/model_operation_bindings_subcontract.py +152 -0
  30. omnibase_infra/models/bindings/model_parsed_binding.py +52 -0
  31. omnibase_infra/models/discovery/model_introspection_config.py +25 -17
  32. omnibase_infra/models/dispatch/__init__.py +8 -0
  33. omnibase_infra/models/dispatch/model_debug_trace_snapshot.py +114 -0
  34. omnibase_infra/models/dispatch/model_materialized_dispatch.py +141 -0
  35. omnibase_infra/models/handlers/model_handler_source_config.py +1 -1
  36. omnibase_infra/models/model_node_identity.py +126 -0
  37. omnibase_infra/models/projection/model_snapshot_topic_config.py +3 -2
  38. omnibase_infra/models/registration/__init__.py +9 -0
  39. omnibase_infra/models/registration/model_event_bus_topic_entry.py +59 -0
  40. omnibase_infra/models/registration/model_node_event_bus_config.py +99 -0
  41. omnibase_infra/models/registration/model_node_introspection_event.py +11 -0
  42. omnibase_infra/models/runtime/__init__.py +9 -0
  43. omnibase_infra/models/validation/model_coverage_metrics.py +2 -2
  44. omnibase_infra/nodes/__init__.py +9 -0
  45. omnibase_infra/nodes/contract_registry_reducer/__init__.py +29 -0
  46. omnibase_infra/nodes/contract_registry_reducer/contract.yaml +255 -0
  47. omnibase_infra/nodes/contract_registry_reducer/models/__init__.py +38 -0
  48. omnibase_infra/nodes/contract_registry_reducer/models/model_contract_registry_state.py +266 -0
  49. omnibase_infra/nodes/contract_registry_reducer/models/model_payload_cleanup_topic_references.py +55 -0
  50. omnibase_infra/nodes/contract_registry_reducer/models/model_payload_deactivate_contract.py +58 -0
  51. omnibase_infra/nodes/contract_registry_reducer/models/model_payload_mark_stale.py +49 -0
  52. omnibase_infra/nodes/contract_registry_reducer/models/model_payload_update_heartbeat.py +71 -0
  53. omnibase_infra/nodes/contract_registry_reducer/models/model_payload_update_topic.py +66 -0
  54. omnibase_infra/nodes/contract_registry_reducer/models/model_payload_upsert_contract.py +92 -0
  55. omnibase_infra/nodes/contract_registry_reducer/node.py +121 -0
  56. omnibase_infra/nodes/contract_registry_reducer/reducer.py +784 -0
  57. omnibase_infra/nodes/contract_registry_reducer/registry/__init__.py +9 -0
  58. omnibase_infra/nodes/contract_registry_reducer/registry/registry_infra_contract_registry_reducer.py +101 -0
  59. omnibase_infra/nodes/handlers/consul/contract.yaml +85 -0
  60. omnibase_infra/nodes/handlers/db/contract.yaml +72 -0
  61. omnibase_infra/nodes/handlers/graph/contract.yaml +127 -0
  62. omnibase_infra/nodes/handlers/http/contract.yaml +74 -0
  63. omnibase_infra/nodes/handlers/intent/contract.yaml +66 -0
  64. omnibase_infra/nodes/handlers/mcp/contract.yaml +69 -0
  65. omnibase_infra/nodes/handlers/vault/contract.yaml +91 -0
  66. omnibase_infra/nodes/node_ledger_projection_compute/__init__.py +50 -0
  67. omnibase_infra/nodes/node_ledger_projection_compute/contract.yaml +104 -0
  68. omnibase_infra/nodes/node_ledger_projection_compute/node.py +284 -0
  69. omnibase_infra/nodes/node_ledger_projection_compute/registry/__init__.py +29 -0
  70. omnibase_infra/nodes/node_ledger_projection_compute/registry/registry_infra_ledger_projection.py +118 -0
  71. omnibase_infra/nodes/node_ledger_write_effect/__init__.py +82 -0
  72. omnibase_infra/nodes/node_ledger_write_effect/contract.yaml +200 -0
  73. omnibase_infra/nodes/node_ledger_write_effect/handlers/__init__.py +22 -0
  74. omnibase_infra/nodes/node_ledger_write_effect/handlers/handler_ledger_append.py +372 -0
  75. omnibase_infra/nodes/node_ledger_write_effect/handlers/handler_ledger_query.py +597 -0
  76. omnibase_infra/nodes/node_ledger_write_effect/models/__init__.py +31 -0
  77. omnibase_infra/nodes/node_ledger_write_effect/models/model_ledger_append_result.py +54 -0
  78. omnibase_infra/nodes/node_ledger_write_effect/models/model_ledger_entry.py +92 -0
  79. omnibase_infra/nodes/node_ledger_write_effect/models/model_ledger_query.py +53 -0
  80. omnibase_infra/nodes/node_ledger_write_effect/models/model_ledger_query_result.py +41 -0
  81. omnibase_infra/nodes/node_ledger_write_effect/node.py +89 -0
  82. omnibase_infra/nodes/node_ledger_write_effect/protocols/__init__.py +13 -0
  83. omnibase_infra/nodes/node_ledger_write_effect/protocols/protocol_ledger_persistence.py +127 -0
  84. omnibase_infra/nodes/node_ledger_write_effect/registry/__init__.py +9 -0
  85. omnibase_infra/nodes/node_ledger_write_effect/registry/registry_infra_ledger_write.py +121 -0
  86. omnibase_infra/nodes/node_registration_orchestrator/registry/registry_infra_node_registration_orchestrator.py +7 -5
  87. omnibase_infra/nodes/reducers/models/__init__.py +7 -2
  88. omnibase_infra/nodes/reducers/models/model_payload_consul_register.py +11 -0
  89. omnibase_infra/nodes/reducers/models/model_payload_ledger_append.py +133 -0
  90. omnibase_infra/nodes/reducers/registration_reducer.py +1 -0
  91. omnibase_infra/protocols/__init__.py +3 -0
  92. omnibase_infra/protocols/protocol_dispatch_engine.py +152 -0
  93. omnibase_infra/runtime/__init__.py +60 -0
  94. omnibase_infra/runtime/binding_resolver.py +753 -0
  95. omnibase_infra/runtime/constants_security.py +70 -0
  96. omnibase_infra/runtime/contract_loaders/__init__.py +9 -0
  97. omnibase_infra/runtime/contract_loaders/operation_bindings_loader.py +789 -0
  98. omnibase_infra/runtime/emit_daemon/__init__.py +97 -0
  99. omnibase_infra/runtime/emit_daemon/cli.py +844 -0
  100. omnibase_infra/runtime/emit_daemon/client.py +811 -0
  101. omnibase_infra/runtime/emit_daemon/config.py +535 -0
  102. omnibase_infra/runtime/emit_daemon/daemon.py +812 -0
  103. omnibase_infra/runtime/emit_daemon/event_registry.py +477 -0
  104. omnibase_infra/runtime/emit_daemon/model_daemon_request.py +139 -0
  105. omnibase_infra/runtime/emit_daemon/model_daemon_response.py +191 -0
  106. omnibase_infra/runtime/emit_daemon/queue.py +618 -0
  107. omnibase_infra/runtime/event_bus_subcontract_wiring.py +466 -0
  108. omnibase_infra/runtime/handler_source_resolver.py +43 -2
  109. omnibase_infra/runtime/kafka_contract_source.py +984 -0
  110. omnibase_infra/runtime/models/__init__.py +13 -0
  111. omnibase_infra/runtime/models/model_contract_load_result.py +224 -0
  112. omnibase_infra/runtime/models/model_runtime_contract_config.py +268 -0
  113. omnibase_infra/runtime/models/model_runtime_scheduler_config.py +4 -3
  114. omnibase_infra/runtime/models/model_security_config.py +109 -0
  115. omnibase_infra/runtime/publisher_topic_scoped.py +294 -0
  116. omnibase_infra/runtime/runtime_contract_config_loader.py +406 -0
  117. omnibase_infra/runtime/service_kernel.py +76 -6
  118. omnibase_infra/runtime/service_message_dispatch_engine.py +558 -15
  119. omnibase_infra/runtime/service_runtime_host_process.py +770 -20
  120. omnibase_infra/runtime/transition_notification_publisher.py +3 -2
  121. omnibase_infra/runtime/util_wiring.py +206 -62
  122. omnibase_infra/services/mcp/service_mcp_tool_sync.py +27 -9
  123. omnibase_infra/services/session/config_consumer.py +25 -8
  124. omnibase_infra/services/session/config_store.py +2 -2
  125. omnibase_infra/services/session/consumer.py +1 -1
  126. omnibase_infra/topics/__init__.py +45 -0
  127. omnibase_infra/topics/platform_topic_suffixes.py +140 -0
  128. omnibase_infra/topics/util_topic_composition.py +95 -0
  129. omnibase_infra/types/typed_dict/__init__.py +9 -1
  130. omnibase_infra/types/typed_dict/typed_dict_envelope_build_params.py +115 -0
  131. omnibase_infra/utils/__init__.py +9 -0
  132. omnibase_infra/utils/util_consumer_group.py +232 -0
  133. omnibase_infra/validation/infra_validators.py +18 -1
  134. omnibase_infra/validation/validation_exemptions.yaml +192 -0
  135. {omnibase_infra-0.2.5.dist-info → omnibase_infra-0.2.7.dist-info}/METADATA +3 -3
  136. {omnibase_infra-0.2.5.dist-info → omnibase_infra-0.2.7.dist-info}/RECORD +139 -52
  137. {omnibase_infra-0.2.5.dist-info → omnibase_infra-0.2.7.dist-info}/entry_points.txt +1 -0
  138. {omnibase_infra-0.2.5.dist-info → omnibase_infra-0.2.7.dist-info}/WHEEL +0 -0
  139. {omnibase_infra-0.2.5.dist-info → omnibase_infra-0.2.7.dist-info}/licenses/LICENSE +0 -0
@@ -65,7 +65,7 @@ import yaml
65
65
  from pydantic import ValidationError
66
66
 
67
67
  from omnibase_core.container import ModelONEXContainer
68
- from omnibase_infra.enums import EnumInfraTransportType
68
+ from omnibase_infra.enums import EnumConsumerGroupPurpose, EnumInfraTransportType
69
69
  from omnibase_infra.errors import (
70
70
  ModelInfraErrorContext,
71
71
  ProtocolConfigurationError,
@@ -75,6 +75,7 @@ from omnibase_infra.errors import (
75
75
  from omnibase_infra.event_bus.event_bus_inmemory import EventBusInmemory
76
76
  from omnibase_infra.event_bus.event_bus_kafka import EventBusKafka
77
77
  from omnibase_infra.event_bus.models.config import ModelKafkaEventBusConfig
78
+ from omnibase_infra.models import ModelNodeIdentity
78
79
  from omnibase_infra.nodes.node_registration_orchestrator.dispatchers import (
79
80
  DispatcherNodeIntrospected,
80
81
  )
@@ -499,7 +500,6 @@ async def bootstrap() -> int:
499
500
  kafka_config = ModelKafkaEventBusConfig(
500
501
  bootstrap_servers=kafka_bootstrap_servers, # type: ignore[arg-type] # NOTE: control flow narrowing limitation
501
502
  environment=environment,
502
- group=config.consumer_group,
503
503
  circuit_breaker_threshold=config.event_bus.circuit_breaker_threshold,
504
504
  )
505
505
  event_bus = EventBusKafka(config=kafka_config)
@@ -1033,13 +1033,39 @@ async def bootstrap() -> int:
1033
1033
  # RuntimeHostProcess accepts config as dict; cast model_dump() result to
1034
1034
  # dict[str, object] to avoid implicit Any typing (Pydantic's model_dump()
1035
1035
  # returns dict[str, Any] but all our model fields are strongly typed)
1036
+ #
1037
+ # NOTE: RuntimeHostProcess expects 'service_name' and 'node_name' keys,
1038
+ # but ModelRuntimeConfig uses 'name'. Map 'name' -> 'service_name'/'node_name'
1039
+ # for compatibility. (OMN-1602)
1040
+ #
1041
+ # INVARIANT: In the current runtime model, `ModelRuntimeConfig.name` represents
1042
+ # both `service_name` and `node_name` by design; multi-node services require
1043
+ # schema expansion.
1044
+ #
1045
+ # TRIGGER FOR SPLIT: Split when ServiceKernel supports registering multiple
1046
+ # node contracts under one service runtime.
1047
+ #
1048
+ # Why both fields get the same value:
1049
+ # - For services using simplified config with just 'name', there's no semantic
1050
+ # distinction between service and node - a single service hosts a single node
1051
+ # - RuntimeHostProcess uses these to construct ModelNodeIdentity for Kafka
1052
+ # consumer group IDs and event routing
1053
+ # - The introspection consumer group format is:
1054
+ # {env}.{service_name}.{node_name}.{purpose}.{version}
1055
+ # e.g., "local.my-service.my-service.introspection.v1"
1056
+ # - When service_name == node_name, the format is intentionally redundant but
1057
+ # maintains consistency with multi-node deployments where they would differ
1036
1058
  runtime_create_start_time = time.time()
1059
+ runtime_config_dict = cast("dict[str, object]", config.model_dump())
1060
+ if config.name:
1061
+ runtime_config_dict["service_name"] = config.name
1062
+ runtime_config_dict["node_name"] = config.name
1037
1063
  runtime = RuntimeHostProcess(
1038
1064
  container=container,
1039
1065
  event_bus=event_bus,
1040
1066
  input_topic=config.input_topic,
1041
1067
  output_topic=config.output_topic,
1042
- config=cast("dict[str, object]", config.model_dump()),
1068
+ config=runtime_config_dict,
1043
1069
  handler_registry=handler_registry,
1044
1070
  # Pass contracts directory for handler discovery (OMN-1317)
1045
1071
  # This enables contract-based handler registration instead of
@@ -1197,6 +1223,37 @@ async def bootstrap() -> int:
1197
1223
  event_bus=event_bus,
1198
1224
  )
1199
1225
 
1226
+ # Create typed node identity for introspection subscription (OMN-1602)
1227
+ # Uses ModelNodeIdentity + EnumConsumerGroupPurpose instead of hardcoded
1228
+ # group_id suffix hack for proper semantic consumer group naming.
1229
+ #
1230
+ # Required fields from config (fail-fast if missing):
1231
+ # - service_name: from config.name (required for node identification)
1232
+ # - node_name: from config.name (required for node identification)
1233
+ # Optional with defaults:
1234
+ # - env: from environment variable or event_bus.environment
1235
+ # - version: from config.contract_version or "v1"
1236
+ if not config.name:
1237
+ context = ModelInfraErrorContext(
1238
+ transport_type=EnumInfraTransportType.RUNTIME,
1239
+ operation="create_node_identity",
1240
+ correlation_id=correlation_id,
1241
+ )
1242
+ raise ProtocolConfigurationError(
1243
+ "Runtime config requires 'name' field for service identification. "
1244
+ "Add 'name: your-service-name' to runtime_config.yaml. "
1245
+ "This is required for typed introspection subscription (OMN-1602).",
1246
+ context=context,
1247
+ parameter="name",
1248
+ )
1249
+
1250
+ introspection_node_identity = ModelNodeIdentity(
1251
+ env=environment,
1252
+ service=config.name,
1253
+ node_name=config.name,
1254
+ version=config.contract_version or "v1",
1255
+ )
1256
+
1200
1257
  # Subscribe with callback - returns unsubscribe function
1201
1258
  subscribe_start_time = time.time()
1202
1259
  logger.info(
@@ -1204,15 +1261,22 @@ async def bootstrap() -> int:
1204
1261
  correlation_id,
1205
1262
  extra={
1206
1263
  "topic": config.input_topic,
1207
- "consumer_group": f"{config.consumer_group}-introspection",
1264
+ "node_identity": {
1265
+ "env": introspection_node_identity.env,
1266
+ "service": introspection_node_identity.service,
1267
+ "node_name": introspection_node_identity.node_name,
1268
+ "version": introspection_node_identity.version,
1269
+ },
1270
+ "purpose": EnumConsumerGroupPurpose.INTROSPECTION.value,
1208
1271
  "event_bus_type": event_bus_type,
1209
1272
  },
1210
1273
  )
1211
1274
 
1212
1275
  introspection_unsubscribe = await event_bus.subscribe(
1213
1276
  topic=config.input_topic,
1214
- group_id=f"{config.consumer_group}-introspection",
1277
+ node_identity=introspection_node_identity,
1215
1278
  on_message=introspection_event_router.handle_message,
1279
+ purpose=EnumConsumerGroupPurpose.INTROSPECTION,
1216
1280
  )
1217
1281
  subscribe_duration = time.time() - subscribe_start_time
1218
1282
 
@@ -1222,7 +1286,13 @@ async def bootstrap() -> int:
1222
1286
  correlation_id,
1223
1287
  extra={
1224
1288
  "topic": config.input_topic,
1225
- "consumer_group": f"{config.consumer_group}-introspection",
1289
+ "node_identity": {
1290
+ "env": introspection_node_identity.env,
1291
+ "service": introspection_node_identity.service,
1292
+ "node_name": introspection_node_identity.node_name,
1293
+ "version": introspection_node_identity.version,
1294
+ },
1295
+ "purpose": EnumConsumerGroupPurpose.INTROSPECTION.value,
1226
1296
  "subscribe_duration_seconds": subscribe_duration,
1227
1297
  "event_bus_type": event_bus_type,
1228
1298
  },