Repository navigation
feat(orchestrator): implement registration orchestrator node [C1] - #79
Conversation
Implement C1: Registration Orchestrator (Event-Driven) per ONEX_RUNTIME_REGISTRATION_TICKET_PLAN.md. ## Components Added ### Orchestrator Node - NodeRegistrationOrchestrator: Routes events to handlers, returns events only - Enforces architectural constraints: no I/O, injected time, events-only output ### Handlers - HandlerNodeIntrospected: Canonical trigger, emits NodeRegistrationInitiated - HandlerRuntimeTick: Timeout detection for ack/liveness deadlines - HandlerNodeRegistrationAcked: Processes ack commands, emits activation events ### Event Models (7 decision events) - ModelNodeRegistrationInitiated - ModelNodeRegistrationAccepted - ModelNodeRegistrationRejected - ModelNodeRegistrationAckTimedOut - ModelNodeRegistrationAckReceived - ModelNodeBecameActive - ModelNodeLivenessExpired ### Command Model - ModelNodeRegistrationAcked: Node acknowledgment command ### Context Model - ModelOrchestratorContext: Time injection with `now: datetime` ### Tests - 60 unit tests covering G2 acceptance criteria - Tests verify events-only output, injected time usage, deduplication ## Architectural Compliance - Orchestrators emit EVENTS only (no intents, no projections) - Orchestrators perform NO I/O (projection reads only) - Orchestrators use injected `now` for all time decisions - Uses ProtocolProjectionReader for state queries
📝 WalkthroughWalkthroughAdds a two‑way node registration workflow: new registration command/event models, three registration handlers (introspect, acked, runtime tick), explicit timezone‑aware timestamp injection across models and event bus headers, container wiring utilities, coroutine‑safety documentation, async metric APIs, and large test suites and docs. Changes
Sequence Diagram(s)sequenceDiagram
participant Node as Node\n(Introspection)
participant Bus as EventBus
participant IntHandler as HandlerNodeIntrospected
participant Orchestrator as RegistrationOrchestrator
participant Kafka as Kafka/InMemory
participant AckHandler as HandlerNodeRegistrationAcked
participant Tick as HandlerRuntimeTick
participant Proj as ProjectionReader
Node->>Bus: publish ModelNodeIntrospectionEvent (timestamp)
Bus->>IntHandler: deliver introspection
IntHandler->>Proj: query projection(node_id)
Proj-->>IntHandler: projection_state
alt new or retriable
IntHandler->>Bus: publish ModelNodeRegistrationInitiated (timestamp)
end
Bus->>Orchestrator: registration initiated
Orchestrator->>Bus: publish ModelNodeRegistrationAccepted (ack_deadline)
Bus->>Node: deliver accepted
Node->>Bus: publish ModelNodeRegistrationAcked (command, timestamp)
Bus->>AckHandler: deliver ack command
AckHandler->>Proj: query projection(node_id)
Proj-->>AckHandler: projection_state
alt state == AWAITING_ACK
AckHandler->>Bus: publish ModelNodeRegistrationAckReceived (liveness_deadline)
AckHandler->>Bus: publish ModelNodeBecameActive
else duplicate/ignored
AckHandler-->>Bus: no-op
end
par periodic
Kafka->>Tick: emit RuntimeTick
Tick->>Proj: query overdue acks & liveness
Proj-->>Tick: overdue list
Tick->>Bus: publish ModelNodeRegistrationAckTimedOut / ModelNodeLivenessExpired
end
Estimated Code Review Effort🎯 5 (Critical) | ⏱️ ~120 minutes Poem
📜 Recent review detailsConfiguration used: defaults Review profile: CHILL Plan: Lite 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
Comment |
PR Review: Registration Orchestrator [C1]This is an excellent implementation of the first orchestrator node in omnibase_infra. The code demonstrates strong adherence to ONEX architectural principles and establishes excellent patterns for future orchestrators. Below is my comprehensive review: ✅ Strengths1. Exceptional Architectural Compliance
2. Strong Type Safety
3. Excellent Documentation
4. Robust Test Coverage
5. Clean Handler PatternThe handler architecture is excellent:
|
| Aspect | dispatch/ version | orchestrators/ version |
|---|---|---|
correlation_id |
UUID | None (optional) |
UUID (required) |
| Description depth | Brief | More detailed |
Impact:
- Import confusion - which one should handlers use?
- Type inconsistency - correlation_id nullability differs
- Violates DRY principle
Recommendation:
- Keep only one: The
models/dispatch/version should be canonical (follows ONEX model organization) - Make correlation_id required: The orchestrator version is correct - correlation_id should be required for tracing
- Delete duplicate: Remove
orchestrators/registration/models/model_orchestrator_context.py - Update imports: Ensure handlers import from
omnibase_infra.models.dispatch
2. MEDIUM: Missing Correlation ID Type Consistency
Location: handler_runtime_tick.py:258-260
# Current code estimates last_heartbeat_at
last_heartbeat_at = projection.registered_at # Fallback to registration timeProblem: The comment acknowledges this is inaccurate ("should be stored in projection")
Impact:
ModelNodeLivenessExpired.last_heartbeat_atwill be incorrect when liveness expires- Debugging liveness issues will be harder without accurate heartbeat timestamps
Recommendation:
- Add
last_heartbeat_atfield toModelRegistrationProjectionschema - Update projector to track heartbeat timestamps
- Use actual last heartbeat time in liveness expiry events
- Create follow-up ticket for this enhancement (OMN-XXX: Track last_heartbeat_at in projection)
3. MEDIUM: Hardcoded Liveness Interval
Location: handler_node_registration_acked.py:60-62
# Default liveness interval in seconds
_DEFAULT_LIVENESS_INTERVAL_SECONDS: int = 60Problem:
- Comment says "should be configurable" but isn't
- Different nodes may need different liveness intervals
- No per-node configuration capability
Impact:
- One-size-fits-all approach may cause false positives (aggressive timeout) or delayed detection (lenient timeout)
- No runtime tuning capability
Recommendation:
- Short-term: Document this limitation in ONEX_RUNTIME_REGISTRATION_TICKET_PLAN.md
- Long-term: Add
liveness_interval_secondsto node capabilities or contract - Consider ticket: OMN-XXX: Configurable per-node liveness intervals
4. LOW: Inconsistent Null Type Annotation
Location: handler_runtime_tick.py:258, event models
Observation: Most code uses X | None (PEP 604), but some event models use datetime | None
Good news: This is mostly consistent! Just noting for awareness.
Recommendation:
- Continue using
X | Nonesyntax per CLAUDE.md guidelines ✅ - No changes needed
5. LOW: Minor Logging Opportunity
Location: handler_runtime_tick.py:189-190
# Double-check with projection helper (defensive)
if not projection.needs_ack_timeout_event(now):
continueObservation: If this defensive check triggers, it's silently skipped
Recommendation (optional):
if not projection.needs_ack_timeout_event(now):
logger.debug(
"Projection filtered by reader but failed helper check",
extra={"node_id": str(projection.entity_id), "correlation_id": str(correlation_id)},
)
continueThis helps debug potential projection reader vs helper inconsistencies.
🔒 Security Review
✅ Good Security Practices
- No credential exposure: No secrets in error messages or logs
- Sanitized logging: Node IDs and correlation IDs are safe to log
- Immutable models:
frozen=Trueprevents tampering - Input validation: Pydantic validates all incoming payloads
⚠️ Minor Security Consideration
Scenario: Unknown node sends NodeRegistrationAcked command
Current behavior:
if projection is None:
logger.warning("Received ack for unknown node", ...)
return []Consideration: In high-scale environments, an attacker could spam ack commands with random UUIDs
Recommendation (future enhancement):
- Add rate limiting for unknown node acks
- Consider metrics/alerting for suspicious ack patterns
- Not critical for MVP but worth tracking
🚀 Performance Considerations
1. Efficient Projection Queries
✅ Handler uses specific projection reader methods:
get_overdue_ack_registrations()- targeted queryget_overdue_liveness_registrations()- targeted query- No full table scans ✅
2. Deduplication at Database Level
✅ Emission markers (ack_timeout_emitted_at, liveness_timeout_emitted_at) prevent duplicate events efficiently
3. RuntimeTick Scalability
Potential concern: As the cluster grows, RuntimeTick handler scans all overdue entities
Current scale: Fine for MVP (<1000 nodes)
Future optimization (when needed):
- Batch processing with pagination
- Separate tick handlers per shard/region
- Priority queue for deadline detection
Recommendation: Document this in architecture notes, address when cluster size demands it
📋 Test Coverage Assessment
Excellent Test Patterns
- ✅ Uses mocks for projection reader (no database dependency)
- ✅ Deterministic time injection (
TEST_NOW) - ✅ Clear test naming (follows Given/When/Then)
- ✅ Edge cases covered (duplicates, terminal states, unknown nodes)
Test Coverage Highlights
- G2 acceptance criteria: 100% covered ✅
- State transitions: Comprehensive ✅
- Timeout detection: Well tested ✅
- Deduplication: Verified ✅
Minor Test Enhancement Suggestion
Consider adding:
async def test_concurrent_ack_processing_idempotency():
"""Verify multiple acks for same node are idempotent."""
# Simulate race condition where multiple acks arrive
# Assert only one set of events emittedThis tests thread-safety claims in docstrings.
🎯 ONEX Guidelines Compliance
| Guideline | Status | Notes |
|---|---|---|
No Any types |
✅ PASS | Consistent use of specific types |
| Pydantic models only | ✅ PASS | All data structures are proper models |
| One model per file | ✅ PASS | Follows model_*.py convention |
| Events-only output | ✅ PASS | Orchestrator architectural constraint met |
| Injected time | ✅ PASS | Never uses datetime.now() |
| No I/O in orchestrator | ✅ PASS | Projection reads are read-only queries |
| Protocol-based design | ✅ PASS | Uses ProtocolProjectionReader |
| Container injection | Orchestrator doesn't use container (projection reader injected directly) | |
| Correlation ID tracking | ✅ PASS | Proper propagation throughout |
| Error sanitization | ✅ PASS | No sensitive data in logs |
📝 Recommendations Summary
Must Fix Before Merge
- Resolve duplicate ModelOrchestratorContext - Delete orchestrators/registration/models/ version, update imports
Should Address Soon
- Track last_heartbeat_at in projection - Create follow-up ticket
- Make liveness interval configurable - Document limitation, create enhancement ticket
Nice to Have
- Add debug logging for defensive projection checks
- Consider concurrency test for ack idempotency
- Document RuntimeTick scalability considerations
🎉 Overall Assessment
Rating: 9/10 - Excellent implementation with minor issues
This PR establishes a strong pattern for future orchestrators. The code quality, documentation, and test coverage are exemplary. The duplicate ModelOrchestratorContext is the only blocking issue.
Why This Is Excellent
- First orchestrator in omnibase_infra - sets the standard
- Clean, testable handler architecture
- Strong adherence to ONEX architectural constraints
- Comprehensive documentation and tests
- Thoughtful design decisions (command vs event, deduplication, state machines)
Why Not Perfect
- Duplicate model definition needs cleanup
- Minor tech debt acknowledged in comments (last_heartbeat_at, configurable intervals)
✅ Approval Recommendation
APPROVE after fixing duplicate ModelOrchestratorContext issue.
The architectural patterns here are sound and will serve as the template for all future orchestrators. Great work! 🚀
Reviewed by: Claude Code (Sonnet 4.5)
Date: 2025-12-22
Guidelines: CLAUDE.md (ONEX Infrastructure)
There was a problem hiding this comment.
Actionable comments posted: 8
🧹 Nitpick comments (6)
src/omnibase_infra/models/registration/events/model_node_registration_initiated.py (1)
82-85: Consider makingemitted_atrequired to enforce injected time pattern.Per PR objectives, orchestrators must use "injected now" for all time decisions. The
default_factory=lambda: datetime.now(UTC)is convenient but could cause test non-determinism if callers forget to explicitly passemitted_at=context.now. Making the field required would enforce correct usage at the call site.This applies to all event models in this PR with similar defaults.
🔎 Alternative: require explicit time
# Timestamps emitted_at: datetime = Field( - default_factory=lambda: datetime.now(UTC), + ..., description="Timestamp when the orchestrator emitted this event (UTC)", )tests/unit/orchestrators/registration/test_handler_node_introspected.py (1)
43-43: Consider updating test date to 2025.
TEST_NOWuses 2024 but the file copyright is 2025. While this doesn't affect test correctness, updating to 2025 improves consistency.📝 Suggested update
-TEST_NOW = datetime(2024, 1, 15, 12, 0, 0, tzinfo=UTC) +TEST_NOW = datetime(2025, 1, 15, 12, 0, 0, tzinfo=UTC)tests/unit/orchestrators/registration/test_handler_node_registration_acked.py (1)
92-147: Recommended: Add emitted_at assertions to verify time injection.The test verifies event types, IDs, and liveness_deadline, but doesn't verify that
emitted_atmatches the injectednowparameter. Adding this assertion would catch violations of the time injection pattern (OMN-948).🔎 Suggested enhancement
# Second event: BecameActive became_active = events[1] assert isinstance(became_active, ModelNodeBecameActive) assert became_active.node_id == node_id assert became_active.entity_id == node_id assert became_active.correlation_id == correlation_id assert became_active.causation_id == ack_command.command_id assert became_active.capabilities == capabilities + # Verify time injection pattern + assert ack_received.emitted_at == TEST_NOW + assert became_active.emitted_at == TEST_NOWApply similar assertions to other test methods that verify event emission.
tests/unit/orchestrators/registration/test_node_registration_orchestrator.py (1)
246-257: Ineffective mock patch fordatetime.datetime.The patch
patch("datetime.datetime")patches thedatetimeclass in the test module's namespace, not in the orchestrator or handler modules wheredatetime.now()might be called. To verify thatdatetime.now()is never called in the handlers, you'd need to patch it in each handler's module namespace (e.g.,patch("omnibase_infra.orchestrators.registration.handlers.handler_runtime_tick.datetime")).However, the test still effectively validates the behavior via the mock assertions on
get_overdue_ack_registrationsandget_overdue_liveness_registrationsat lines 260-268, confirming the injectednowis passed correctly. Consider either removing the ineffective mock or patching the correct module namespaces.src/omnibase_infra/orchestrators/registration/handlers/handler_node_registration_acked.py (1)
236-262: Consider stronger typing forprojectionparameter.The
projectionparameter is typed asobjectwith an inline import and assert forModelRegistrationProjection. While this works, a cleaner approach would be to useTYPE_CHECKINGfor the import and type the parameter directly, avoiding the assert.🔎 Suggested refactor
from typing import TYPE_CHECKING from uuid import UUID from omnibase_infra.enums import EnumRegistrationState if TYPE_CHECKING: from pydantic import BaseModel + from omnibase_infra.models.projection.model_registration_projection import ( + ModelRegistrationProjection, + ) ... def _emit_activation_events( self, command: ModelNodeRegistrationAcked, now: datetime, correlation_id: UUID, - projection: object, # ModelRegistrationProjection + projection: ModelRegistrationProjection, ) -> list[BaseModel]: ... - from omnibase_infra.models.projection.model_registration_projection import ( - ModelRegistrationProjection, - ) - - # Type assertion for projection - assert isinstance(projection, ModelRegistrationProjection) - node_id = command.node_idsrc/omnibase_infra/orchestrators/registration/handlers/handler_runtime_tick.py (1)
188-202: Use explicit type narrowing instead of type: ignore.Line 199 suppresses a legitimate type error. While the defensive check on line 190 should ensure
ack_deadlineis not None, the type system cannot prove this. Use an explicit None check for proper type narrowing.🔎 Proposed type narrowing
for projection in overdue_projections: # Double-check with projection helper (defensive) if not projection.needs_ack_timeout_event(now): continue + + # Type narrowing: ensure ack_deadline is not None + if projection.ack_deadline is None: + logger.warning( + "Projection passed needs_ack_timeout_event but has no ack_deadline", + extra={ + "node_id": str(projection.entity_id), + "correlation_id": str(correlation_id), + }, + ) + continue event = ModelNodeRegistrationAckTimedOut( entity_id=projection.entity_id, node_id=projection.entity_id, correlation_id=correlation_id, causation_id=tick.tick_id, # Link to triggering tick emitted_at=now, - deadline_at=projection.ack_deadline, # type: ignore[arg-type] + deadline_at=projection.ack_deadline, )
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Lite
📒 Files selected for processing (28)
src/omnibase_infra/models/dispatch/__init__.pysrc/omnibase_infra/models/dispatch/model_orchestrator_context.pysrc/omnibase_infra/models/registration/__init__.pysrc/omnibase_infra/models/registration/commands/__init__.pysrc/omnibase_infra/models/registration/commands/model_node_registration_acked.pysrc/omnibase_infra/models/registration/events/__init__.pysrc/omnibase_infra/models/registration/events/model_node_became_active.pysrc/omnibase_infra/models/registration/events/model_node_liveness_expired.pysrc/omnibase_infra/models/registration/events/model_node_registration_accepted.pysrc/omnibase_infra/models/registration/events/model_node_registration_ack_received.pysrc/omnibase_infra/models/registration/events/model_node_registration_ack_timed_out.pysrc/omnibase_infra/models/registration/events/model_node_registration_initiated.pysrc/omnibase_infra/models/registration/events/model_node_registration_rejected.pysrc/omnibase_infra/orchestrators/__init__.pysrc/omnibase_infra/orchestrators/registration/__init__.pysrc/omnibase_infra/orchestrators/registration/handlers/__init__.pysrc/omnibase_infra/orchestrators/registration/handlers/handler_node_introspected.pysrc/omnibase_infra/orchestrators/registration/handlers/handler_node_registration_acked.pysrc/omnibase_infra/orchestrators/registration/handlers/handler_runtime_tick.pysrc/omnibase_infra/orchestrators/registration/models/__init__.pysrc/omnibase_infra/orchestrators/registration/models/model_orchestrator_context.pysrc/omnibase_infra/orchestrators/registration/node_registration_orchestrator.pytests/unit/orchestrators/__init__.pytests/unit/orchestrators/registration/__init__.pytests/unit/orchestrators/registration/test_handler_node_introspected.pytests/unit/orchestrators/registration/test_handler_node_registration_acked.pytests/unit/orchestrators/registration/test_handler_runtime_tick.pytests/unit/orchestrators/registration/test_node_registration_orchestrator.py
🧰 Additional context used
📓 Path-based instructions (2)
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.py: NEVER useAnytypes in Python code. Always use specific types. UseX | None(PEP 604) syntax instead ofOptional[X]for nullable types.
UseEnumMessageCategory(values: EVENT, COMMAND, INTENT) for message routing, topic parsing, and dispatcher selection. UseEnumNodeOutputType(values: EVENT, COMMAND, INTENT, PROJECTION) for execution shape validation and handler return type validation. PROJECTION exists only in EnumNodeOutputType and is only valid for REDUCER nodes.
UseX | Nonesyntax (PEP 604) for nullable types instead ofOptional[X]. Example:def get_user(id: str) -> User | None:instead ofdef get_user(id: str) -> Optional[User]:
All services MUST useModelONEXContainerfor dependency injection. Bootstrap pattern:container = ModelONEXContainer()followed bywire_infrastructure_services(container)andservice = container.service_registry.resolve_service(ServiceType).
Always propagate correlation_id from incoming requests to error context. Auto-generate usinguuid4()if no correlation_id exists. Use UUID format for all new correlation IDs. Include correlation_id in all error context for distributed tracing.
NEVER include in error messages or context: passwords, API keys, tokens, secrets, full connection strings with credentials, PII (names, emails, SSNs, phone numbers), internal IP addresses (in production logs), private keys or certificates, session tokens or cookies.
SAFE to include in error messages: service names (e.g., 'postgresql', 'kafka'), operation names (e.g., 'connect', 'query'), correlation IDs (always include for tracing), error codes, sanitized hostnames, port numbers, retry counts, timeout values, resource identifiers (non-sensitive).
UseProtocolConfigurationErrorfor config validation failures,SecretResolutionErrorfor secret/credential resolution,InfraConnectionErrorfor connection failures,InfraTimeoutErrorfor operation timeouts,InfraAuthenticationErrorfor auth/authz failures, `InfraUnava...
Files:
tests/unit/orchestrators/registration/test_handler_node_registration_acked.pysrc/omnibase_infra/orchestrators/registration/handlers/handler_runtime_tick.pysrc/omnibase_infra/models/registration/__init__.pysrc/omnibase_infra/orchestrators/registration/handlers/handler_node_registration_acked.pysrc/omnibase_infra/models/dispatch/__init__.pysrc/omnibase_infra/orchestrators/__init__.pysrc/omnibase_infra/models/registration/events/model_node_liveness_expired.pysrc/omnibase_infra/models/dispatch/model_orchestrator_context.pysrc/omnibase_infra/orchestrators/registration/handlers/handler_node_introspected.pysrc/omnibase_infra/models/registration/events/model_node_became_active.pytests/unit/orchestrators/__init__.pysrc/omnibase_infra/models/registration/events/__init__.pysrc/omnibase_infra/models/registration/commands/__init__.pysrc/omnibase_infra/orchestrators/registration/__init__.pytests/unit/orchestrators/registration/test_handler_runtime_tick.pysrc/omnibase_infra/models/registration/events/model_node_registration_accepted.pysrc/omnibase_infra/models/registration/events/model_node_registration_ack_timed_out.pysrc/omnibase_infra/models/registration/commands/model_node_registration_acked.pysrc/omnibase_infra/orchestrators/registration/node_registration_orchestrator.pytests/unit/orchestrators/registration/test_node_registration_orchestrator.pysrc/omnibase_infra/models/registration/events/model_node_registration_rejected.pysrc/omnibase_infra/orchestrators/registration/models/model_orchestrator_context.pytests/unit/orchestrators/registration/test_handler_node_introspected.pysrc/omnibase_infra/models/registration/events/model_node_registration_initiated.pysrc/omnibase_infra/models/registration/events/model_node_registration_ack_received.pytests/unit/orchestrators/registration/__init__.pysrc/omnibase_infra/orchestrators/registration/models/__init__.pysrc/omnibase_infra/orchestrators/registration/handlers/__init__.py
**/model_*.py
📄 CodeRabbit inference engine (CLAUDE.md)
All data structures must be proper Pydantic models. One model per file named as
model_<name>.pywith class patternModel<Name>. Files must contain exactly oneModel*class.
Files:
src/omnibase_infra/models/registration/events/model_node_liveness_expired.pysrc/omnibase_infra/models/dispatch/model_orchestrator_context.pysrc/omnibase_infra/models/registration/events/model_node_became_active.pysrc/omnibase_infra/models/registration/events/model_node_registration_accepted.pysrc/omnibase_infra/models/registration/events/model_node_registration_ack_timed_out.pysrc/omnibase_infra/models/registration/commands/model_node_registration_acked.pysrc/omnibase_infra/models/registration/events/model_node_registration_rejected.pysrc/omnibase_infra/orchestrators/registration/models/model_orchestrator_context.pysrc/omnibase_infra/models/registration/events/model_node_registration_initiated.pysrc/omnibase_infra/models/registration/events/model_node_registration_ack_received.py
🧠 Learnings (20)
📓 Common learnings
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T16:55:49.755Z
Learning: Applies to agents/**/*.py : Implement ONEX-compliant agent architecture with four node types: Effect (External I/O), Compute (Pure transforms), Reducer (State/persistence), and Orchestrator (Workflow coordination)
📚 Learning: 2025-11-24T16:32:55.606Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T16:32:55.606Z
Learning: Applies to tests/unit/infrastructure/**/test_*.py : All node implementations must have comprehensive unit tests following the testing pattern in `tests/unit/infrastructure/` with tests for node initialization and node execution
Applied to files:
tests/unit/orchestrators/registration/test_handler_node_registration_acked.pytests/unit/orchestrators/__init__.pytests/unit/orchestrators/registration/test_node_registration_orchestrator.pytests/unit/orchestrators/registration/test_handler_node_introspected.py
📚 Learning: 2025-12-22T00:11:20.308Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-22T00:11:20.308Z
Learning: Applies to **/node.py : All ONEX node base classes and I/O models come from `omnibase_core.nodes`: NodeEffect, NodeCompute, NodeReducer, NodeOrchestrator, ModelEffectInput, ModelEffectOutput, ModelComputeInput, ModelComputeOutput, ModelReducerInput, ModelReducerOutput, ModelOrchestratorInput, ModelOrchestratorOutput. Never define new node archetypes in infra.
Applied to files:
src/omnibase_infra/models/registration/__init__.pysrc/omnibase_infra/orchestrators/__init__.pysrc/omnibase_infra/models/registration/events/model_node_became_active.pysrc/omnibase_infra/models/registration/events/__init__.pysrc/omnibase_infra/models/registration/events/model_node_registration_accepted.pysrc/omnibase_infra/models/registration/events/model_node_registration_initiated.py
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/models/model_contract_*.py : All ONEX node auto-generated Pydantic models must be organized in a `models/` directory with files for state.py, model_contract_actions.py, model_contract_models.py, model_contract_validation.py, model_contract_cli.py (optional), model_contract_capabilities.py (optional), and error_codes.py, generated from the corresponding contract definitions
Applied to files:
src/omnibase_infra/models/registration/__init__.pysrc/omnibase_infra/models/registration/events/model_node_registration_accepted.pysrc/omnibase_infra/models/registration/commands/model_node_registration_acked.py
📚 Learning: 2025-11-28T18:58:53.781Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/canonical_patterns.mdc:0-0
Timestamp: 2025-11-28T18:58:53.781Z
Learning: Organize models under `src/omnibase_core/models/` by domain including: base, cli, common, config, core, contracts, discovery, health, infrastructure, logging, metadata, nodes, operations, results, security, service, tools, validation, and workflows
Applied to files:
src/omnibase_infra/models/registration/__init__.pysrc/omnibase_infra/models/registration/events/__init__.py
📚 Learning: 2025-11-24T16:32:55.606Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T16:32:55.606Z
Learning: Node communication must use event-driven patterns through `ModelEventEnvelope` from `omnibase_core.models.events.model_event_envelope`
Applied to files:
src/omnibase_infra/models/registration/__init__.pysrc/omnibase_infra/models/registration/events/model_node_became_active.pysrc/omnibase_infra/models/registration/events/model_node_registration_accepted.py
📚 Learning: 2025-12-08T00:48:30.737Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_spi PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-08T00:48:30.737Z
Learning: Import `omnibase_core` models and types only for type hints and runtime usage - follow the SPI → Core dependency direction
Applied to files:
src/omnibase_infra/models/dispatch/__init__.py
📚 Learning: 2025-11-24T16:33:32.747Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/standards.mdc:0-0
Timestamp: 2025-11-24T16:33:32.747Z
Learning: Applies to **/*.py : Import models from shared core paths using `omnibase.model.core.model_*` pattern
Applied to files:
src/omnibase_infra/models/dispatch/__init__.py
📚 Learning: 2025-11-24T16:32:55.606Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T16:32:55.606Z
Learning: ORCHESTRATOR Nodes must inherit from `NodeOrchestrator` or use `NodeOrchestratorService` and must coordinate workflows, manage node interactions, and handle process/event orchestration
Applied to files:
src/omnibase_infra/orchestrators/__init__.pytests/unit/orchestrators/__init__.pysrc/omnibase_infra/orchestrators/registration/__init__.pysrc/omnibase_infra/orchestrators/registration/node_registration_orchestrator.py
📚 Learning: 2025-12-03T16:55:49.755Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T16:55:49.755Z
Learning: Applies to agents/**/*.py : Implement ONEX-compliant agent architecture with four node types: Effect (External I/O), Compute (Pure transforms), Reducer (State/persistence), and Orchestrator (Workflow coordination)
Applied to files:
src/omnibase_infra/orchestrators/__init__.py
📚 Learning: 2025-12-06T22:21:32.649Z
Learnt from: CR
Repo: OmniNode-ai/omniagent PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T22:21:32.649Z
Learning: Applies to nodes/**/*.py : Use `omnibase_infra` handlers for OmniIntelligence queries via HttpRestAdapter envelope pattern
Applied to files:
src/omnibase_infra/orchestrators/registration/handlers/handler_node_introspected.py
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/introspection.py : All ONEX nodes must include an `introspection.py` file implementing standards-compliant introspection logic
Applied to files:
src/omnibase_infra/orchestrators/registration/handlers/handler_node_introspected.pytests/unit/orchestrators/registration/test_handler_node_introspected.py
📚 Learning: 2025-11-28T18:58:53.781Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/canonical_patterns.mdc:0-0
Timestamp: 2025-11-28T18:58:53.781Z
Learning: Applies to **/*.py : Implement Node classes by inheriting from `NodeBase` with proper UUID and `ModelSemVer` fields
Applied to files:
src/omnibase_infra/models/registration/events/model_node_became_active.pysrc/omnibase_infra/models/registration/events/model_node_registration_accepted.pysrc/omnibase_infra/models/registration/events/model_node_registration_ack_timed_out.pysrc/omnibase_infra/models/registration/commands/model_node_registration_acked.py
📚 Learning: 2025-11-30T21:55:10.298Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: Applies to src/omninode_bridge/nodes/**/{models,node}.py : Bridge nodes MUST implement FSM states: PENDING, PROCESSING, COMPLETED, FAILED. Use Pydantic v2 models with proper state enum validation
Applied to files:
src/omnibase_infra/models/registration/events/model_node_became_active.pysrc/omnibase_infra/models/registration/events/model_node_registration_accepted.pysrc/omnibase_infra/models/registration/events/model_node_registration_ack_timed_out.pysrc/omnibase_infra/models/registration/commands/model_node_registration_acked.pysrc/omnibase_infra/models/registration/events/model_node_registration_rejected.pysrc/omnibase_infra/models/registration/events/model_node_registration_initiated.py
📚 Learning: 2025-12-06T22:21:32.649Z
Learnt from: CR
Repo: OmniNode-ai/omniagent PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T22:21:32.649Z
Learning: Applies to tests/**/*.py : Organize test files into `tests/unit/`, `tests/integration/`, and `tests/nodes/` directories
Applied to files:
tests/unit/orchestrators/__init__.py
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/node_tests/**/*.py : All ONEX node tests must be organized in a `node_tests/` directory using scenario-driven testing patterns with fixture-injected tests
Applied to files:
tests/unit/orchestrators/__init__.pytests/unit/orchestrators/registration/test_node_registration_orchestrator.pytests/unit/orchestrators/registration/test_handler_node_introspected.py
📚 Learning: 2025-11-24T17:24:54.193Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-24T17:24:54.193Z
Learning: Organize test files in directory structure: node_name/v1_0_0/ with scenarios/, snapshots/, and node_tests/test_scenarios.py subdirectories
Applied to files:
tests/unit/orchestrators/__init__.py
📚 Learning: 2025-11-30T21:55:10.298Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: Applies to src/omninode_bridge/nodes/**/*.py : All nodes in omninode_bridge MUST use omnibase_core standards (ModelServiceEffect, ModelServiceCompute for effect/compute nodes; NodeOrchestrator, NodeReducer with mixins for orchestrator/reducer nodes)
Applied to files:
tests/unit/orchestrators/__init__.pysrc/omnibase_infra/models/registration/events/model_node_registration_accepted.pysrc/omnibase_infra/models/registration/commands/model_node_registration_acked.py
📚 Learning: 2025-12-07T17:50:13.678Z
Learnt from: CR
Repo: OmniNode-ai/omniintelligence PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-07T17:50:13.678Z
Learning: Organize tests following the structure: tests/conftest.py for shared fixtures, tests/unit/ for unit tests (no infrastructure), tests/integration/ for integration tests (requires Kafka/DBs), tests/nodes/ for node-specific tests
Applied to files:
tests/unit/orchestrators/__init__.py
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/models/error_codes.py : All ONEX node error handling must use auto-generated error codes defined in `models/error_codes.py` from contract definitions
Applied to files:
src/omnibase_infra/models/registration/events/model_node_registration_accepted.pysrc/omnibase_infra/models/registration/events/model_node_registration_rejected.py
🧬 Code graph analysis (17)
tests/unit/orchestrators/registration/test_handler_node_registration_acked.py (8)
src/omnibase_infra/enums/enum_registration_state.py (1)
EnumRegistrationState(24-258)src/omnibase_infra/models/registration/model_node_capabilities.py (1)
ModelNodeCapabilities(13-167)src/omnibase_infra/models/registration/commands/model_node_registration_acked.py (1)
ModelNodeRegistrationAcked(29-99)src/omnibase_infra/models/registration/events/model_node_became_active.py (1)
ModelNodeBecameActive(25-93)src/omnibase_infra/models/registration/events/model_node_registration_ack_received.py (1)
ModelNodeRegistrationAckReceived(21-89)src/omnibase_infra/orchestrators/registration/handlers/handler_node_registration_acked.py (2)
HandlerNodeRegistrationAcked(65-294)handle(114-234)src/omnibase_infra/projectors/projection_reader_registration.py (2)
ProjectionReaderRegistration(45-655)get_entity_state(145-225)tests/helpers/deterministic.py (1)
now(136-147)
src/omnibase_infra/orchestrators/registration/handlers/handler_runtime_tick.py (5)
src/omnibase_infra/models/projection/model_registration_projection.py (3)
ModelRegistrationProjection(34-326)needs_ack_timeout_event(284-304)needs_liveness_timeout_event(306-326)src/omnibase_infra/models/registration/events/model_node_liveness_expired.py (1)
ModelNodeLivenessExpired(21-93)src/omnibase_infra/models/registration/events/model_node_registration_ack_timed_out.py (1)
ModelNodeRegistrationAckTimedOut(21-93)src/omnibase_infra/projectors/projection_reader_registration.py (1)
ProjectionReaderRegistration(45-655)src/omnibase_infra/runtime/models/model_runtime_tick.py (1)
ModelRuntimeTick(59-186)
src/omnibase_infra/models/registration/__init__.py (7)
src/omnibase_infra/models/registration/events/model_node_became_active.py (1)
ModelNodeBecameActive(25-93)src/omnibase_infra/models/registration/events/model_node_liveness_expired.py (1)
ModelNodeLivenessExpired(21-93)src/omnibase_infra/models/registration/events/model_node_registration_accepted.py (1)
ModelNodeRegistrationAccepted(21-89)src/omnibase_infra/models/registration/events/model_node_registration_ack_received.py (1)
ModelNodeRegistrationAckReceived(21-89)src/omnibase_infra/models/registration/events/model_node_registration_ack_timed_out.py (1)
ModelNodeRegistrationAckTimedOut(21-93)src/omnibase_infra/models/registration/events/model_node_registration_initiated.py (1)
ModelNodeRegistrationInitiated(22-91)src/omnibase_infra/models/registration/events/model_node_registration_rejected.py (1)
ModelNodeRegistrationRejected(21-94)
src/omnibase_infra/models/dispatch/__init__.py (2)
src/omnibase_infra/models/dispatch/model_orchestrator_context.py (1)
ModelOrchestratorContext(33-89)src/omnibase_infra/orchestrators/registration/models/model_orchestrator_context.py (1)
ModelOrchestratorContext(48-110)
src/omnibase_infra/orchestrators/__init__.py (1)
src/omnibase_infra/orchestrators/registration/node_registration_orchestrator.py (1)
NodeRegistrationOrchestrator(72-307)
src/omnibase_infra/models/dispatch/model_orchestrator_context.py (1)
src/omnibase_infra/orchestrators/registration/models/model_orchestrator_context.py (1)
ModelOrchestratorContext(48-110)
src/omnibase_infra/orchestrators/registration/handlers/handler_node_introspected.py (3)
src/omnibase_infra/enums/enum_registration_state.py (1)
EnumRegistrationState(24-258)src/omnibase_infra/models/registration/events/model_node_registration_initiated.py (1)
ModelNodeRegistrationInitiated(22-91)src/omnibase_infra/projectors/projection_reader_registration.py (1)
get_entity_state(145-225)
src/omnibase_infra/models/registration/events/model_node_became_active.py (1)
src/omnibase_infra/models/registration/model_node_capabilities.py (1)
ModelNodeCapabilities(13-167)
src/omnibase_infra/models/registration/events/__init__.py (7)
src/omnibase_infra/models/registration/events/model_node_became_active.py (1)
ModelNodeBecameActive(25-93)src/omnibase_infra/models/registration/events/model_node_liveness_expired.py (1)
ModelNodeLivenessExpired(21-93)src/omnibase_infra/models/registration/events/model_node_registration_accepted.py (1)
ModelNodeRegistrationAccepted(21-89)src/omnibase_infra/models/registration/events/model_node_registration_ack_received.py (1)
ModelNodeRegistrationAckReceived(21-89)src/omnibase_infra/models/registration/events/model_node_registration_ack_timed_out.py (1)
ModelNodeRegistrationAckTimedOut(21-93)src/omnibase_infra/models/registration/events/model_node_registration_initiated.py (1)
ModelNodeRegistrationInitiated(22-91)src/omnibase_infra/models/registration/events/model_node_registration_rejected.py (1)
ModelNodeRegistrationRejected(21-94)
src/omnibase_infra/models/registration/commands/__init__.py (1)
src/omnibase_infra/models/registration/commands/model_node_registration_acked.py (1)
ModelNodeRegistrationAcked(29-99)
tests/unit/orchestrators/registration/test_handler_runtime_tick.py (8)
src/omnibase_infra/enums/enum_registration_state.py (1)
EnumRegistrationState(24-258)src/omnibase_infra/models/registration/model_node_capabilities.py (1)
ModelNodeCapabilities(13-167)src/omnibase_infra/models/registration/events/model_node_liveness_expired.py (1)
ModelNodeLivenessExpired(21-93)src/omnibase_infra/models/registration/events/model_node_registration_ack_timed_out.py (1)
ModelNodeRegistrationAckTimedOut(21-93)src/omnibase_infra/orchestrators/registration/handlers/handler_runtime_tick.py (2)
HandlerRuntimeTick(62-285)handle(102-155)src/omnibase_infra/projectors/projection_reader_registration.py (3)
ProjectionReaderRegistration(45-655)get_overdue_ack_registrations(381-477)get_overdue_liveness_registrations(479-577)src/omnibase_infra/runtime/models/model_runtime_tick.py (1)
ModelRuntimeTick(59-186)src/omnibase_infra/orchestrators/registration/handlers/handler_node_introspected.py (1)
handle(119-213)
src/omnibase_infra/models/registration/commands/model_node_registration_acked.py (1)
tests/helpers/deterministic.py (1)
now(136-147)
src/omnibase_infra/orchestrators/registration/node_registration_orchestrator.py (6)
src/omnibase_infra/models/registration/commands/model_node_registration_acked.py (1)
ModelNodeRegistrationAcked(29-99)src/omnibase_infra/orchestrators/registration/handlers/handler_node_introspected.py (2)
HandlerNodeIntrospected(77-213)handle(119-213)src/omnibase_infra/orchestrators/registration/handlers/handler_node_registration_acked.py (2)
HandlerNodeRegistrationAcked(65-294)handle(114-234)src/omnibase_infra/orchestrators/registration/handlers/handler_runtime_tick.py (2)
HandlerRuntimeTick(62-285)handle(102-155)src/omnibase_infra/projectors/projection_reader_registration.py (1)
ProjectionReaderRegistration(45-655)src/omnibase_infra/runtime/models/model_runtime_tick.py (1)
ModelRuntimeTick(59-186)
src/omnibase_infra/orchestrators/registration/models/model_orchestrator_context.py (2)
src/omnibase_infra/models/dispatch/model_orchestrator_context.py (1)
ModelOrchestratorContext(33-89)tests/helpers/deterministic.py (1)
now(136-147)
tests/unit/orchestrators/registration/test_handler_node_introspected.py (4)
src/omnibase_infra/enums/enum_registration_state.py (1)
EnumRegistrationState(24-258)src/omnibase_infra/models/registration/events/model_node_registration_initiated.py (1)
ModelNodeRegistrationInitiated(22-91)src/omnibase_infra/orchestrators/registration/handlers/handler_node_introspected.py (2)
HandlerNodeIntrospected(77-213)handle(119-213)src/omnibase_infra/projectors/projection_reader_registration.py (2)
ProjectionReaderRegistration(45-655)get_entity_state(145-225)
src/omnibase_infra/orchestrators/registration/models/__init__.py (1)
src/omnibase_infra/orchestrators/registration/models/model_orchestrator_context.py (1)
ModelOrchestratorContext(48-110)
src/omnibase_infra/orchestrators/registration/handlers/__init__.py (3)
src/omnibase_infra/orchestrators/registration/handlers/handler_node_introspected.py (1)
HandlerNodeIntrospected(77-213)src/omnibase_infra/orchestrators/registration/handlers/handler_node_registration_acked.py (1)
HandlerNodeRegistrationAcked(65-294)src/omnibase_infra/orchestrators/registration/handlers/handler_runtime_tick.py (1)
HandlerRuntimeTick(62-285)
🔇 Additional comments (32)
src/omnibase_infra/models/registration/commands/model_node_registration_acked.py (1)
29-66: Well-documented command model with clear semantics.The distinction between commands (imperative requests) and events (facts) is clearly documented. The validity conditions and state machine transitions are well-specified, aiding maintainability.
src/omnibase_infra/models/registration/events/model_node_registration_accepted.py (1)
21-51: LGTM!The model correctly requires
ack_deadline(no default), ensuring callers must compute it explicitly from the injected time context. The docstring clearly explains the handshake semantics and timeout behavior.src/omnibase_infra/models/registration/events/model_node_registration_ack_received.py (1)
21-51: LGTM!The model correctly requires
liveness_deadlinewith no default, ensuring explicit computation from injected time. The docstring clearly explains the handshake completion and transition to liveness monitoring.tests/unit/orchestrators/__init__.py (1)
1-3: LGTM!Standard test package initializer following ONEX conventions. No executable code or imports needed at this level.
src/omnibase_infra/orchestrators/registration/models/__init__.py (1)
1-21: LGTM!Clean package initialization following ONEX model export patterns. The docstring clearly explains the exported context model and handler return type conventions.
src/omnibase_infra/orchestrators/__init__.py (1)
1-24: LGTM!Excellent documentation of ONEX orchestrator constraints. The docstring clearly establishes the architectural boundaries (events-only output, no I/O, injected time, projection reads only) that align with the PR objectives.
tests/unit/orchestrators/registration/__init__.py (1)
1-16: LGTM!Clear test scope documentation that aligns with the PR's G2 acceptance criteria. The validation goals (events-only, injected time, deduplication, idempotency) are well-articulated.
tests/unit/orchestrators/registration/test_handler_node_introspected.py (4)
83-139: LGTM!Excellent coverage of G2 requirement 3. Tests thoroughly validate that
HandlerNodeIntrospectedemitsModelNodeRegistrationInitiatedfor new nodes with proper field linkage (causation_id, entity_id, node_id, correlation_id).
141-205: LGTM!Comprehensive coverage of G2 requirement 4 using parameterized tests. All blocking states are validated to ensure no registration initiation occurs.
207-312: LGTM!Thorough validation of retriable state handling. Tests confirm that nodes in LIVENESS_EXPIRED, REJECTED, and ACK_TIMED_OUT states can re-initiate registration as per the state decision matrix.
314-419: LGTM!Excellent validation of event field correctness and projection reader integration. Tests ensure proper correlation/causation linkage, unique registration attempts, and correct projection query parameters.
src/omnibase_infra/models/registration/commands/__init__.py (1)
1-15: LGTM!Clean command model package following ONEX patterns. The docstring appropriately distinguishes commands (imperative requests) from events, aligning with orchestrator architecture.
src/omnibase_infra/models/registration/events/model_node_registration_ack_timed_out.py (1)
1-96: LGTM!Well-structured event model following ONEX patterns. Excellent documentation of event semantics, FSM impact (AWAITING_ACK → ACK_TIMED_OUT), and deduplication strategy via emission markers (C2 requirement).
src/omnibase_infra/models/registration/events/__init__.py (1)
1-56: LGTM!Clean barrel export pattern for the 7 registration decision event models. All imports match the
__all__declaration.src/omnibase_infra/orchestrators/registration/handlers/__init__.py (1)
1-41: LGTM!Clean re-export pattern for the three orchestrator handlers with proper
__all__declaration.tests/unit/orchestrators/registration/test_handler_runtime_tick.py (1)
100-138: LGTM! Excellent time injection test coverage.These tests properly validate that:
emitted_atmatches the injectednowparameter (lines 137, 503)- The handler passes injected
nowto projection reader methods (lines 445-449, 471-475)This comprehensive coverage of the time injection pattern (OMN-948) serves as a good example for other test files.
Also applies to: 478-503
src/omnibase_infra/models/registration/events/model_node_liveness_expired.py (1)
86-89: Critical: Replace default_factory with explicit emitted_at in orchestrator handlers.The
default_factory=lambda: datetime.now(UTC)violates the architectural constraint that orchestrators must use injected time. Per the PR objectives: "All time decisions use injected now."Orchestrator handlers receive
now: datetimeas a parameter (line 24 mentions "from tick.now"), but this default_factory bypasses that by calling system time directly. This breaks:
- Deterministic testing (tests can't control emitted_at)
- Time injection pattern (OMN-948)
- Architectural compliance (C1 global constraints)
Solution: Remove the default_factory and require orchestrator handlers to explicitly pass
emitted_at=nowwhen constructing events.🔎 Proposed fix
emitted_at: datetime = Field( ..., - description="When the liveness expiry was detected (from RuntimeTick.now)", + description=( + "When the liveness expiry was detected. MUST be set explicitly " + "from handler's injected now parameter (from RuntimeTick.now)." + ), )Then update handlers to pass
emitted_at=nowexplicitly when creating events.Likely an incorrect or invalid review comment.
tests/unit/orchestrators/registration/test_node_registration_orchestrator.py (4)
1-97: LGTM!The test setup is well-structured with deterministic time (
TEST_NOW), properly typed helper functions, and comprehensive mock setup. Thecreate_projectionhelper covers all relevant projection fields for testing various registration states.
100-213: Good coverage for G2 "events-only" requirement.These tests comprehensively verify that the orchestrator emits only events (no intents, no projections) for all three payload types: introspection, runtime tick, and ack command. The assertions correctly validate event types.
309-411: LGTM!The routing tests thoroughly verify payload-to-handler routing for all supported types and correctly test the
ValueErrorfor unknown payloads.
414-547: LGTM!Correlation ID handling and convenience method tests are well-structured and cover both explicit and fallback correlation ID scenarios.
src/omnibase_infra/models/registration/events/model_node_became_active.py (1)
25-94: LGTM!The event model is well-documented with a comprehensive docstring, follows the frozen Pydantic pattern for immutability, uses
extra="forbid"for strict validation, and properly types all fields. TheModelNodeCapabilitiescomposition enables routing and discovery decisions as documented.src/omnibase_infra/orchestrators/registration/node_registration_orchestrator.py (4)
65-68: TYPE_CHECKING pattern is correctly used.The
from __future__ import annotationsimport (line 38) ensures annotations are evaluated as strings, making it safe to importBaseModelonly for type checking. This avoids a runtime circular import while maintaining type safety.
113-127: LGTM!Clean constructor that initializes handlers with the shared projection reader. The handler composition pattern supports testability and follows the single responsibility principle.
134-223: LGTM!The routing logic is well-structured:
- Proper correlation ID resolution with a three-level fallback chain (explicit → envelope → uuid4())
- Clear isinstance-based routing to handlers
- Appropriate ValueError for unsupported payloads with informative message
- Good debug logging at each routing branch
252-279: Good fallback behavior fornowin runtime tick handler.The
handle_runtime_tickconvenience method correctly falls back totick.nowifnowis not provided, maintaining consistency with the time injection pattern while providing ergonomic usage.src/omnibase_infra/orchestrators/registration/handlers/handler_node_registration_acked.py (2)
114-171: LGTM!The
handlemethod correctly implements the state decision matrix. The projection query followed by state-based branching is clean, and the ACCEPTED/AWAITING_ACK states correctly trigger activation events.
173-234: Comprehensive state handling with appropriate logging.The handler correctly implements idempotent behavior for duplicate acks (ACK_RECEIVED, ACTIVE), warns on early acks (PENDING_REGISTRATION), late acks (ACK_TIMED_OUT), and terminal states. The catch-all for unexpected states provides defensive coverage.
src/omnibase_infra/orchestrators/registration/__init__.py (1)
1-48: LGTM!The package
__init__.pyprovides a clean public API surface with comprehensive documentation. The re-exports are well-organized and the__all__list correctly enumerates all public symbols.src/omnibase_infra/models/registration/__init__.py (1)
1-54: LGTM! Clean module organization for registration events.The module properly exports the 7 new decision event models following the ONEX event-driven architecture pattern. The imports and all exports are consistent, and the updated docstring clearly describes the 2-way registration workflow.
src/omnibase_infra/orchestrators/registration/handlers/handler_runtime_tick.py (2)
1-101: LGTM! Clean handler setup with proper dependency injection.The module docstring clearly describes the timeout detection logic and deduplication strategy. The handler follows the stateless, dependency-injected pattern appropriate for orchestrator handlers.
102-156: LGTM! Well-structured timeout detection with proper logging.The handle method correctly delegates to specialized helpers for ack and liveness timeout detection, and provides clear diagnostic logging when timeouts are detected.
| initiated_event = ModelNodeRegistrationInitiated( | ||
| entity_id=node_id, | ||
| node_id=node_id, | ||
| correlation_id=correlation_id, | ||
| causation_id=event.correlation_id, # Link to triggering event | ||
| registration_attempt_id=uuid4(), | ||
| ) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Find the handler file and examine relevant lines
find . -type f -name "handler_node_introspected.py" 2>/dev/null | head -5
# Also search for ModelNodeRegistrationInitiated and ModelNodeIntrospectionEvent definitions
echo "=== Searching for event model definitions ==="
find . -type f -name "*.py" -type f 2>/dev/null | xargs grep -l "ModelNodeRegistrationInitiated\|ModelNodeIntrospectionEvent" 2>/dev/null | head -10Repository: OmniNode-ai/omnibase_infra
Length of output: 831
🏁 Script executed:
#!/bin/bash
# Get the full handler file content to examine lines 119-124 and 196-202
if find . -name "handler_node_introspected.py" 2>/dev/null | head -1; then
FILE=$(find . -name "handler_node_introspected.py" 2>/dev/null | head -1)
echo "=== Handler file: $FILE ==="
wc -l "$FILE"
echo ""
echo "=== Lines 115-130 (handler signature) ==="
sed -n '115,130p' "$FILE"
echo ""
echo "=== Lines 190-210 (event creation) ==="
sed -n '190,210p' "$FILE"
fiRepository: OmniNode-ai/omnibase_infra
Length of output: 1681
🏁 Script executed:
#!/bin/bash
# Search for ModelNodeRegistrationInitiated definition
echo "=== Searching for ModelNodeRegistrationInitiated ==="
find . -type f -name "*.py" 2>/dev/null | xargs grep -A 10 "class ModelNodeRegistrationInitiated" 2>/dev/null | head -30
echo ""
echo "=== Searching for ModelNodeIntrospectionEvent ==="
find . -type f -name "*.py" 2>/dev/null | xargs grep -A 10 "class ModelNodeIntrospectionEvent" 2>/dev/null | head -30Repository: OmniNode-ai/omnibase_infra
Length of output: 4242
🏁 Script executed:
#!/bin/bash
# Examine ModelNodeRegistrationInitiated completely
echo "=== Full ModelNodeRegistrationInitiated ==="
cat ./src/omnibase_infra/models/registration/events/model_node_registration_initiated.py
echo ""
echo "=== Full ModelNodeIntrospectionEvent (registration) ==="
cat ./src/omnibase_infra/models/registration/model_node_introspection_event.pyRepository: OmniNode-ai/omnibase_infra
Length of output: 8391
Critical: Handler must use injected now for emitted_at.
The handler receives now: datetime (line 122) but doesn't pass it when creating the event. The event will use default_factory=lambda: datetime.now(UTC) instead, violating the time injection pattern for testability.
Additionally, line 200 sets causation_id=event.correlation_id, but causation_id should be the message_id of the triggering event, not its correlation_id. Since ModelNodeIntrospectionEvent lacks a message_id field, the event model needs architectural clarification to properly implement causal tracing.
Fix:
- Add
emitted_at=nowto theModelNodeRegistrationInitiatedconstructor - Either add a
message_idfield toModelNodeIntrospectionEventor document the causal tracing strategy for events without explicit message IDs
🤖 Prompt for AI Agents
In
src/omnibase_infra/orchestrators/registration/handlers/handler_node_introspected.py
around lines 196-202, the created ModelNodeRegistrationInitiated event must use
the injected now for emitted_at and must set causation_id to the triggering
event's message_id (not its correlation_id); update the constructor call to
include emitted_at=now and set causation_id=event.message_id, and if
ModelNodeIntrospectionEvent currently lacks a message_id add that field (or
update the event model / docs to define the causal tracing approach so handlers
can reliably use message_id for causation).
Bump INFRA_MAX_UNIONS from 515 to 540 to accommodate ~20 new legitimate `X | None` nullable unions added by the registration orchestrator models (correlation_id, trace_id, deadlines, etc.).
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
src/omnibase_infra/validation/infra_validators.py (1)
637-638: Stale threshold value in docstring.The docstring references
INFRA_MAX_UNIONS (465)but the constant is now540. Consider referencing the constant name only (without the value) to avoid future drift, or update to the current value.🔎 Suggested fix
- max_unions: Maximum union count threshold. Defaults to INFRA_MAX_UNIONS (465). + max_unions: Maximum union count threshold. Defaults to INFRA_MAX_UNIONS.tests/unit/validation/test_validator_defaults.py (2)
240-244: Stale threshold value in comment.Line 242 comment says
Default max (410)butINFRA_MAX_UNIONSis now540. This appears to be a leftover from an earlier threshold.🔎 Suggested fix
mock_validate.assert_called_once_with( INFRA_SRC_PATH, # Default directory - max_unions=INFRA_MAX_UNIONS, # Default max (410) + max_unions=INFRA_MAX_UNIONS, # Default max strict=INFRA_UNIONS_STRICT, # Strict mode (True) per OMN-983 )
492-498: Stale threshold values in docstring.The docstring references
~402 unions as of 2025-12-20andINFRA_MAX_UNIONS (410)which are outdated. The baseline is now ~534 and threshold is 540 as documented in the updated test at lines 43-50.🔎 Suggested fix
- Current baseline (~402 unions as of 2025-12-20): + Current baseline (~534 unions as of 2025-12-22): - Most unions are legitimate `X | None` nullable patterns (ONEX-preferred) - These are counted but NOT flagged as violations - Actual violations (primitive soup, Union[X,None] syntax) are reported separately - Threshold: INFRA_MAX_UNIONS (410) - buffer above baseline after json_types.py. + Threshold: INFRA_MAX_UNIONS (540) - buffer above baseline after OMN-C1 orchestrator. Target: Reduce to <200 through ongoing dict[str, object] → JsonValue migration.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Lite
📒 Files selected for processing (2)
src/omnibase_infra/validation/infra_validators.pytests/unit/validation/test_validator_defaults.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.py: NEVER useAnytypes in Python code. Always use specific types. UseX | None(PEP 604) syntax instead ofOptional[X]for nullable types.
UseEnumMessageCategory(values: EVENT, COMMAND, INTENT) for message routing, topic parsing, and dispatcher selection. UseEnumNodeOutputType(values: EVENT, COMMAND, INTENT, PROJECTION) for execution shape validation and handler return type validation. PROJECTION exists only in EnumNodeOutputType and is only valid for REDUCER nodes.
UseX | Nonesyntax (PEP 604) for nullable types instead ofOptional[X]. Example:def get_user(id: str) -> User | None:instead ofdef get_user(id: str) -> Optional[User]:
All services MUST useModelONEXContainerfor dependency injection. Bootstrap pattern:container = ModelONEXContainer()followed bywire_infrastructure_services(container)andservice = container.service_registry.resolve_service(ServiceType).
Always propagate correlation_id from incoming requests to error context. Auto-generate usinguuid4()if no correlation_id exists. Use UUID format for all new correlation IDs. Include correlation_id in all error context for distributed tracing.
NEVER include in error messages or context: passwords, API keys, tokens, secrets, full connection strings with credentials, PII (names, emails, SSNs, phone numbers), internal IP addresses (in production logs), private keys or certificates, session tokens or cookies.
SAFE to include in error messages: service names (e.g., 'postgresql', 'kafka'), operation names (e.g., 'connect', 'query'), correlation IDs (always include for tracing), error codes, sanitized hostnames, port numbers, retry counts, timeout values, resource identifiers (non-sensitive).
UseProtocolConfigurationErrorfor config validation failures,SecretResolutionErrorfor secret/credential resolution,InfraConnectionErrorfor connection failures,InfraTimeoutErrorfor operation timeouts,InfraAuthenticationErrorfor auth/authz failures, `InfraUnava...
Files:
tests/unit/validation/test_validator_defaults.pysrc/omnibase_infra/validation/infra_validators.py
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T16:32:55.606Z
Learning: ORCHESTRATOR Nodes must inherit from `NodeOrchestrator` or use `NodeOrchestratorService` and must coordinate workflows, manage node interactions, and handle process/event orchestration
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T16:55:49.755Z
Learning: Applies to agents/**/*.py : Implement ONEX-compliant agent architecture with four node types: Effect (External I/O), Compute (Pure transforms), Reducer (State/persistence), and Orchestrator (Workflow coordination)
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: Applies to src/omninode_bridge/nodes/**/{models,node}.py : Bridge nodes MUST implement FSM states: PENDING, PROCESSING, COMPLETED, FAILED. Use Pydantic v2 models with proper state enum validation
🔇 Additional comments (2)
src/omnibase_infra/validation/infra_validators.py (1)
330-338: LGTM - Threshold increase is well-documented.The bump from 515 to 540 to accommodate ~20 new nullable unions from registration orchestrator models is reasonable. The baseline tracking (534 as of 2025-12-22) and rationale for the buffer are clearly documented.
tests/unit/validation/test_validator_defaults.py (1)
43-54: LGTM - Test expectations correctly updated.The test assertion and documentation are updated to match the new
INFRA_MAX_UNIONSthreshold of 540. The rationale mentioning OMN-C1 orchestrator provides good traceability.
Merged origin/main with conflict resolution: - Combined threshold history documentation from both branches - Updated INFRA_MAX_UNIONS from 515 to 555 to accommodate: - OMN-C1 registration orchestrator models (~19 unions) - Additional unions from main branch merge (~14 unions)
Pull Request Review: Registration Orchestrator Node [C1]SummaryThis PR implements the first orchestrator node in omnibase_infra, establishing a critical architectural pattern for the ONEX runtime registration system. Overall Assessment: ✅ APPROVE with minor suggestions 🎯 Strengths1. Excellent Architectural Compliance
2. Clean Handler Pattern
3. Robust State Management
4. Comprehensive Testing
5. Documentation Quality
🐛 Potential Issues (Minor, Non-Blocking)1. Hardcoded Default
|
…onsolidation [C1] - Consolidate duplicate ModelOrchestratorContext to single source of truth - Remove dispatch version, use orchestrators/registration version with required correlation_id - Fix time injection pattern: make emitted_at required in event models - Remove default_factory=lambda: datetime.now(UTC) from event models - Add explicit emitted_at=now to handler event creation - Fix handler_runtime_tick last_heartbeat_at fallback (use now instead of registered_at) - Replace type:ignore with explicit type narrowing for ack_deadline - Update test dates from 2024 to 2025 BREAKING: emitted_at is now required in ModelNodeRegistrationRejected and ModelNodeBecameActive
PR Review: Registration Orchestrator (C1) ImplementationOverviewThis PR implements the first orchestrator node in omnibase_infra, establishing critical patterns for event-driven workflow coordination. The implementation is architecturally sound and demonstrates excellent adherence to ONEX principles. ✅ Strengths1. Exemplary ONEX Compliance
2. Clean Handler Architecture
3. Robust Event Models
4. Excellent Documentation
5. Comprehensive Test Coverage
🔍 Issues Found1. Critical: Model DuplicationLocation: Issue:
Impact:
Recommendation:
2. Type Annotation InconsistencyLocation: Issue: # Current: Uses detection time as "last heartbeat"
last_heartbeat_at = nowProblem: Recommendation: # Use None to indicate unknown last heartbeat
last_heartbeat_at = None # Unknown - projection doesn't track this yetRationale: Honesty over approximation. If future work adds heartbeat tracking, this field can be populated accurately. 3. Missing Defensive NarrowingLocation: Issue: Type narrowing is correct but could fail silently: ack_deadline = projection.ack_deadline
if ack_deadline is None:
# This shouldn't happen since needs_ack_timeout_event checks this
continue # Silent skip - no loggingRecommendation: Add warning log since this indicates a projection consistency issue: if ack_deadline is None:
logger.warning(
"Projection passed needs_ack_timeout_event but ack_deadline is None",
extra={"node_id": str(projection.entity_id)}
)
continue🎯 Architectural Observations✅ Pattern EstablishmentThis PR establishes the canonical orchestrator pattern for omnibase_infra:
Impact: Future orchestrators (C2, C3, etc.) can follow this template. ✅ Durable Timeout Handling (C2)Excellent implementation of emission markers:
|
| Convention | Status | Notes |
|---|---|---|
File naming (model_*.py) |
✅ | All models follow convention |
Class naming (Model*, Handler*) |
✅ | Correct |
Type annotations (no Any) |
✅ | Uses ModelEventEnvelope[object] |
| Enum usage | ✅ | EnumRegistrationState properly used |
| One model per file | ✅ | Verified |
| Protocol resolution | N/A | No protocol resolution in this PR |
| Container injection | Orchestrator uses direct dependency injection (not container) - acceptable for MVP |
🚀 Recommendations
High Priority
- Resolve
ModelOrchestratorContextduplication (see Issue feat: PostgreSQL Adapter with Comprehensive Tests and Structured Logging #1) - Fix
last_heartbeat_atsemantics (see Issue Add Claude Code GitHub Workflow #2) - Add defensive logging for projection consistency checks (see Issue feat: RedPanda Event Bus Integration with Fail-Fast Infrastructure #3)
Medium Priority
- Consider adding integration tests (current tests are all unit tests with mocks)
- Add
mypy --strictvalidation to pre-commit hooks (if not already present)
Low Priority (Future Work)
- Document RuntimeTick scalability considerations in
handler_runtime_tick.py - Consider extracting state transition logic to FSM helper (if more orchestrators need it)
🎉 Verdict
Recommendation: APPROVE with minor changes
This is exceptional work that establishes a solid foundation for ONEX orchestrators. The architectural compliance, documentation quality, and test coverage are all excellent.
The issues found are minor and easily addressed:
- Model duplication is a cleanup task (no functional impact)
last_heartbeat_atfix is a 1-line change- Defensive logging is nice-to-have
This PR can merge after resolving Issue #1 (ModelOrchestratorContext duplication).
CLAUDE.md Compliance Score: 9.5/10
- Strengths: Strong typing, agent-driven, events-only, no backwards compatibility, excellent docs
- Deduction: Model duplication violates DRY, minor type semantics issue
Great work establishing the orchestrator pattern! 🚀
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (3)
src/omnibase_infra/orchestrators/registration/handlers/handler_node_introspected.py (1)
196-203:emitted_at=nowis correctly passed;causation_iduses correlation_id as documented fallback.The previous review flagged that
emitted_atshould use injected time — this is now correctly implemented withemitted_at=now.Regarding
causation_id=event.correlation_id: sinceModelNodeIntrospectionEventdoesn't have amessage_idfield, usingcorrelation_idis an acceptable fallback for causal tracing. Consider adding a brief inline comment documenting this decision for future maintainers.🔎 Suggested documentation
initiated_event = ModelNodeRegistrationInitiated( entity_id=node_id, node_id=node_id, correlation_id=correlation_id, - causation_id=event.correlation_id, # Link to triggering event + # causation_id: Using correlation_id since ModelNodeIntrospectionEvent + # lacks message_id. This maintains causal linkage for tracing. + causation_id=event.correlation_id, emitted_at=now, # Use injected time for consistency registration_attempt_id=uuid4(), )src/omnibase_infra/orchestrators/registration/handlers/handler_runtime_tick.py (1)
261-277:last_heartbeat_atsemantics are documented but potentially misleading.The comment explains the rationale for using
now(detection time) instead ofNoneorregistered_at. However, settinglast_heartbeat_at=nowis semantically inaccurate —nowrepresents when the expiry was detected, not when the last heartbeat was received.Per the past review, consider passing
Noneto indicate "no heartbeat data available" sinceModelNodeLivenessExpired.last_heartbeat_atacceptsNone. This would be more semantically correct than using detection time.🔎 Proposed alternative
- # Determine last heartbeat time for the event. - # The projection stores liveness_deadline (expected next heartbeat) but not - # last_heartbeat_at directly. We use detection time (now) as the best - # approximation since: - # 1. registered_at could be very stale for long-running nodes - # 2. liveness_deadline is when we expected, not when we received - # 3. Detection time is the last moment we confirmed the node unreachable - last_heartbeat_at = now + # TODO: Store actual last_heartbeat_at in projection (see future ticket) + # Pass None to indicate no heartbeat timestamp data is available. + # This is more accurate than using detection time or registered_at. + last_heartbeat_at = None event = ModelNodeLivenessExpired( entity_id=projection.entity_id, node_id=projection.entity_id, correlation_id=correlation_id, causation_id=tick.tick_id, # Link to triggering tick emitted_at=now, last_heartbeat_at=last_heartbeat_at, )src/omnibase_infra/orchestrators/registration/handlers/handler_node_registration_acked.py (1)
268-285:emitted_at=nowcorrectly passed for time injection consistency.Both
ModelNodeRegistrationAckReceivedandModelNodeBecameActivenow use the injectednowtimestamp, addressing the previous review concern.
🧹 Nitpick comments (2)
src/omnibase_infra/orchestrators/registration/handlers/handler_node_registration_acked.py (1)
236-242: Consider using precise type hint forprojectionparameter.The
projectionparameter is typed asobjectwith a comment indicatingModelRegistrationProjection, requiring an assert and local import. Since this is an internal method, consider typing it directly.🔎 Proposed improvement
+ from omnibase_infra.models.projection.model_registration_projection import ( + ModelRegistrationProjection, + ) + def _emit_activation_events( self, command: ModelNodeRegistrationAcked, now: datetime, correlation_id: UUID, - projection: object, # ModelRegistrationProjection + projection: ModelRegistrationProjection, ) -> list[BaseModel]:Then remove the local import and assert at lines 257-262.
tests/unit/orchestrators/registration/test_node_registration_orchestrator.py (1)
245-269: Datetime patching may not catch system clock usage.The
patch("datetime.datetime")at line 246 patches the module-leveldatetime, but since the handler importsfrom datetime import datetime, the patch won't intercept calls made via the local binding. The test's assertions at lines 260-268 effectively verify the behavior by checking that the injectednowis passed to projection reader calls, which is the important verification.Consider removing the ineffective patch and relying solely on the mock assertions, or adding a clearer comment explaining the verification strategy.
🔎 Simplified test without ineffective patch
- # Act - Patch datetime.now to ensure it's never called - with patch("datetime.datetime") as mock_datetime: - # Preserve the real datetime class for type checking - mock_datetime.side_effect = lambda *args, **kwargs: datetime( - *args, **kwargs - ) - - # The orchestrator should NOT call datetime.now() - events = await orchestrator.handle( - envelope=envelope, - now=TEST_NOW, - correlation_id=tick.correlation_id, - ) + # Act + events = await orchestrator.handle( + envelope=envelope, + now=TEST_NOW, + correlation_id=tick.correlation_id, + ) - # Assert - deadline queries use injected now - mock_reader.get_overdue_ack_registrations.assert_called_once_with( - now=TEST_NOW, - domain="registration", - correlation_id=tick.correlation_id, - ) + # Assert - deadline queries use injected now (not system clock) + mock_reader.get_overdue_ack_registrations.assert_called_once_with( + now=TEST_NOW, + domain="registration", + correlation_id=tick.correlation_id, + )
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Lite
📒 Files selected for processing (15)
src/omnibase_infra/models/dispatch/__init__.pysrc/omnibase_infra/models/registration/events/model_node_became_active.pysrc/omnibase_infra/models/registration/events/model_node_registration_rejected.pysrc/omnibase_infra/orchestrators/registration/handlers/handler_node_introspected.pysrc/omnibase_infra/orchestrators/registration/handlers/handler_node_registration_acked.pysrc/omnibase_infra/orchestrators/registration/handlers/handler_runtime_tick.pytests/helpers/deterministic.pytests/integration/runtime/test_dispatch_context_integration.pytests/unit/handlers/test_handler_http.pytests/unit/orchestrators/registration/test_handler_node_introspected.pytests/unit/orchestrators/registration/test_handler_node_registration_acked.pytests/unit/orchestrators/registration/test_handler_runtime_tick.pytests/unit/orchestrators/registration/test_node_registration_orchestrator.pytests/unit/plugins/test_plugin_compute_base.pytests/unit/plugins/test_plugin_compute_determinism.py
✅ Files skipped from review due to trivial changes (2)
- tests/unit/plugins/test_plugin_compute_determinism.py
- tests/integration/runtime/test_dispatch_context_integration.py
🚧 Files skipped from review as they are similar to previous changes (5)
- tests/unit/orchestrators/registration/test_handler_node_registration_acked.py
- src/omnibase_infra/models/registration/events/model_node_registration_rejected.py
- src/omnibase_infra/models/registration/events/model_node_became_active.py
- tests/unit/orchestrators/registration/test_handler_runtime_tick.py
- tests/unit/orchestrators/registration/test_handler_node_introspected.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.py: NEVER useAnytypes in Python code. Always use specific types. UseX | None(PEP 604) syntax instead ofOptional[X]for nullable types.
UseEnumMessageCategory(values: EVENT, COMMAND, INTENT) for message routing, topic parsing, and dispatcher selection. UseEnumNodeOutputType(values: EVENT, COMMAND, INTENT, PROJECTION) for execution shape validation and handler return type validation. PROJECTION exists only in EnumNodeOutputType and is only valid for REDUCER nodes.
UseX | Nonesyntax (PEP 604) for nullable types instead ofOptional[X]. Example:def get_user(id: str) -> User | None:instead ofdef get_user(id: str) -> Optional[User]:
All services MUST useModelONEXContainerfor dependency injection. Bootstrap pattern:container = ModelONEXContainer()followed bywire_infrastructure_services(container)andservice = container.service_registry.resolve_service(ServiceType).
Always propagate correlation_id from incoming requests to error context. Auto-generate usinguuid4()if no correlation_id exists. Use UUID format for all new correlation IDs. Include correlation_id in all error context for distributed tracing.
NEVER include in error messages or context: passwords, API keys, tokens, secrets, full connection strings with credentials, PII (names, emails, SSNs, phone numbers), internal IP addresses (in production logs), private keys or certificates, session tokens or cookies.
SAFE to include in error messages: service names (e.g., 'postgresql', 'kafka'), operation names (e.g., 'connect', 'query'), correlation IDs (always include for tracing), error codes, sanitized hostnames, port numbers, retry counts, timeout values, resource identifiers (non-sensitive).
UseProtocolConfigurationErrorfor config validation failures,SecretResolutionErrorfor secret/credential resolution,InfraConnectionErrorfor connection failures,InfraTimeoutErrorfor operation timeouts,InfraAuthenticationErrorfor auth/authz failures, `InfraUnava...
Files:
tests/unit/handlers/test_handler_http.pytests/helpers/deterministic.pysrc/omnibase_infra/orchestrators/registration/handlers/handler_runtime_tick.pysrc/omnibase_infra/models/dispatch/__init__.pysrc/omnibase_infra/orchestrators/registration/handlers/handler_node_registration_acked.pysrc/omnibase_infra/orchestrators/registration/handlers/handler_node_introspected.pytests/unit/plugins/test_plugin_compute_base.pytests/unit/orchestrators/registration/test_node_registration_orchestrator.py
🧠 Learnings (6)
📓 Common learnings
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T16:32:55.606Z
Learning: ORCHESTRATOR Nodes must inherit from `NodeOrchestrator` or use `NodeOrchestratorService` and must coordinate workflows, manage node interactions, and handle process/event orchestration
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: NodeBridgeOrchestrator MUST support multi-step execution workflow coordination with service routing. Target performance: <50ms standard workflows, <150ms with OnexTree intelligence
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: All ONEX nodes must conform to the canonical structure, code generation, and interface patterns established in the `node_cli` node, using it as the primary source of truth for directory structure, contract schema patterns, linked document architecture, base state patterns, shared schema references, extensibility patterns, CLI interface declarations, code generation, dependency injection, error handling, testing, and documentation
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T16:55:49.755Z
Learning: Applies to agents/**/*.py : Implement ONEX-compliant agent architecture with four node types: Effect (External I/O), Compute (Pure transforms), Reducer (State/persistence), and Orchestrator (Workflow coordination)
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T16:32:55.606Z
Learning: All ONEX nodes must conform to the 4-Node Architecture pattern with clear separation of concerns and unidirectional data flow (EFFECT → COMPUTE → REDUCER → ORCHESTRATOR)
Learnt from: CR
Repo: OmniNode-ai/omniintelligence PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-07T17:50:13.678Z
Learning: Decompose intelligence operations into specialized ONEX nodes following a four-node pattern: Orchestrator (coordinate workflows), Reducer (manage state, FSM transitions), Compute (pure data processing), and Effect (external I/O)
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: Applies to src/omninode_bridge/codegen/**/*.py : Code generation service MUST auto-generate ONEX v2.0 compliant nodes with intelligent mixin injection and quality validation. Generate comprehensive test suites with 90%+ coverage.
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: All ONEX nodes must use the node_kafka_event_bus as a secondary reference only for complex backend and event bus logic and advanced configuration patterns
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/introspection.py : All ONEX nodes must include an `introspection.py` file implementing standards-compliant introspection logic
Applied to files:
src/omnibase_infra/orchestrators/registration/handlers/handler_node_introspected.py
📚 Learning: 2025-12-06T22:21:32.649Z
Learnt from: CR
Repo: OmniNode-ai/omniagent PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T22:21:32.649Z
Learning: Applies to nodes/**/*.py : Use `omnibase_infra` handlers for OmniIntelligence queries via HttpRestAdapter envelope pattern
Applied to files:
src/omnibase_infra/orchestrators/registration/handlers/handler_node_introspected.py
📚 Learning: 2025-11-24T16:32:55.606Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T16:32:55.606Z
Learning: Applies to tests/unit/infrastructure/**/test_*.py : All node implementations must have comprehensive unit tests following the testing pattern in `tests/unit/infrastructure/` with tests for node initialization and node execution
Applied to files:
tests/unit/orchestrators/registration/test_node_registration_orchestrator.py
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/node_tests/**/*.py : All ONEX node tests must be organized in a `node_tests/` directory using scenario-driven testing patterns with fixture-injected tests
Applied to files:
tests/unit/orchestrators/registration/test_node_registration_orchestrator.py
📚 Learning: 2025-11-30T21:55:10.298Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: Applies to tests/bridge_nodes/**/*.py : All Bridge Node implementations MUST include comprehensive test coverage with focus on critical paths (event schemas, entity models). Target: 90%+ coverage for critical components.
Applied to files:
tests/unit/orchestrators/registration/test_node_registration_orchestrator.py
🧬 Code graph analysis (4)
src/omnibase_infra/orchestrators/registration/handlers/handler_runtime_tick.py (4)
src/omnibase_infra/models/projection/model_registration_projection.py (3)
ModelRegistrationProjection(34-326)needs_ack_timeout_event(284-304)needs_liveness_timeout_event(306-326)src/omnibase_infra/models/registration/events/model_node_liveness_expired.py (1)
ModelNodeLivenessExpired(21-93)src/omnibase_infra/models/registration/events/model_node_registration_ack_timed_out.py (1)
ModelNodeRegistrationAckTimedOut(21-93)src/omnibase_infra/projectors/projection_reader_registration.py (3)
ProjectionReaderRegistration(45-655)get_overdue_ack_registrations(381-477)get_overdue_liveness_registrations(479-577)
src/omnibase_infra/models/dispatch/__init__.py (1)
src/omnibase_infra/orchestrators/registration/models/model_orchestrator_context.py (1)
ModelOrchestratorContext(48-110)
src/omnibase_infra/orchestrators/registration/handlers/handler_node_registration_acked.py (6)
src/omnibase_infra/enums/enum_registration_state.py (1)
EnumRegistrationState(24-258)src/omnibase_infra/models/registration/commands/model_node_registration_acked.py (1)
ModelNodeRegistrationAcked(29-99)src/omnibase_infra/models/registration/events/model_node_became_active.py (1)
ModelNodeBecameActive(25-95)src/omnibase_infra/models/registration/events/model_node_registration_ack_received.py (1)
ModelNodeRegistrationAckReceived(21-89)src/omnibase_infra/projectors/projection_reader_registration.py (2)
ProjectionReaderRegistration(45-655)get_entity_state(145-225)src/omnibase_infra/models/projection/model_registration_projection.py (1)
ModelRegistrationProjection(34-326)
tests/unit/orchestrators/registration/test_node_registration_orchestrator.py (4)
tests/unit/orchestrators/registration/test_handler_node_introspected.py (2)
create_mock_projection_reader(46-50)create_projection(53-69)tests/unit/orchestrators/registration/test_handler_node_registration_acked.py (2)
create_mock_projection_reader(53-57)create_projection(60-77)tests/unit/orchestrators/registration/test_handler_runtime_tick.py (2)
create_mock_projection_reader(48-53)create_projection(69-93)tests/helpers/deterministic.py (1)
now(136-147)
🔇 Additional comments (13)
tests/helpers/deterministic.py (1)
128-134: LGTM! Consistent default timestamp update.The updated default time (2025-01-01) aligns with the broader test suite updates in this PR and provides a consistent baseline for deterministic timing tests across orchestrator and handler test modules.
tests/unit/plugins/test_plugin_compute_base.py (1)
308-308: LGTM! Test data aligned with updated deterministic defaults.The timestamp update maintains consistency with the DeterministicClock default now set to 2025-01-01.
tests/unit/handlers/test_handler_http.py (1)
2071-2071: LGTM! Mock response timestamp aligned with DeterministicClock default.The updated timestamp in the mock response body matches the new DeterministicClock default (2025-01-01T00:00:00Z), maintaining consistency across the test suite.
src/omnibase_infra/orchestrators/registration/handlers/handler_node_introspected.py (2)
1-54: Well-structured module with clear documentation.The module docstring clearly documents the decision logic and thread safety guarantees. The use of
frozensetfor state constants is appropriate for immutability.
56-74: State categorization is complete and correct.The retriable states (
LIVENESS_EXPIRED,REJECTED,ACK_TIMED_OUT) and blocking states (PENDING_REGISTRATION,ACCEPTED,AWAITING_ACK,ACK_RECEIVED,ACTIVE) cover allEnumRegistrationStatevalues appropriately for registration initiation decisions.src/omnibase_infra/orchestrators/registration/handlers/handler_runtime_tick.py (2)
1-60: Well-documented handler with clear deduplication strategy.The module docstring clearly explains the detection logic and deduplication approach using projection emission markers. The separation of ack timeout and liveness expiry checks is clean.
188-208: Ack timeout detection logic is correct.The defensive double-check with
needs_ack_timeout_event(now)and explicit type narrowing forack_deadlinehandle edge cases properly. The causation linkage totick.tick_idcorrectly traces timeout events to their trigger.src/omnibase_infra/orchestrators/registration/handlers/handler_node_registration_acked.py (2)
99-112: Good configurable design with sensible defaults.The configurable
liveness_interval_secondswith a 60-second default provides flexibility for different deployment scenarios.
160-234: Comprehensive state decision logic with proper logging.All registration states are handled explicitly with appropriate log levels (debug for expected duplicates, warning for unexpected states). The early return pattern keeps the logic clear.
tests/unit/orchestrators/registration/test_node_registration_orchestrator.py (4)
52-97: Well-structured test fixtures with deterministic time.The
TEST_NOWconstant and helper functions (create_mock_projection_reader,create_projection) provide clean, reusable test setup. The projection factory supports all relevant fields for comprehensive scenario testing.
100-178: G2 acceptance criteria well-tested.The tests verify that the orchestrator emits only events (no I/O) across all three payload types: introspection, runtime tick, and ack command. The mock assertions confirm read-only projection access.
469-547: Convenience method tests provide good coverage.Tests for direct handler access methods (
handle_introspection,handle_runtime_tick,handle_registration_ack) ensure the orchestrator exposes clean APIs for specific payload types without envelope wrapping.
459-466: Verifycorrelation_id=Noneis handled by the orchestrator.The test correctly passes
correlation_id=Noneto verify fallback to envelope's correlation_id. The orchestrator'shandle()method acceptsUUID | None = Noneand properly falls back: first to envelope's correlation_id, then auto-generates a new UUID if both are None (line 174:corr_id = correlation_id or getattr(envelope, "correlation_id", None) or uuid4()).
| "ModelDispatchRoute", | ||
| "ModelDispatcherMetrics", | ||
| "ModelDispatcherRegistration", | ||
| "ModelOrchestratorContext", |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
echo "=== 1. Find ModelOrchestratorContext definitions ==="
fd -e py -x grep -l "class ModelOrchestratorContext" {} \;
echo -e "\n=== 2. Display current dispatch __init__.py around line 126 ==="
if [ -f "src/omnibase_infra/models/dispatch/__init__.py" ]; then
sed -n '120,135p' "src/omnibase_infra/models/dispatch/__init__.py"
fi
echo -e "\n=== 3. Find ModelOrchestratorContext import sources ==="
rg "class ModelOrchestratorContext|from.*ModelOrchestratorContext" -A 5 --type pyRepository: OmniNode-ai/omnibase_infra
Length of output: 1487
🏁 Script executed:
#!/bin/bash
echo "=== 4. Check correlation_id field definitions in both versions ==="
echo "--- Orchestrators version ---"
if [ -f "src/omnibase_infra/orchestrators/registration/models/model_orchestrator_context.py" ]; then
cat "src/omnibase_infra/orchestrators/registration/models/model_orchestrator_context.py"
else
find . -name "model_orchestrator_context.py" -type f 2>/dev/null | head -5 | xargs -I {} sh -c 'echo "File: {}"; cat "{}"'
fi
echo -e "\n--- Dispatch model if it exists ---"
find . -path "*/dispatch*" -name "*orchestrator_context*" -type f 2>/dev/null | head -3 | xargs -I {} sh -c 'echo "File: {}"; cat "{}"'Repository: OmniNode-ai/omnibase_infra
Length of output: 4468
🏁 Script executed:
#!/bin/bash
echo "=== 5. Search for ModelOrchestratorContext usage patterns ==="
rg "ModelOrchestratorContext\(" --type py -A 3 | head -100
echo -e "\n=== 6. Check for correlation_id=None patterns ==="
rg "correlation_id\s*=\s*None" --type py | grep -i orchestrator
echo -e "\n=== 7. Check imports of ModelOrchestratorContext from dispatch ==="
rg "from.*dispatch.*import.*ModelOrchestratorContext|from.*dispatch.*import.*\*" --type pyRepository: OmniNode-ai/omnibase_infra
Length of output: 1814
🏁 Script executed:
#!/bin/bash
echo "=== Inspect test file with correlation_id=None ==="
rg -B 10 -A 10 "correlation_id=None" tests/unit/orchestrators/registration/test_node_registration_orchestrator.py
echo -e "\n=== Check if this is the only occurrence ==="
rg -n "correlation_id=None" --type pyRepository: OmniNode-ai/omnibase_infra
Length of output: 3067
🏁 Script executed:
#!/bin/bash
echo "=== Check dispatch module imports ==="
head -50 src/omnibase_infra/models/dispatch/__init__.py | grep -A 2 -B 2 "ModelOrchestratorContext"
echo -e "\n=== Verify the import statement ==="
grep "ModelOrchestratorContext" src/omnibase_infra/models/dispatch/__init__.pyRepository: OmniNode-ai/omnibase_infra
Length of output: 206
Update code passing correlation_id=None to generate UUID per guidelines.
Re-exporting ModelOrchestratorContext enforces the coding guideline that correlation_id must always be present. The schema requires correlation_id: UUID (non-nullable), but multiple test and production files pass correlation_id=None:
- Test files:
test_node_registration_orchestrator.py:462,test_chain_propagation_validator.py(3 instances),test_registration_reducer.py,test_mixin_async_circuit_breaker_race_conditions.py,test_infra_errors.py,test_dispatch_context_integration.py,test_dispatch_context_enforcer.py(6 instances) - Production code:
mixin_async_circuit_breaker.py(methods withcorrelation_id=Nonedefaults),mixin_node_introspection.py
Per the guideline "Always propagate correlation_id... Auto-generate using uuid4() if no correlation_id exists," generate a UUID when correlation_id is unavailable rather than passing None.
🤖 Prompt for AI Agents
In src/omnibase_infra/models/dispatch/__init__.py around line 126, the exported
ModelOrchestratorContext allows callers to pass correlation_id=None which
violates the non-nullable UUID schema; update the model so correlation_id is
never None by adding a default-generation step (use uuid.uuid4()) when
correlation_id is missing or explicitly None — either change the
dataclass/constructor to set default_factory=uuid.uuid4 or wrap the export with
a small factory that replaces None with uuid4(), and update any method
signatures that default to correlation_id=None (e.g., mixins) to stop
propagating None and instead call the new factory/constructor so a UUID is
auto-generated.
Time Injection Pattern (CRITICAL): - Made emitted_at/timestamp required fields in event models (no default_factory) - Updated handlers to pass explicit emitted_at=now - Fixed mixin_node_introspection.py timestamp injection ModelOrchestratorContext Consolidation (MAJOR): - Removed re-export from models/dispatch/__init__.py - Canonical location: orchestrators/registration/models/ Correlation ID Fix (CRITICAL): - Changed correlation_id=None to correlation_id=uuid4() in introspection mixin Handler Logic Fix (MAJOR): - Fixed last_heartbeat_at fallback to None (semantically correct) Test Improvements (NITPICK): - Updated test dates to 2025 - Fixed ineffective datetime.datetime mock patches - Added emitted_at assertions for time injection verification Type Improvements (NITPICK): - Precise ModelRegistrationProjection type hint - Removed type: ignore with proper type narrowing
Merged origin/main into jonah/omn-c1-registration-orchestrator. Resolved conflicts in: - src/omnibase_infra/validation/infra_validators.py - tests/unit/validation/test_validator_defaults.py Combined threshold history documentation from both branches: - OMN-950: reducer tests (540 unions) - OMN-954: effect idempotency tests PR #78 (544 unions) - OMN-C1: registration orchestrator PR #79 (555 unions)
PR Review: Registration Orchestrator [C1] - First ONEX OrchestratorOverviewThis is an excellent implementation of the first orchestrator node in omnibase_infra. The code demonstrates strong adherence to ONEX principles and establishes solid patterns for future orchestrators. The PR successfully implements C1 from ONEX_RUNTIME_REGISTRATION_TICKET_PLAN.md with 4,482 additions across 60 comprehensive tests. ✅ Strengths1. Architectural Compliance - Exceptional
2. Type Safety - Outstanding
3. Handler Design - Well-Structured
4. Test Coverage - Comprehensive
5. Documentation - Excellent
🔍 Issues IdentifiedCRITICAL IssuesNone identified. All critical architectural constraints are met. MAJOR Issues1. ModelOrchestratorContext Duplication ✅ FIXEDStatus: Fixed in commit 08c5568
MINOR Issues1. Correlation ID Generation in Introspection Mixin ✅ FIXEDStatus: Fixed in commit 87b2f41
2. Test Date Consistency ✅ FIXEDStatus: Fixed in commit 87b2f41
NITPICK Issues1. Union Threshold IncreaseFile: src/omnibase_infra/validation/infra_validators.py Assessment: Acceptable increase
Recommendation: Monitor future union growth. If this continues, consider:
2. Last Heartbeat HandlingFile: handler_runtime_tick.py:261-273 Assessment: Semantically correct
Recommendation: Address in follow-up ticket when heartbeat tracking is implemented 🔒 Security Considerations✅ No Security Issues Identified
🎯 Performance Considerations✅ Efficient Implementation
Potential Optimization (Future)RuntimeTick Handler: Currently processes all overdue entities on each tick
📋 Testing AssessmentTest Quality: ExcellentCoverage:
Test Structure:
Gaps (acceptable for C1, address in integration phase):
🚀 RecommendationsFor This PR: APPROVE ✅This PR is ready to merge. All critical issues have been fixed in subsequent commits. For Follow-Up Work
📊 Code Quality Metrics
🎓 Lessons for Future OrchestratorsThis PR establishes excellent patterns to replicate:
✅ Final VerdictAPPROVE - Excellent Work This PR demonstrates:
Recommendation: Merge after CI passes. This establishes the gold standard pattern for future orchestrators. Reviewed by: Claude Code (ONEX Agent) |
- Replace 5 `type: ignore` comments with proper type narrowing: - mixin_node_introspection.py: Use getattr and assert patterns - inmemory_event_bus.py: Use getattr for model_dump access - runtime_shape_validator.py: Use cast() for return type - handler_consul.py, handler_vault.py: Use model_validate() - Add time injection documentation to event models: - model_node_became_active.py - model_node_liveness_expired.py - model_node_registration_ack_timed_out.py - model_node_registration_rejected.py - Update test dates from 2024 to 2025: - test_plugin_compute_base.py Verified: mypy passes, 505 tests pass for modified components
Code Review: Registration Orchestrator Implementation (C1)OverviewThis PR implements the first orchestrator node in omnibase_infra, establishing critical patterns for the ONEX architecture. The implementation is exemplary and demonstrates deep understanding of ONEX principles. ✅ Strengths1. Architectural Compliance - OUTSTANDING
2. Type Safety - PERFECT
3. Event Model Design - EXCELLENTAll 7 event models follow best practices:
4. Handler Design - CLEAN# HandlerNodeIntrospected: Clear state decision matrix
_RETRIABLE_STATES = frozenset({LIVENESS_EXPIRED, REJECTED, ACK_TIMED_OUT})
_BLOCKING_STATES = frozenset({PENDING_REGISTRATION, ACCEPTED, ...})
5. Test Coverage - COMPREHENSIVE60 unit tests covering:
6. Documentation - THOROUGH
🔍 Observations & Suggestions1. Type Narrowing Pattern (Minor Enhancement Opportunity)In ack_deadline = projection.ack_deadline
if ack_deadline is None:
continueObservation: The defensive None check is good, but could add a structured logging warning since this "shouldn't happen" per the comment. Suggestion (optional): if ack_deadline is None:
logger.warning(
"Unexpected None ack_deadline for overdue projection",
extra={"entity_id": str(projection.entity_id)},
)
continue2. Last Heartbeat Tracking (Known Limitation - Documented)In last_heartbeat_at = None
# TODO: Add last_heartbeat_at field to ModelRegistrationProjectionObservation: Properly documented limitation with clear TODO. This is acceptable for MVP since:
Not blocking - can be addressed in follow-up ticket. 3. Liveness Interval Configuration
Observation: The comment says "should be configurable" but uses a reasonable default. Suggestion: Consider adding to future configuration model, but not blocking for this PR since:
4. Command vs Event Distinction (Well Done)
Observation: Excellent architectural clarity. The distinction between commands (imperative) and events (facts) is properly documented and implemented. 🎯 ONEX Pattern Compliance
🚀 Impact & SignificanceThis PR is architecturally significant because:
The implementation quality is production-ready and serves as an excellent reference for subsequent orchestrator implementations. ✅ Final RecommendationAPPROVE with enthusiasm 🎉 Why approve:
Minor suggestions are non-blocking - they're enhancements for future iterations, not defects. What makes this PR exceptional:
📚 Related Patterns for Future PRsFor teams implementing C2 (Durable Timeout Handling) and subsequent orchestrators:
Excellent work! This establishes a strong foundation for the ONEX runtime registration system. 📋 Checklist Summary
Ship it! 🚢 |
Add structured logging when ack_deadline is unexpectedly None in HandlerRuntimeTick. This defensive check shouldn't trigger in normal operation, but logging helps with debugging if it does occur.
Code Review: Registration Orchestrator [C1] - PR #79Overall Assessment: EXCELLENT ⭐This PR demonstrates outstanding adherence to ONEX standards and serves as an exemplary template for future orchestrator nodes. Approval Status: ✅ Approved with one architectural clarification requested ✅ Strengths1. Perfect Architectural Compliance
2. Exceptional Type Safety
3. Comprehensive Testing
4. Outstanding Documentation
🔍 Issues Identified🚨 isinstance Usage Violates Protocol Resolution PatternLocation: src/omnibase_infra/orchestrators/registration/node_registration_orchestrator.py:180-217 Issue: The orchestrator uses isinstance for payload routing, conflicting with CLAUDE.md guideline: "Protocol Resolution - Duck typing through protocols, never isinstance" Why This Matters:
Recommended Solutions: Option A - Protocol-Based Dispatch (preferred): Use structural typing with Protocol definitions and hasattr checks for duck typing Option B - Document Exception: Add architectural justification (like KafkaEventBus documented exceptions in CLAUDE.md) Action Required: Please clarify approach or provide isinstance rationale.
|
| Requirement | Status | Evidence |
|---|---|---|
| No Any types | ✅ | Uses object for generic payloads |
| No I/O in orchestrator | ✅ | All I/O delegated to projection reader |
| Events-only output | ✅ | All 7 models are events |
| Injected time | ✅ | All handlers use now parameter |
| PEP 604 unions | ✅ | Uses X pipe None throughout |
| Pydantic models | ✅ | Frozen BaseModel everywhere |
| Naming conventions | ✅ | Follows all patterns |
| Correlation ID tracking | ✅ | Propagated through all events |
| Protocol resolution | ❌ | Uses isinstance instead of duck typing |
| Test coverage | ✅ | 52 tests covering G2 criteria |
9/10 requirements met - Only protocol resolution needs clarification.
🚀 Recommendation
APPROVE with isinstance clarification
This is exceptional work establishing the gold standard for ONEX orchestrators. Once isinstance pattern is either refactored to protocol-based dispatch or documented as accepted exception with rationale, this PR will be 100% ONEX compliant.
Reviewed by: Claude Sonnet 4.5 (ONEX Code Review Agent)
Review Date: 2025-12-23
Files Reviewed: 45 files, 4515 additions, 72 deletions
Test Coverage: 52 unit tests passing
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (7)
src/omnibase_infra/handlers/handler_vault.py (1)
186-197: Sanitize ValidationError to prevent token leakage.The current error handling exposes the full
ValidationErrormessage, which can contain actual field values including the sensitivetokenfield. PydanticValidationError.errors()includes aninputkey with the actual value that failed validation.handler_consul.py (lines 261-264) correctly sanitizes this by extracting only field names. Apply the same pattern here to prevent token leakage.
🔎 Proposed fix based on handler_consul.py pattern
except ValidationError as e: ctx = ModelInfraErrorContext( transport_type=EnumInfraTransportType.VAULT, operation="initialize", target_name="vault_adapter", correlation_id=init_correlation_id, namespace=None, # Config not initialized yet ) + # Security: Sanitize validation error to prevent token exposure + sanitized_fields = [err.get("loc", ("unknown",))[-1] for err in e.errors()] raise ProtocolConfigurationError( - f"Invalid Vault configuration: {e}", + f"Invalid Vault configuration - validation failed for fields: {sanitized_fields}", context=ctx, ) from eAs per coding guidelines: "NEVER include in error messages or context: passwords, API keys, tokens, secrets..."
src/omnibase_infra/validation/infra_validators.py (1)
330-346: Clarify "minimal buffer" language - threshold equals baseline.The comment states "minimal buffer for codebase growth" but the threshold (555) equals the baseline (~555), resulting in zero or near-zero buffer. This is misleading and could cause confusion.
Options to resolve:
- If zero buffer is intentional (strict enforcement), update the comment to:
"Threshold: 555 (current baseline, zero buffer - strict mode)"- If some buffer is intended, increase the threshold (e.g., 560 or 565) and update comment accordingly
Impact: Zero buffer means any PR adding even a single union will fail validation immediately, which might be intentional for strict control but should be explicit in documentation.
🔎 Proposed documentation fix (if zero buffer is intentional)
-# Threshold: 555 (current baseline with minimal buffer for codebase growth) +# Threshold: 555 (current baseline, zero buffer - strict enforcement) # Target: Reduce to <200 through dict[str, object] -> JsonValue migration.tests/unit/validation/test_validator_defaults.py (1)
43-60: Test documentation mirrors source file "minimal buffer" inconsistency.The test documentation on line 55 states "minimal buffer" but describes a threshold (555) that equals the baseline (~555), which means zero or near-zero buffer. This mirrors the same documentation issue in the source file.
Recommendation: If the source file documentation is updated per the previous comment, update this test documentation accordingly to maintain consistency.
🔎 Proposed fix (if source uses "zero buffer" language)
- Threshold: 555 (current baseline with minimal buffer) + Threshold: 555 (current baseline, zero buffer - strict enforcement) Target: Reduce to <200 through ongoing dict[str, object] -> JsonValue migration.src/omnibase_infra/models/registration/model_node_introspection_event.py (1)
24-55: Fix docstring examples in two locations to include requiredtimestampThe registration model's
timestampfield is now required (line 138:Field(...)), but two docstring examples don't include it and will fail validation:
- model_node_introspection_event.py lines 45-54: The example constructs
ModelNodeIntrospectionEventwithouttimestamp. Update to:>>> from uuid import uuid4 >>> from datetime import datetime, UTC >>> event = ModelNodeIntrospectionEvent( ... node_id=uuid4(), ... node_type="effect", ... node_version="1.2.3", ... capabilities={"postgres": True, "read": True, "write": True}, ... endpoints={"health": "http://localhost:8080/health"}, ... correlation_id=uuid4(), ... timestamp=datetime.now(UTC), ... )
- registration_reducer.py lines 505-515: The example also omits both
timestampandcorrelation_id. Update to include both required fields:>>> event = ModelNodeIntrospectionEvent( ... node_id=uuid4(), ... node_type="effect", ... node_version="1.0.0", ... endpoints={"health": "http://localhost:8080/health"}, ... correlation_id=uuid4(), ... timestamp=datetime.now(UTC), ... )The test fixtures are properly updated and will not break; this change only affects documentation examples.
tests/unit/models/registration/test_model_node_heartbeat_event.py (1)
3-12: Outdated docstring: remove "Timestamp auto-generation" reference.The module docstring at line 10 mentions "Timestamp auto-generation", but the model now requires explicit timestamp injection (no default_factory). This is inconsistent with the actual behavior being tested.
🔎 Suggested fix
"""Unit tests for ModelNodeHeartbeatEvent. Tests validate: - Required field instantiation - Optional field handling - Non-negative constraint validation for uptime_seconds, active_operations_count, and memory_usage_mb - JSON serialization/deserialization roundtrip -- Timestamp auto-generation +- Timestamp injection (required field, no auto-generation) - Frozen model immutability """src/omnibase_infra/models/registration/model_node_heartbeat_event.py (1)
37-48: Docstring example missing requiredtimestampfield.The example in the docstring omits the now-required
timestampfield. This would cause aValidationErrorif executed.🔎 Suggested fix
Example: >>> from uuid import uuid4 + >>> from datetime import UTC, datetime >>> event = ModelNodeHeartbeatEvent( ... node_id=uuid4(), ... node_type="effect", ... node_version="1.2.3", ... uptime_seconds=3600.5, ... active_operations_count=5, ... memory_usage_mb=256.0, ... cpu_usage_percent=15.5, + ... timestamp=datetime.now(UTC), ... )tests/unit/models/registration/test_model_node_introspection_event.py (1)
3-12: Outdated docstring: remove "Timestamp auto-generation" reference.Line 10 mentions "Timestamp auto-generation", but the model now requires explicit timestamp injection. This is inconsistent with the actual behavior being tested.
🔎 Suggested fix
"""Unit tests for ModelNodeIntrospectionEvent. Tests validate: - Required field instantiation - Optional field handling - Literal node_type validation - JSON serialization/deserialization roundtrip -- Timestamp auto-generation +- Timestamp injection (required field, no auto-generation) - Frozen model immutability """
🧹 Nitpick comments (3)
tests/performance/registration/effect/conftest.py (1)
155-164: Explicit timestamp injection for performance introspection fixture looks correctUsing
timestamp=datetime.now(UTC)here aligns the performance fixture with the new requiredtimestampfield onModelNodeIntrospectionEvent. For perf tests, a real clock is fine; if you ever need strictly repeatable measurements, you could instead inject a shared test clock or constant likeTEST_TIMESTAMP, but that’s optional.tests/unit/registration/effect/conftest.py (1)
261-309: Fixtures now correctly satisfy the requiredtimestampfieldAdding
timestamp=datetime.now(UTC)in bothsample_introspection_eventandcreate_introspection_eventbrings these shared fixtures in line with the updatedModelNodeIntrospectionEventcontract. For these registry‑effect tests a real wall‑clock timestamp is fine; if you later need strict reproducibility, you could switch to a shared constant or injected clock, but it’s not required for correctness here.Also applies to: 383-393
src/omnibase_infra/orchestrators/registration/handlers/handler_runtime_tick.py (1)
196-202: Good defensive coding against unexpected state.The explicit None check for
ack_deadline(lines 196-202) provides a safety net even thoughprojection.needs_ack_timeout_event(now)at line 190 already guaranteesack_deadlineis not None. The defensive warning log helps identify potential projection/query inconsistencies during development and operations.This defensive pattern is acceptable but optional—it guards against "impossible" states that could arise from future code changes or edge cases.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Lite
📒 Files selected for processing (29)
src/omnibase_infra/event_bus/inmemory_event_bus.pysrc/omnibase_infra/handlers/handler_consul.pysrc/omnibase_infra/handlers/handler_vault.pysrc/omnibase_infra/mixins/mixin_node_introspection.pysrc/omnibase_infra/models/registration/commands/model_node_registration_acked.pysrc/omnibase_infra/models/registration/events/model_node_became_active.pysrc/omnibase_infra/models/registration/events/model_node_liveness_expired.pysrc/omnibase_infra/models/registration/events/model_node_registration_accepted.pysrc/omnibase_infra/models/registration/events/model_node_registration_ack_received.pysrc/omnibase_infra/models/registration/events/model_node_registration_ack_timed_out.pysrc/omnibase_infra/models/registration/events/model_node_registration_initiated.pysrc/omnibase_infra/models/registration/events/model_node_registration_rejected.pysrc/omnibase_infra/models/registration/model_node_heartbeat_event.pysrc/omnibase_infra/models/registration/model_node_introspection_event.pysrc/omnibase_infra/orchestrators/registration/handlers/handler_node_registration_acked.pysrc/omnibase_infra/orchestrators/registration/handlers/handler_runtime_tick.pysrc/omnibase_infra/validation/infra_validators.pysrc/omnibase_infra/validation/runtime_shape_validator.pytests/helpers/deterministic.pytests/performance/registration/effect/conftest.pytests/unit/models/registration/test_model_node_heartbeat_event.pytests/unit/models/registration/test_model_node_introspection_event.pytests/unit/nodes/reducers/test_registration_reducer.pytests/unit/orchestrators/registration/test_handler_node_introspected.pytests/unit/orchestrators/registration/test_handler_node_registration_acked.pytests/unit/orchestrators/registration/test_node_registration_orchestrator.pytests/unit/plugins/test_plugin_compute_base.pytests/unit/registration/effect/conftest.pytests/unit/validation/test_validator_defaults.py
🚧 Files skipped from review as they are similar to previous changes (5)
- tests/helpers/deterministic.py
- tests/unit/orchestrators/registration/test_handler_node_introspected.py
- src/omnibase_infra/models/registration/events/model_node_became_active.py
- tests/unit/plugins/test_plugin_compute_base.py
- src/omnibase_infra/models/registration/events/model_node_registration_rejected.py
🧰 Additional context used
📓 Path-based instructions (3)
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.py: NEVER useAnytypes in Python code. Always use specific types. UseX | None(PEP 604) syntax instead ofOptional[X]for nullable types.
UseEnumMessageCategory(values: EVENT, COMMAND, INTENT) for message routing, topic parsing, and dispatcher selection. UseEnumNodeOutputType(values: EVENT, COMMAND, INTENT, PROJECTION) for execution shape validation and handler return type validation. PROJECTION exists only in EnumNodeOutputType and is only valid for REDUCER nodes.
UseX | Nonesyntax (PEP 604) for nullable types instead ofOptional[X]. Example:def get_user(id: str) -> User | None:instead ofdef get_user(id: str) -> Optional[User]:
All services MUST useModelONEXContainerfor dependency injection. Bootstrap pattern:container = ModelONEXContainer()followed bywire_infrastructure_services(container)andservice = container.service_registry.resolve_service(ServiceType).
Always propagate correlation_id from incoming requests to error context. Auto-generate usinguuid4()if no correlation_id exists. Use UUID format for all new correlation IDs. Include correlation_id in all error context for distributed tracing.
NEVER include in error messages or context: passwords, API keys, tokens, secrets, full connection strings with credentials, PII (names, emails, SSNs, phone numbers), internal IP addresses (in production logs), private keys or certificates, session tokens or cookies.
SAFE to include in error messages: service names (e.g., 'postgresql', 'kafka'), operation names (e.g., 'connect', 'query'), correlation IDs (always include for tracing), error codes, sanitized hostnames, port numbers, retry counts, timeout values, resource identifiers (non-sensitive).
UseProtocolConfigurationErrorfor config validation failures,SecretResolutionErrorfor secret/credential resolution,InfraConnectionErrorfor connection failures,InfraTimeoutErrorfor operation timeouts,InfraAuthenticationErrorfor auth/authz failures, `InfraUnava...
Files:
tests/unit/orchestrators/registration/test_handler_node_registration_acked.pytests/unit/nodes/reducers/test_registration_reducer.pysrc/omnibase_infra/event_bus/inmemory_event_bus.pysrc/omnibase_infra/models/registration/events/model_node_liveness_expired.pysrc/omnibase_infra/models/registration/events/model_node_registration_ack_timed_out.pysrc/omnibase_infra/models/registration/events/model_node_registration_accepted.pytests/unit/validation/test_validator_defaults.pysrc/omnibase_infra/models/registration/model_node_introspection_event.pytests/performance/registration/effect/conftest.pysrc/omnibase_infra/handlers/handler_vault.pytests/unit/models/registration/test_model_node_introspection_event.pysrc/omnibase_infra/orchestrators/registration/handlers/handler_node_registration_acked.pysrc/omnibase_infra/models/registration/events/model_node_registration_initiated.pysrc/omnibase_infra/validation/runtime_shape_validator.pysrc/omnibase_infra/models/registration/commands/model_node_registration_acked.pysrc/omnibase_infra/handlers/handler_consul.pytests/unit/models/registration/test_model_node_heartbeat_event.pytests/unit/registration/effect/conftest.pysrc/omnibase_infra/orchestrators/registration/handlers/handler_runtime_tick.pytests/unit/orchestrators/registration/test_node_registration_orchestrator.pysrc/omnibase_infra/models/registration/model_node_heartbeat_event.pysrc/omnibase_infra/mixins/mixin_node_introspection.pysrc/omnibase_infra/models/registration/events/model_node_registration_ack_received.pysrc/omnibase_infra/validation/infra_validators.py
**/model_*.py
📄 CodeRabbit inference engine (CLAUDE.md)
All data structures must be proper Pydantic models. One model per file named as
model_<name>.pywith class patternModel<Name>. Files must contain exactly oneModel*class.
Files:
src/omnibase_infra/models/registration/events/model_node_liveness_expired.pysrc/omnibase_infra/models/registration/events/model_node_registration_ack_timed_out.pysrc/omnibase_infra/models/registration/events/model_node_registration_accepted.pysrc/omnibase_infra/models/registration/model_node_introspection_event.pysrc/omnibase_infra/models/registration/events/model_node_registration_initiated.pysrc/omnibase_infra/models/registration/commands/model_node_registration_acked.pysrc/omnibase_infra/models/registration/model_node_heartbeat_event.pysrc/omnibase_infra/models/registration/events/model_node_registration_ack_received.py
**/mixin_*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Mixin files must follow naming pattern
mixin_<name>.pywith class patternMixin<Name>. Files must contain exactly oneMixin*class.
Files:
src/omnibase_infra/mixins/mixin_node_introspection.py
🧠 Learnings (27)
📓 Common learnings
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T16:55:49.755Z
Learning: Applies to agents/**/*.py : Implement ONEX-compliant agent architecture with four node types: Effect (External I/O), Compute (Pure transforms), Reducer (State/persistence), and Orchestrator (Workflow coordination)
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: All ONEX nodes must conform to the canonical structure, code generation, and interface patterns established in the `node_cli` node, using it as the primary source of truth for directory structure, contract schema patterns, linked document architecture, base state patterns, shared schema references, extensibility patterns, CLI interface declarations, code generation, dependency injection, error handling, testing, and documentation
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T16:32:55.606Z
Learning: All ONEX nodes must conform to the 4-Node Architecture pattern with clear separation of concerns and unidirectional data flow (EFFECT → COMPUTE → REDUCER → ORCHESTRATOR)
Learnt from: CR
Repo: OmniNode-ai/omniintelligence PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-07T17:50:13.678Z
Learning: Decompose intelligence operations into specialized ONEX nodes following a four-node pattern: Orchestrator (coordinate workflows), Reducer (manage state, FSM transitions), Compute (pure data processing), and Effect (external I/O)
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/*.py : All ONEX node implementations must follow dependency injection and protocol-first design patterns as established in the node_cli canonical reference
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: Applies to src/omninode_bridge/codegen/**/*.py : Code generation service MUST auto-generate ONEX v2.0 compliant nodes with intelligent mixin injection and quality validation. Generate comprehensive test suites with 90%+ coverage.
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: NodeBridgeOrchestrator MUST support multi-step execution workflow coordination with service routing. Target performance: <50ms standard workflows, <150ms with OnexTree intelligence
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: All ONEX nodes must use the node_kafka_event_bus as a secondary reference only for complex backend and event bus logic and advanced configuration patterns
📚 Learning: 2025-11-24T16:32:55.606Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T16:32:55.606Z
Learning: Applies to tests/unit/infrastructure/**/test_*.py : All node implementations must have comprehensive unit tests following the testing pattern in `tests/unit/infrastructure/` with tests for node initialization and node execution
Applied to files:
tests/unit/orchestrators/registration/test_handler_node_registration_acked.pytests/unit/models/registration/test_model_node_introspection_event.pytests/unit/orchestrators/registration/test_node_registration_orchestrator.py
📚 Learning: 2025-12-22T00:11:20.308Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-22T00:11:20.308Z
Learning: Applies to **/*dispatcher*.py : Use `ModelEventEnvelope[object]` instead of `Any` for generic dispatchers that must accept envelopes with any payload type. Use specific type parameters (e.g., `ModelEventEnvelope[UserCreatedEvent]`) when the dispatcher knows the exact payload type.
Applied to files:
src/omnibase_infra/event_bus/inmemory_event_bus.py
📚 Learning: 2025-12-06T22:21:32.649Z
Learnt from: CR
Repo: OmniNode-ai/omniagent PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T22:21:32.649Z
Learning: Applies to nodes/**/*.py : Use event bus mixins from `omnibase_core` for Kafka publishing instead of direct Kafka clients
Applied to files:
src/omnibase_infra/event_bus/inmemory_event_bus.pysrc/omnibase_infra/mixins/mixin_node_introspection.py
📚 Learning: 2025-12-06T22:21:32.649Z
Learnt from: CR
Repo: OmniNode-ai/omniagent PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T22:21:32.649Z
Learning: Applies to nodes/effect/**/*.py : Use handler envelopes from `omnibase_infra` for all I/O operations (HTTP, database, Kafka) instead of custom clients
Applied to files:
src/omnibase_infra/event_bus/inmemory_event_bus.py
📚 Learning: 2025-11-24T16:32:55.606Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T16:32:55.606Z
Learning: Node communication must use event-driven patterns through `ModelEventEnvelope` from `omnibase_core.models.events.model_event_envelope`
Applied to files:
src/omnibase_infra/event_bus/inmemory_event_bus.pysrc/omnibase_infra/models/registration/events/model_node_registration_accepted.pysrc/omnibase_infra/models/registration/events/model_node_registration_initiated.py
📚 Learning: 2025-11-30T21:55:10.298Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: Applies to src/omninode_bridge/nodes/**/{models,node}.py : Bridge nodes MUST implement FSM states: PENDING, PROCESSING, COMPLETED, FAILED. Use Pydantic v2 models with proper state enum validation
Applied to files:
src/omnibase_infra/models/registration/events/model_node_registration_ack_timed_out.pysrc/omnibase_infra/models/registration/events/model_node_registration_accepted.py
📚 Learning: 2025-11-28T18:58:53.781Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/canonical_patterns.mdc:0-0
Timestamp: 2025-11-28T18:58:53.781Z
Learning: Applies to **/*.py : Implement Node classes by inheriting from `NodeBase` with proper UUID and `ModelSemVer` fields
Applied to files:
src/omnibase_infra/models/registration/events/model_node_registration_accepted.pysrc/omnibase_infra/models/registration/commands/model_node_registration_acked.pysrc/omnibase_infra/models/registration/events/model_node_registration_ack_received.py
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/models/model_contract_*.py : All ONEX node auto-generated Pydantic models must be organized in a `models/` directory with files for state.py, model_contract_actions.py, model_contract_models.py, model_contract_validation.py, model_contract_cli.py (optional), model_contract_capabilities.py (optional), and error_codes.py, generated from the corresponding contract definitions
Applied to files:
src/omnibase_infra/models/registration/events/model_node_registration_accepted.pysrc/omnibase_infra/models/registration/commands/model_node_registration_acked.py
📚 Learning: 2025-12-22T00:11:20.308Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-22T00:11:20.308Z
Learning: Applies to **/node.py : All ONEX node base classes and I/O models come from `omnibase_core.nodes`: NodeEffect, NodeCompute, NodeReducer, NodeOrchestrator, ModelEffectInput, ModelEffectOutput, ModelComputeInput, ModelComputeOutput, ModelReducerInput, ModelReducerOutput, ModelOrchestratorInput, ModelOrchestratorOutput. Never define new node archetypes in infra.
Applied to files:
src/omnibase_infra/models/registration/events/model_node_registration_accepted.pysrc/omnibase_infra/models/registration/events/model_node_registration_initiated.py
📚 Learning: 2025-11-30T21:55:10.298Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: Applies to src/omninode_bridge/nodes/**/*.py : All nodes in omninode_bridge MUST use omnibase_core standards (ModelServiceEffect, ModelServiceCompute for effect/compute nodes; NodeOrchestrator, NodeReducer with mixins for orchestrator/reducer nodes)
Applied to files:
src/omnibase_infra/models/registration/events/model_node_registration_accepted.pysrc/omnibase_infra/mixins/mixin_node_introspection.py
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/models/error_codes.py : All ONEX node error handling must use auto-generated error codes defined in `models/error_codes.py` from contract definitions
Applied to files:
src/omnibase_infra/models/registration/events/model_node_registration_accepted.py
📚 Learning: 2025-12-20T04:09:41.832Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-20T04:09:41.832Z
Learning: Applies to **/*.py : Use PEP 604 union syntax (str | None) instead of Optional or Union types
Applied to files:
tests/unit/validation/test_validator_defaults.py
📚 Learning: 2025-11-28T18:58:53.781Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/canonical_patterns.mdc:0-0
Timestamp: 2025-11-28T18:58:53.781Z
Learning: Applies to **/*.py : Use proper union type definitions and discriminated unions where appropriate
Applied to files:
tests/unit/validation/test_validator_defaults.py
📚 Learning: 2025-11-29T22:07:25.230Z
Learnt from: CR
Repo: OmniNode-ai/omniintelligence PR: 0
File: migration_sources/omniarchon/CLAUDE.md:0-0
Timestamp: 2025-11-29T22:07:25.230Z
Learning: Applies to migration_sources/omniarchon/**/*.py : All configuration classes using Pydantic must validate that no hardcoded secrets or sensitive defaults exist. Use Field(..., description=...) for all parameters. Generate comprehensive .env.example templates documenting all variables with descriptions.
Applied to files:
src/omnibase_infra/handlers/handler_vault.py
📚 Learning: 2025-11-29T22:07:25.230Z
Learnt from: CR
Repo: OmniNode-ai/omniintelligence PR: 0
File: migration_sources/omniarchon/CLAUDE.md:0-0
Timestamp: 2025-11-29T22:07:25.230Z
Learning: Applies to migration_sources/omniarchon/**/*.py : Use Pydantic Settings (BaseSettings with Field annotation and env parameter) for configuration management instead of direct os.getenv() calls when building configuration classes.
Applied to files:
src/omnibase_infra/handlers/handler_vault.py
📚 Learning: 2025-11-24T16:33:51.604Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-24T16:33:51.604Z
Learning: Applies to tests/unit/models/**/test_model_*.py : Model tests must achieve 100% coverage and test instantiation, inheritance, serialization, deserialization, JSON serialization, roundtrip serialization, equality, hashing, string representation, repr, attributes, validation, metadata, data creation, copying, and immutability
Applied to files:
tests/unit/models/registration/test_model_node_introspection_event.py
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/node_tests/**/*.py : All ONEX node tests must be organized in a `node_tests/` directory using scenario-driven testing patterns with fixture-injected tests
Applied to files:
tests/unit/models/registration/test_model_node_introspection_event.pytests/unit/orchestrators/registration/test_node_registration_orchestrator.py
📚 Learning: 2025-12-20T04:09:41.832Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-20T04:09:41.832Z
Learning: Applies to **/*.py : Use EnumNodeKind for architectural role classification (EFFECT, COMPUTE, REDUCER, ORCHESTRATOR, RUNTIME_HOST) and EnumNodeType for implementation type discovery
Applied to files:
tests/unit/models/registration/test_model_node_introspection_event.py
📚 Learning: 2025-11-24T17:22:32.195Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/canonical_patterns.mdc:0-0
Timestamp: 2025-11-24T17:22:32.195Z
Learning: Applies to **/protocols/protocol_*.py : All Protocol definitions must use model-only signatures: methods accept only validated Pydantic models, never dict, primitives, or argument models
Applied to files:
src/omnibase_infra/handlers/handler_consul.py
📚 Learning: 2025-11-30T21:55:10.298Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: Applies to tests/bridge_nodes/**/*.py : All Bridge Node implementations MUST include comprehensive test coverage with focus on critical paths (event schemas, entity models). Target: 90%+ coverage for critical components.
Applied to files:
tests/unit/orchestrators/registration/test_node_registration_orchestrator.py
📚 Learning: 2025-11-30T21:55:10.298Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: Applies to src/omninode_bridge/codegen/**/*.py : Code generation service MUST auto-generate ONEX v2.0 compliant nodes with intelligent mixin injection and quality validation. Generate comprehensive test suites with 90%+ coverage.
Applied to files:
tests/unit/orchestrators/registration/test_node_registration_orchestrator.py
📚 Learning: 2025-12-03T16:55:49.755Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T16:55:49.755Z
Learning: Applies to **/*.py : Use type-safe configuration via Pydantic Settings from config/settings.py with 90+ type-safe variables organized into External Service Discovery, Shared Infrastructure, AI Provider API Keys, Local Services, and Feature Flags
Applied to files:
src/omnibase_infra/models/registration/model_node_heartbeat_event.py
📚 Learning: 2025-11-30T21:55:10.298Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: Applies to src/omninode_bridge/nodes/**/*.py : Import mixins from omnibase_core.mixins.* and use Mixin* naming pattern (e.g., MixinHealthCheck, MixinMetrics, MixinEventBus) - never use local custom mixins unless experimental and documented
Applied to files:
src/omnibase_infra/mixins/mixin_node_introspection.py
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/introspection.py : All ONEX nodes must include an `introspection.py` file implementing standards-compliant introspection logic
Applied to files:
src/omnibase_infra/mixins/mixin_node_introspection.py
📚 Learning: 2025-11-24T16:32:55.606Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T16:32:55.606Z
Learning: Node implementations must use mixin-based composition from `omnibase_core.mixins` (e.g., `MixinHealthCheck`, `MixinNodeExecutor`) to add capabilities
Applied to files:
src/omnibase_infra/mixins/mixin_node_introspection.py
📚 Learning: 2025-12-03T16:55:49.755Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T16:55:49.755Z
Learning: Applies to **/*.py : Publish intelligence requests to Kafka event bus using topics: dev.archon-intelligence.intelligence.code-analysis-{requested,completed,failed}.v1 for consistency and event-driven architecture
Applied to files:
src/omnibase_infra/mixins/mixin_node_introspection.py
🧬 Code graph analysis (14)
tests/unit/orchestrators/registration/test_handler_node_registration_acked.py (8)
src/omnibase_infra/enums/enum_registration_state.py (1)
EnumRegistrationState(24-258)src/omnibase_infra/models/projection/model_registration_projection.py (1)
ModelRegistrationProjection(34-326)src/omnibase_infra/models/registration/model_node_capabilities.py (1)
ModelNodeCapabilities(13-167)src/omnibase_infra/models/registration/commands/model_node_registration_acked.py (1)
ModelNodeRegistrationAcked(29-99)src/omnibase_infra/models/registration/events/model_node_became_active.py (1)
ModelNodeBecameActive(25-95)src/omnibase_infra/models/registration/events/model_node_registration_ack_received.py (1)
ModelNodeRegistrationAckReceived(21-89)src/omnibase_infra/orchestrators/registration/handlers/handler_node_registration_acked.py (1)
handle(117-237)src/omnibase_infra/projectors/projection_reader_registration.py (1)
get_entity_state(145-225)
src/omnibase_infra/models/registration/events/model_node_registration_accepted.py (2)
tests/performance/registration/effect/conftest.py (1)
correlation_id(133-139)tests/unit/registration/effect/conftest.py (1)
correlation_id(242-248)
src/omnibase_infra/handlers/handler_vault.py (1)
src/omnibase_infra/handlers/model_vault_adapter_config.py (1)
ModelVaultAdapterConfig(21-143)
tests/unit/models/registration/test_model_node_introspection_event.py (2)
src/omnibase_infra/models/registration/model_node_introspection_event.py (1)
ModelNodeIntrospectionEvent(24-141)tests/unit/models/registration/test_model_node_heartbeat_event.py (1)
test_timestamp_is_required(590-604)
src/omnibase_infra/orchestrators/registration/handlers/handler_node_registration_acked.py (3)
src/omnibase_infra/enums/enum_registration_state.py (1)
EnumRegistrationState(24-258)src/omnibase_infra/models/projection/model_registration_projection.py (1)
ModelRegistrationProjection(34-326)src/omnibase_infra/projectors/projection_reader_registration.py (2)
ProjectionReaderRegistration(45-655)get_entity_state(145-225)
src/omnibase_infra/models/registration/events/model_node_registration_initiated.py (2)
tests/performance/registration/effect/conftest.py (1)
correlation_id(133-139)tests/unit/registration/effect/conftest.py (1)
correlation_id(242-248)
src/omnibase_infra/models/registration/commands/model_node_registration_acked.py (2)
tests/performance/registration/effect/conftest.py (1)
correlation_id(133-139)tests/unit/registration/effect/conftest.py (1)
correlation_id(242-248)
src/omnibase_infra/handlers/handler_consul.py (2)
src/omnibase_infra/handlers/model_consul_handler_config.py (1)
ModelConsulHandlerConfig(23-148)src/omnibase_infra/event_bus/kafka_event_bus.py (1)
config(448-454)
tests/unit/models/registration/test_model_node_heartbeat_event.py (2)
tests/unit/models/registration/test_model_node_introspection_event.py (1)
test_timestamp_is_required(354-368)src/omnibase_infra/models/registration/model_node_heartbeat_event.py (1)
ModelNodeHeartbeatEvent(19-94)
tests/unit/registration/effect/conftest.py (1)
tests/helpers/deterministic.py (1)
now(136-147)
src/omnibase_infra/orchestrators/registration/handlers/handler_runtime_tick.py (4)
src/omnibase_infra/models/projection/model_registration_projection.py (3)
ModelRegistrationProjection(34-326)needs_ack_timeout_event(284-304)needs_liveness_timeout_event(306-326)src/omnibase_infra/models/registration/events/model_node_liveness_expired.py (1)
ModelNodeLivenessExpired(21-93)src/omnibase_infra/models/registration/events/model_node_registration_ack_timed_out.py (1)
ModelNodeRegistrationAckTimedOut(21-93)src/omnibase_infra/projectors/projection_reader_registration.py (2)
get_overdue_ack_registrations(381-477)get_overdue_liveness_registrations(479-577)
tests/unit/orchestrators/registration/test_node_registration_orchestrator.py (4)
src/omnibase_infra/enums/enum_registration_state.py (1)
EnumRegistrationState(24-258)src/omnibase_infra/models/registration/events/model_node_registration_ack_received.py (1)
ModelNodeRegistrationAckReceived(21-89)src/omnibase_infra/models/registration/events/model_node_registration_initiated.py (1)
ModelNodeRegistrationInitiated(22-91)src/omnibase_infra/orchestrators/registration/node_registration_orchestrator.py (4)
handle(134-223)handle_introspection(225-250)handle_runtime_tick(252-279)handle_registration_ack(281-307)
src/omnibase_infra/mixins/mixin_node_introspection.py (4)
src/omnibase_infra/event_bus/inmemory_event_bus.py (2)
publish_envelope(351-392)publish(243-349)src/omnibase_infra/mixins/protocol_event_bus_like.py (2)
publish_envelope(26-37)publish(39-52)tests/performance/registration/effect/conftest.py (1)
correlation_id(133-139)tests/unit/registration/effect/conftest.py (1)
correlation_id(242-248)
src/omnibase_infra/models/registration/events/model_node_registration_ack_received.py (2)
tests/performance/registration/effect/conftest.py (1)
correlation_id(133-139)tests/unit/registration/effect/conftest.py (1)
correlation_id(242-248)
🔇 Additional comments (22)
src/omnibase_infra/validation/runtime_shape_validator.py (2)
156-156: LGTM: Clean import for type casting.The addition of
castto the typing imports is appropriate and necessary for the type hint at line 859. Follows coding guidelines for explicit type usage.
857-859: LGTM: Proper type cast for decorator return.The explicit
cast(F, wrapper)correctly addresses mypy's inability to verify thatfunctools.wrapspreserves the signature type. This is a standard pattern for decorator typing in Python and has no runtime impact—the cast is purely for static type checking.The inline comment effectively explains the rationale for the cast.
src/omnibase_infra/handlers/handler_vault.py (1)
184-185: LGTM! Correct Pydantic v2 validation pattern.The change from
**configexpansion tomodel_validate(config)is the recommended Pydantic v2 approach for type-safe dict validation. This is consistent with the pattern used inhandler_consul.py(lines 248-249).src/omnibase_infra/handlers/handler_consul.py (1)
248-249: LGTM! Correct Pydantic v2 validation with proper error sanitization.The change to
model_validate(config)is the recommended Pydantic v2 approach. Excellent security practice with theValidationErrorsanitization (lines 261-264) that extracts only field names without exposing sensitive token values.This sanitization pattern should be applied to
handler_vault.pyas well (see my comment there).Also applies to: 257-265
src/omnibase_infra/models/registration/events/model_node_liveness_expired.py (1)
21-93: Liveness expiry event model matches the described C2 semanticsThe
ModelNodeLivenessExpireddefinition (frozen model, extra forbidden, explicitemitted_atandlast_heartbeat_atinjection) cleanly reflects the documented behavior: one event per timeout occurrence, causation linking to the RuntimeTick, and nullablelast_heartbeat_atfor “never received” cases. No changes needed here.src/omnibase_infra/event_bus/inmemory_event_bus.py (1)
365-383: Boundmodel_dump/dictusage inpublish_envelopeis behavior‑preservingRefactoring to capture
envelope.model_dump/envelope.dictinto local variables before calling them keeps the serialization semantics identical while making the intent clearer and slightly friendlier to type checkers. The fallback paths for dict and generic JSON‑serializable objects are unchanged. Looks good.tests/unit/models/registration/test_model_node_heartbeat_event.py (1)
24-26: Well-implemented time injection pattern with comprehensive test coverage.The deterministic
TEST_TIMESTAMPconstant and thetest_timestamp_is_requiredtest properly validate the ONEX time injection pattern. The test correctly verifies that omittingtimestampraises aValidationError, ensuring the model enforces explicit time injection for testability.Also applies to: 587-604
src/omnibase_infra/models/registration/events/model_node_registration_initiated.py (1)
55-94: LGTM!The model structure follows ONEX patterns correctly:
- Frozen immutability for event safety
- Required fields with explicit
Field(...)- no defaults for required data- Time injection pattern enforced (no
default_factoryforemitted_at)- Proper
__all__exportsrc/omnibase_infra/models/registration/model_node_heartbeat_event.py (1)
93-94: LGTM!The timestamp field correctly enforces explicit injection with
Field(...)and nodefault_factory. The inline comment clearly documents the testability rationale.tests/unit/models/registration/test_model_node_introspection_event.py (1)
28-30: LGTM!The time injection pattern is properly implemented and tested. The
test_timestamp_is_requiredtest correctly validates that omitting the timestamp raises aValidationError, consistent with the pattern in the heartbeat event tests.Also applies to: 351-368
src/omnibase_infra/models/registration/events/model_node_registration_ack_received.py (1)
53-92: LGTM!The model correctly implements the ONEX event pattern with:
- Frozen immutability
- Required time injection for
emitted_at- Semantic
liveness_deadlinefield for heartbeat monitoring- Proper
__all__exporttests/unit/orchestrators/registration/test_handler_node_registration_acked.py (3)
1-50: LGTM!Comprehensive test module with:
- Clear G2 acceptance criteria mapping in docstring
- Deterministic
TEST_NOWfor time injection testing- Well-documented test structure covering key FSM states and edge cases
92-155: Well-structured test with proper time injection verification.The test correctly validates:
- Two events emitted (AckReceived + BecameActive) in correct order
emitted_atequals injectednow(lines 139, 154)liveness_deadlinecalculated from injected time- Causation linking via
command_id- Capabilities propagation from projection
288-323: LGTM!Efficient use of
pytest.mark.parametrizeto test all terminal states without code duplication. The assertion message at line 323 includes the state name for clear failure diagnostics.src/omnibase_infra/models/registration/commands/model_node_registration_acked.py (1)
68-102: LGTM!The command model is well-designed:
command_idwithdefault_factory=uuid4is appropriate for command identification- Required
timestampwith no default enforces time injection- Excellent docstring explaining command vs event semantics and orchestrator processing flow
- Proper
__all__exportsrc/omnibase_infra/models/registration/events/model_node_registration_ack_timed_out.py (1)
21-96: LGTM!Excellent event model implementation:
- Complete docstring example with all required fields
- Clear semantics for
emitted_at(detection time) vsdeadline_at(original deadline)- Detailed documentation of event semantics, deduplication markers, and FSM impact
- Proper
__all__export with explicit type annotationsrc/omnibase_infra/mixins/mixin_node_introspection.py (3)
333-351: LGTM! Type narrowing pattern for mypy.The local
event_busvariable with the explicit assert provides type narrowing for mypy, eliminating the need fortype: ignorecomments. While the assert is technically redundant (the None check at line 1308 already handles this), it helps the type checker understand the non-None guarantee in both publish paths.
418-453: LGTM! Explicit time injection for heartbeat events.The changes introduce explicit time injection via
now = datetime.now(UTC)and pass it astimestamp=nowto the heartbeat event. This aligns with the PR's time injection pattern and ensures testability. The type narrowing pattern forevent_busis consistent withpublish_introspection.
1654-1660: LGTM! Correlation ID generation fix.Generating
correlation_id=uuid4()when the request message lacks a value ensures non-null correlation IDs are propagated, aligning with the coding guideline to auto-generate usinguuid4()when no correlation_id exists.src/omnibase_infra/orchestrators/registration/handlers/handler_node_registration_acked.py (1)
264-293: LGTM! Time injection pattern correctly implemented.Both
ModelNodeRegistrationAckReceived(line 270) andModelNodeBecameActive(line 280) now explicitly passemitted_at=now, ensuring consistent time injection across both events. This addresses the past review comment requestingemitted_at=nowfor time injection consistency.The liveness deadline is also correctly computed from the injected
nowparameter (line 262), and both events properly link to the command viacausation_id=command.command_id.tests/unit/orchestrators/registration/test_node_registration_orchestrator.py (1)
1-553: LGTM! Comprehensive test suite for NodeRegistrationOrchestrator.This test suite thoroughly validates the orchestrator's core requirements:
- G2 Requirement: Events-only output - Tests confirm no I/O operations beyond read-only projection queries (lines 104-216).
- G2 Requirement: Injected time - Tests verify
nowparameter is passed through to all handlers and used for deadline calculations (lines 222-307).- Routing validation - Tests confirm correct handler dispatch for introspection, runtime tick, and ack payloads (lines 313-414).
- Correlation ID handling - Tests verify proper propagation and fallback behavior (lines 420-471).
The use of
TEST_NOW(line 53) ensures deterministic, reproducible test execution. The mock-based approach effectively validates that the orchestrator performs only read-only projection queries.src/omnibase_infra/orchestrators/registration/handlers/handler_runtime_tick.py (1)
265-285: LGTM! Correct semantic handling of last_heartbeat_at.Setting
last_heartbeat_at = None(line 277) correctly addresses the past review comment. The extensive comment block (lines 265-277) clearly explains the semantic reasoning:
- Using
nowwould incorrectly imply a recent heartbeat- Using
registered_atwould conflate registration with heartbeat receipt- Using
Noneaccurately indicates heartbeat timestamp data is not trackedThe TODO comment documents the future projection schema enhancement, preventing confusion about why None is used here.
Complete Phase 9 (Documentation & Testing) for event bus integration: Documentation: - EVENT_BUS_INTEGRATION_GUIDE.md: Comprehensive developer guide with quick start, configuration reference, pub/sub patterns, error handling, circuit breaker usage, correlation ID tracking, and troubleshooting - MVP_EVENT_CATALOG.md: Event schema catalog with message categories, topic naming conventions, header schema, and example events - EVENT_BUS_OPERATIONS_RUNBOOK.md: Operational runbook with deployment checklist, monitoring, DLQ handling, and disaster recovery - EVENT_BUS_COVERAGE_REPORT.md: Validation report confirming feature completeness and test coverage Performance Tests (31 tests): - Throughput benchmarks (target: >1000 events/sec) - Latency measurements (p50, p95, p99 percentiles) - Sustained load and memory stability tests Integration Tests (83 tests): - Event schema validation (30 tests) - Correlation ID tracking (19 tests) - End-to-end dispatch flow (34 tests) All 114 new tests pass.
Code Review: Registration Orchestrator [C1] - OMN-888I've completed a thorough review of PR #79 implementing the first orchestrator node in omnibase_infra. This is excellent work that establishes critical patterns for the ONEX runtime. Below are my findings organized by category. ✅ Strengths1. Architectural Compliance - Excellent
2. Code Quality - Outstanding
3. Test Coverage - Exemplary
4. Documentation - Exceptional
5. ONEX Pattern Adherence - Perfect
🎯 Code Quality HighlightsTime Injection Pattern (Critical Fix Applied)The PR correctly implements time injection with required # CORRECT - Event models require explicit time injection
class ModelNodeBecameActive(BaseModel):
emitted_at: datetime = Field(...) # Required, no default_factory
# CORRECT - Handlers pass explicit emitted_at=now
event = ModelNodeBecameActive(
entity_id=projection.entity_id,
emitted_at=now, # Injected from context
...
)This ensures deterministic testing and time-travel debugging capabilities. Type Safety Without
|
…t fixtures Fix CI failures in TestBoundaryConditions where ModelNodeIntrospectionEvent was missing the required timestamp field. The model requires explicit timestamp injection (no default_factory) for testability. Added timestamp=TEST_TIMESTAMP to 7 test cases: - test_max_uuid_values - test_min_uuid_values - test_minimal_valid_version - test_very_long_endpoint_url - test_special_characters_in_metadata - test_maximum_intent_payload_size - test_uuid_version_variations Fixes PR #79 CI failures.
Pull Request Review: Registration Orchestrator [C1]Overall Assessment: ✅ APPROVED - This is an excellent implementation that sets a strong foundation for the ONEX orchestrator pattern. The code quality is exceptional, architectural compliance is rigorous, and the test coverage is comprehensive. 🎯 Strengths1. Exemplary Architectural Compliance
2. Excellent Code Organization
3. Comprehensive Documentation
4. Robust Test Coverage
5. First-Class PatternsThis is the first orchestrator node in omnibase_infra and establishes excellent patterns:
🔍 Code Quality ObservationsType Safety Excellence# Perfect nullable type usage (PEP 604)
correlation_id: UUID | None = Field(default=None)
# No Any types anywhere in the orchestrator code ✅
# Proper BaseModel return types from handlers ✅Time Injection Pattern# Handlers always use injected time
async def handle(
self,
event: ModelNodeIntrospectionEvent,
now: datetime, # Injected, never datetime.now()
correlation_id: UUID,
) -> list[BaseModel]:
# Use now for all decisions
initiated_event = ModelNodeRegistrationInitiated(
emitted_at=now, # ✅ Uses injected time
...
)State Machine Clarity# Clear frozensets for state categories
_RETRIABLE_STATES: frozenset[EnumRegistrationState] = frozenset({
EnumRegistrationState.LIVENESS_EXPIRED,
EnumRegistrationState.REJECTED,
EnumRegistrationState.ACK_TIMED_OUT,
})
_BLOCKING_STATES: frozenset[EnumRegistrationState] = frozenset({
EnumRegistrationState.PENDING_REGISTRATION,
EnumRegistrationState.ACCEPTED,
EnumRegistrationState.AWAITING_ACK,
EnumRegistrationState.ACK_RECEIVED,
EnumRegistrationState.ACTIVE,
})Proper Event vs Command DistinctionThe PR correctly distinguishes between commands (imperative requests) and events (facts):
📊 Test Coverage AnalysisUnit Tests (60 total)
Integration Tests
Performance Tests
🎨 Architecture HighlightsClean Handler SeparationEvent FlowProjection Integration
🔒 Security & CorrectnessError Handling
Idempotency
Correlation Tracking
📝 Minor Observations (Non-Blocking)1. Liveness Interval Hardcoded# handler_node_registration_acked.py:65
_DEFAULT_LIVENESS_INTERVAL_SECONDS: int = 60Observation: The comment notes "This should be configurable". This is fine for the MVP, but consider making this configurable via container or config model in a future ticket. Impact: Low - default is reasonable, handlers accept it as constructor param for testing 2. Validation Baseline UpdateThe PR bumps Rationale (from code):
✅ This follows ONEX guidelines for nullable types using PEP 604 syntax. 3. Event Model Timestamp HandlingEvent models correctly require explicit # Timestamps - MUST be explicitly injected (no default_factory for testability)
emitted_at: datetime = Field(
...,
description="Timestamp when the orchestrator emitted this event (UTC)",
)✅ This enforces time injection and enables deterministic testing. Excellent design. 🚀 Unblocks Future WorkThis PR successfully unblocks:
Depends on (satisfied):
📚 Documentation QualityThe PR includes exceptional documentation:
✅ Final RecommendationAPPROVE - This PR demonstrates exceptional engineering quality: ✅ Architectural compliance: Perfect adherence to ONEX orchestrator constraints This is production-ready code that successfully implements the first orchestrator node in omnibase_infra and establishes the architectural patterns that all future orchestrators will follow. No blocking issues identified. The minor observations above are suggestions for future iterations, not requirements for this PR. 🎓 Learning Points for Future PRsThis PR exemplifies ONEX best practices:
Excellent work! 🎉 |
…ures Add required timestamp field to 16 event constructions in test_registration_reducer.py that were causing CI failures. The ModelNodeIntrospectionEvent model requires timestamp as a mandatory field, but several test fixtures were missing it.
PR Review: Registration Orchestrator Implementation [C1]OverviewThis PR implements the first orchestrator node in ✅ STRENGTHS1. Architectural Compliance - ExceptionalThe orchestrator perfectly adheres to ONEX constraints:
2. Model Design - OutstandingEvent models are exceptionally well-designed:
3. Handler Logic - ExcellentHandlers demonstrate clean, testable design:
4. Test Coverage - Comprehensive60 unit tests covering G2 acceptance criteria with excellent patterns:
5. Documentation - SuperiorEvery component has exceptional documentation:
🔍 CODE QUALITY OBSERVATIONSType SafetyThe PR demonstrates excellent type safety practices:
Error Handling
ONEX ConventionsPerfect adherence to ONEX coding rules:
🎯 MINOR OBSERVATIONS (Not blocking, just notes for future work)1. ModelOrchestratorContext ConsolidationGood work consolidating duplicate 2. Last Heartbeat TrackingThe TODO comment at 3. Union Threshold IncreaseThe bump from 515 to 555 unions is well-documented with proper justification. The threshold history in validation comments provides excellent traceability. 🔒 SECURITY & PERFORMANCESecurity
Performance
📊 TEST COVERAGE ANALYSISThe PR includes 114 new tests across three categories: Unit Tests (60 tests)
Integration Tests (83 tests)
Performance Tests (31 tests)
Coverage Assessment: Excellent. All critical paths are tested. 🎓 ARCHITECTURAL SIGNIFICANCEThis PR establishes the orchestrator pattern for omnibase_infra:
The patterns established here will be referenced by future orchestrator implementations. ✨ RECOMMENDATIONSFor This PR: APPROVE & MERGE ✅This is production-ready code that exceeds quality standards:
For Future Work (Optional):
📝 FINAL VERDICTSTRONGLY APPROVE ✅ This PR demonstrates exceptional software engineering:
The registration orchestrator establishes a gold standard for future orchestrator implementations. Excellent work! Reviewed against: CLAUDE.md, ONEX_RUNTIME_REGISTRATION_TICKET_PLAN.md, ONEX architectural patterns |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (4)
tests/integration/event_bus/test_dispatch_flow.py (1)
643-650: Consider makingcreate_handlera regular function.The
create_handlerfunction is declared asasync defbut doesn't perform any async operations (noawaitstatements). Since Python allows returning an async function from a regular function, this can be simplified.🔎 Optional simplification
- async def create_handler( + def create_handler( idx: int, ) -> Callable[[ModelEventMessage], Awaitable[None]]: async def handler(msg: ModelEventMessage) -> None: all_received[idx].append(msg) return handlertests/performance/event_bus/test_event_bus_load.py (1)
496-499: Minor inconsistency:error_countlacks lock protection.The
bad_handlerincrementserror_countwithout anasyncio.Lock, whilegood_handleruses a lock forgood_count. This is inconsistent, though in practice it won't cause incorrect behavior in this single-coroutine test context.🔎 Suggested fix for consistency
+ error_lock = asyncio.Lock() + async def bad_handler(msg: ModelEventMessage) -> None: nonlocal error_count - error_count += 1 + async with error_lock: + error_count += 1 raise ValueError("Intentional error")tests/performance/event_bus/conftest.py (1)
165-180: Consider movingtimeimport to module level.The
timeimport inside the fixture works but is unconventional. Moving it to the module level (line 33 area) would be more idiomatic.🔎 Suggested change
Add to the module-level imports around line 33:
import timeThen remove line 167:
- import timetests/performance/event_bus/test_event_bus_throughput.py (1)
36-36: Unused import:TYPE_CHECKING.The
TYPE_CHECKINGimport is not used anywhere in this file.🔎 Suggested fix
-from typing import TYPE_CHECKING
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Lite
📒 Files selected for processing (14)
docs/architecture/EVENT_BUS_INTEGRATION_GUIDE.mddocs/design/MVP_EVENT_CATALOG.mddocs/operations/EVENT_BUS_OPERATIONS_RUNBOOK.mddocs/operations/README.mddocs/validation/EVENT_BUS_COVERAGE_REPORT.mdtests/integration/event_bus/test_correlation_tracking.pytests/integration/event_bus/test_dispatch_flow.pytests/integration/event_bus/test_event_schema_validation.pytests/performance/event_bus/__init__.pytests/performance/event_bus/conftest.pytests/performance/event_bus/test_event_bus_latency.pytests/performance/event_bus/test_event_bus_load.pytests/performance/event_bus/test_event_bus_throughput.pytests/unit/nodes/reducers/test_registration_reducer.py
✅ Files skipped from review due to trivial changes (3)
- docs/operations/EVENT_BUS_OPERATIONS_RUNBOOK.md
- docs/architecture/EVENT_BUS_INTEGRATION_GUIDE.md
- docs/validation/EVENT_BUS_COVERAGE_REPORT.md
🚧 Files skipped from review as they are similar to previous changes (1)
- tests/unit/nodes/reducers/test_registration_reducer.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.py: NEVER useAnytypes in Python code. Always use specific types. UseX | None(PEP 604) syntax instead ofOptional[X]for nullable types.
UseEnumMessageCategory(values: EVENT, COMMAND, INTENT) for message routing, topic parsing, and dispatcher selection. UseEnumNodeOutputType(values: EVENT, COMMAND, INTENT, PROJECTION) for execution shape validation and handler return type validation. PROJECTION exists only in EnumNodeOutputType and is only valid for REDUCER nodes.
UseX | Nonesyntax (PEP 604) for nullable types instead ofOptional[X]. Example:def get_user(id: str) -> User | None:instead ofdef get_user(id: str) -> Optional[User]:
All services MUST useModelONEXContainerfor dependency injection. Bootstrap pattern:container = ModelONEXContainer()followed bywire_infrastructure_services(container)andservice = container.service_registry.resolve_service(ServiceType).
Always propagate correlation_id from incoming requests to error context. Auto-generate usinguuid4()if no correlation_id exists. Use UUID format for all new correlation IDs. Include correlation_id in all error context for distributed tracing.
NEVER include in error messages or context: passwords, API keys, tokens, secrets, full connection strings with credentials, PII (names, emails, SSNs, phone numbers), internal IP addresses (in production logs), private keys or certificates, session tokens or cookies.
SAFE to include in error messages: service names (e.g., 'postgresql', 'kafka'), operation names (e.g., 'connect', 'query'), correlation IDs (always include for tracing), error codes, sanitized hostnames, port numbers, retry counts, timeout values, resource identifiers (non-sensitive).
UseProtocolConfigurationErrorfor config validation failures,SecretResolutionErrorfor secret/credential resolution,InfraConnectionErrorfor connection failures,InfraTimeoutErrorfor operation timeouts,InfraAuthenticationErrorfor auth/authz failures, `InfraUnava...
Files:
tests/performance/event_bus/__init__.pytests/performance/event_bus/conftest.pytests/integration/event_bus/test_event_schema_validation.pytests/integration/event_bus/test_correlation_tracking.pytests/performance/event_bus/test_event_bus_latency.pytests/performance/event_bus/test_event_bus_throughput.pytests/performance/event_bus/test_event_bus_load.pytests/integration/event_bus/test_dispatch_flow.py
🧠 Learnings (21)
📓 Common learnings
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T16:55:49.755Z
Learning: Applies to agents/**/*.py : Implement ONEX-compliant agent architecture with four node types: Effect (External I/O), Compute (Pure transforms), Reducer (State/persistence), and Orchestrator (Workflow coordination)
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: All ONEX nodes must conform to the canonical structure, code generation, and interface patterns established in the `node_cli` node, using it as the primary source of truth for directory structure, contract schema patterns, linked document architecture, base state patterns, shared schema references, extensibility patterns, CLI interface declarations, code generation, dependency injection, error handling, testing, and documentation
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: Applies to src/omninode_bridge/codegen/**/*.py : Code generation service MUST auto-generate ONEX v2.0 compliant nodes with intelligent mixin injection and quality validation. Generate comprehensive test suites with 90%+ coverage.
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/*.py : All ONEX node implementations must follow dependency injection and protocol-first design patterns as established in the node_cli canonical reference
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T16:32:55.606Z
Learning: All ONEX nodes must conform to the 4-Node Architecture pattern with clear separation of concerns and unidirectional data flow (EFFECT → COMPUTE → REDUCER → ORCHESTRATOR)
Learnt from: CR
Repo: OmniNode-ai/omniintelligence PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-07T17:50:13.678Z
Learning: Decompose intelligence operations into specialized ONEX nodes following a four-node pattern: Orchestrator (coordinate workflows), Reducer (manage state, FSM transitions), Compute (pure data processing), and Effect (external I/O)
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: All ONEX nodes must use the node_kafka_event_bus as a secondary reference only for complex backend and event bus logic and advanced configuration patterns
📚 Learning: 2025-12-22T00:11:20.308Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-22T00:11:20.308Z
Learning: Applies to **/kafka_event_bus.py : KafkaEventBus intentionally violates pattern validators: 14 methods (threshold: 10) and 10 __init__ parameters (threshold: 5). This complexity is acceptable due to event bus pattern requirements, backwards compatibility, and infrastructure cohesion. Design rationale documented in class and method docstrings.
Applied to files:
tests/performance/event_bus/__init__.pytests/performance/event_bus/conftest.pytests/integration/event_bus/test_event_schema_validation.pytests/performance/event_bus/test_event_bus_latency.pytests/performance/event_bus/test_event_bus_throughput.pytests/performance/event_bus/test_event_bus_load.pytests/integration/event_bus/test_dispatch_flow.py
📚 Learning: 2025-12-06T22:21:32.649Z
Learnt from: CR
Repo: OmniNode-ai/omniagent PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T22:21:32.649Z
Learning: Applies to nodes/**/*.py : Use event bus mixins from `omnibase_core` for Kafka publishing instead of direct Kafka clients
Applied to files:
tests/performance/event_bus/__init__.py
📚 Learning: 2025-11-30T21:55:10.298Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: Applies to src/omninode_bridge/events/**/*.py : Kafka event publishing MUST use OnexEnvelopeV1 format with 13 topics for event streaming at all workflow lifecycle stages
Applied to files:
docs/design/MVP_EVENT_CATALOG.md
📚 Learning: 2025-12-22T00:11:20.308Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-22T00:11:20.308Z
Learning: Applies to **/*.py : Use `EnumMessageCategory` (values: EVENT, COMMAND, INTENT) for message routing, topic parsing, and dispatcher selection. Use `EnumNodeOutputType` (values: EVENT, COMMAND, INTENT, PROJECTION) for execution shape validation and handler return type validation. PROJECTION exists only in EnumNodeOutputType and is only valid for REDUCER nodes.
Applied to files:
docs/design/MVP_EVENT_CATALOG.md
📚 Learning: 2025-12-07T17:50:13.678Z
Learnt from: CR
Repo: OmniNode-ai/omniintelligence PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-07T17:50:13.678Z
Learning: Implement Kafka event-driven architecture with proper topic naming using prefix dev.archon-intelligence. and proper event flow pattern with Effect nodes consuming events, processing, and publishing results with Dead Letter Queue routing
Applied to files:
docs/design/MVP_EVENT_CATALOG.md
📚 Learning: 2025-11-30T21:55:10.298Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: Deviations from omnibase_core standards are only acceptable for: (1) Orchestrator/Reducer nodes (ModelService* disabled), (2) Experimental features being prototyped for upstream, (3) Performance-critical optimizations with benchmark proof, (4) Bridge-specific unique patterns. All deviations require explicit documentation and justification.
Applied to files:
docs/design/MVP_EVENT_CATALOG.md
📚 Learning: 2025-11-24T17:22:32.195Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/canonical_patterns.mdc:0-0
Timestamp: 2025-11-24T17:22:32.195Z
Learning: Follow canonical patterns from reference implementations: use node_cli/v1_0_0/ as primary reference and node_kafka_event_bus/v1_0_0/ for complex backend patterns
Applied to files:
docs/design/MVP_EVENT_CATALOG.md
📚 Learning: 2025-11-28T18:58:53.781Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/canonical_patterns.mdc:0-0
Timestamp: 2025-11-28T18:58:53.781Z
Learning: Organize models under `src/omnibase_core/models/` by domain including: base, cli, common, config, core, contracts, discovery, health, infrastructure, logging, metadata, nodes, operations, results, security, service, tools, validation, and workflows
Applied to files:
docs/design/MVP_EVENT_CATALOG.md
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/*.py : All ONEX node implementations must follow dependency injection and protocol-first design patterns as established in the node_cli canonical reference
Applied to files:
docs/design/MVP_EVENT_CATALOG.md
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: All ONEX nodes must conform to the canonical structure, code generation, and interface patterns established in the `node_cli` node, using it as the primary source of truth for directory structure, contract schema patterns, linked document architecture, base state patterns, shared schema references, extensibility patterns, CLI interface declarations, code generation, dependency injection, error handling, testing, and documentation
Applied to files:
docs/design/MVP_EVENT_CATALOG.md
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: All ONEX nodes must use the node_kafka_event_bus as a secondary reference only for complex backend and event bus logic and advanced configuration patterns
Applied to files:
docs/design/MVP_EVENT_CATALOG.md
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/models/error_codes.py : All ONEX node error handling must use auto-generated error codes defined in `models/error_codes.py` from contract definitions
Applied to files:
docs/design/MVP_EVENT_CATALOG.md
📚 Learning: 2025-11-24T16:33:51.604Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-24T16:33:51.604Z
Learning: Applies to tests/**/conftest.py : Test fixtures must be defined in `conftest.py` and should provide reusable sample data, UUIDs, semantic versions, and model data
Applied to files:
tests/performance/event_bus/conftest.py
📚 Learning: 2025-12-07T17:50:13.678Z
Learnt from: CR
Repo: OmniNode-ai/omniintelligence PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-07T17:50:13.678Z
Learning: Organize tests following the structure: tests/conftest.py for shared fixtures, tests/unit/ for unit tests (no infrastructure), tests/integration/ for integration tests (requires Kafka/DBs), tests/nodes/ for node-specific tests
Applied to files:
tests/performance/event_bus/conftest.py
📚 Learning: 2025-11-24T16:33:51.604Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-24T16:33:51.604Z
Learning: Applies to tests/unit/models/**/test_model_*.py : Model tests must achieve 100% coverage and test instantiation, inheritance, serialization, deserialization, JSON serialization, roundtrip serialization, equality, hashing, string representation, repr, attributes, validation, metadata, data creation, copying, and immutability
Applied to files:
tests/integration/event_bus/test_event_schema_validation.py
📚 Learning: 2025-12-03T16:55:49.755Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T16:55:49.755Z
Learning: Applies to agents/**/*.py : Use correlation_id UUID for end-to-end traceability across all agent routing, manifest injection, and execution events
Applied to files:
tests/integration/event_bus/test_correlation_tracking.py
📚 Learning: 2025-12-22T00:11:20.308Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-22T00:11:20.308Z
Learning: Applies to **/*.py : Always propagate correlation_id from incoming requests to error context. Auto-generate using `uuid4()` if no correlation_id exists. Use UUID format for all new correlation IDs. Include correlation_id in all error context for distributed tracing.
Applied to files:
tests/integration/event_bus/test_correlation_tracking.py
📚 Learning: 2025-12-03T16:55:49.755Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T16:55:49.755Z
Learning: Applies to agents/**/*.py : Implement agent observability using three-layer traceability with correlation_id tracking through agent_routing_decisions, agent_manifest_injections, and agent_execution_logs tables
Applied to files:
tests/integration/event_bus/test_correlation_tracking.py
📚 Learning: 2025-11-29T17:13:38.776Z
Learnt from: CR
Repo: OmniNode-ai/omniarchon PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-29T17:13:38.776Z
Learning: Applies to {services/**/*.py,scripts/**/*.py} : Use correlation IDs for distributed logging across services. Implement log tracing with `python3 scripts/view_pipeline_logs.py --correlation-id X`.
Applied to files:
tests/integration/event_bus/test_correlation_tracking.py
📚 Learning: 2025-12-03T16:55:49.755Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T16:55:49.755Z
Learning: Applies to scripts/tests/**/*.sh : Implement comprehensive test suites in scripts/tests/ with separate test files for Kafka, PostgreSQL, Intelligence, and Routing functionality
Applied to files:
tests/integration/event_bus/test_dispatch_flow.py
🧬 Code graph analysis (4)
tests/performance/event_bus/conftest.py (3)
src/omnibase_infra/event_bus/inmemory_event_bus.py (1)
InMemoryEventBus(68-687)src/omnibase_infra/event_bus/models/model_event_headers.py (1)
ModelEventHeaders(16-81)src/omnibase_infra/event_bus/models/model_event_message.py (1)
ModelEventMessage(14-60)
tests/integration/event_bus/test_event_schema_validation.py (3)
src/omnibase_infra/event_bus/inmemory_event_bus.py (1)
InMemoryEventBus(68-687)src/omnibase_infra/event_bus/models/model_event_headers.py (2)
ModelEventHeaders(16-81)validate_headers(75-81)src/omnibase_infra/event_bus/models/model_event_message.py (2)
ModelEventMessage(14-60)ack(55-60)
tests/performance/event_bus/test_event_bus_latency.py (4)
tests/performance/event_bus/conftest.py (4)
event_bus(36-49)generate_unique_topic(202-208)sample_message_bytes(92-98)sample_headers(114-125)src/omnibase_infra/event_bus/inmemory_event_bus.py (1)
InMemoryEventBus(68-687)src/omnibase_infra/event_bus/models/model_event_headers.py (1)
ModelEventHeaders(16-81)src/omnibase_infra/event_bus/models/model_event_message.py (1)
ModelEventMessage(14-60)
tests/performance/event_bus/test_event_bus_throughput.py (4)
tests/performance/event_bus/conftest.py (5)
event_bus(36-49)generate_unique_topic(202-208)sample_message_bytes(92-98)high_volume_event_bus(53-66)large_message_bytes(102-110)src/omnibase_infra/event_bus/inmemory_event_bus.py (2)
InMemoryEventBus(68-687)get_topic_offset(627-637)src/omnibase_infra/event_bus/models/model_event_headers.py (1)
ModelEventHeaders(16-81)src/omnibase_infra/event_bus/models/model_event_message.py (1)
ModelEventMessage(14-60)
🔇 Additional comments (44)
docs/operations/README.md (1)
9-9: Documentation addition is correct; linked file exists and is properly documented.The new table row at line 9 follows the established markdown format, and
EVENT_BUS_OPERATIONS_RUNBOOK.mdexists indocs/operations/with comprehensive sections covering deployment, configuration, monitoring, and troubleshooting. The change is ready to merge.tests/integration/event_bus/test_correlation_tracking.py (7)
1-36: LGTM! Excellent test module structure.The module documentation, imports, and configuration are well-organized. The docstring clearly outlines test categories, and the TYPE_CHECKING guard properly defers imports for type hints.
43-63: LGTM! Fixtures provide proper test isolation.The fixtures correctly implement async lifecycle management and generate unique resource identifiers for test isolation using UUID-based naming.
71-215: LGTM! Comprehensive correlation ID propagation tests.The test suite thoroughly validates correlation ID behavior including preservation, auto-generation, uniqueness, and UUID format compliance. The tests follow a clear, consistent pattern and cover all essential propagation scenarios.
222-314: LGTM! Excellent distributed tracing context validation.The tests properly verify that correlation IDs and distributed tracing metadata (trace_id, span_id, parent_span_id) are preserved through event history and message flows, supporting end-to-end observability.
368-368: Acceptable synchronization pattern for integration tests.The
asyncio.sleep(0.1)calls provide synchronization for async message processing across multiple hops. While sleep-based synchronization can be fragile, it's a standard pattern for integration tests with in-memory event buses and the 0.1-second duration should be sufficient.Also applies to: 422-422, 476-476
492-600: LGTM! Comprehensive error scenario coverage.The tests thoroughly validate that correlation IDs are preserved through error conditions including handler failures, event history persistence after errors, and circuit breaker activation. The circuit breaker test correctly triggers the threshold and verifies continued correlation tracking.
607-723: LGTM! Complete dispatch context correlation validation.The tests provide comprehensive coverage of correlation ID handling across all node type dispatch contexts (reducer, compute, orchestrator, effect, runtime_host) and properly verify time injection requirements for each type. The error preservation test correctly validates that correlation IDs survive error transformations.
tests/integration/event_bus/test_dispatch_flow.py (6)
1-36: LGTM: Clean module structure and imports.The module follows best practices with proper type checking imports, comprehensive docstring, and integration test marking.
43-60: LGTM: Proper fixture lifecycle management.Both fixtures correctly handle setup and teardown, with proper async context management for the event bus.
206-354: LGTM: Comprehensive category routing tests.Excellent coverage of topic parsing variations (ONEX standard, environment-aware, category extraction) with proper assertions on parsed fields and routing behavior.
361-466: LGTM: Thorough pattern matching test coverage.Tests comprehensively cover wildcard patterns, edge cases (empty strings, case sensitivity), and ModelDispatchRoute behavior including disabled routes.
697-825: LGTM: Complete dispatch result modeling tests.Thorough validation of ModelDispatchResult creation, error/success transformations, and status detection methods with appropriate assertions.
67-199: No issues found. InMemoryEventBus delivers messages synchronously within the publish call. Each subscriber callback is awaited sequentially (line 327), so by the timeawait event_bus.publish(...)returns, all subscribers have received and processed the message. The tests correctly assume immediate receipt and require no additional synchronization.tests/integration/event_bus/test_event_schema_validation.py (7)
1-35: LGTM! Clean imports and test configuration.The imports follow best practices with future annotations, proper TYPE_CHECKING guards, and PEP 604 union syntax. The test markers appropriately categorize this as an integration test suite.
43-67: LGTM! Well-structured test fixtures.Both fixtures follow proper patterns:
sample_headersprovides reusable test data, andstarted_event_busimplements the async generator pattern with proper setup/teardown usingyield.
75-243: LGTM! Comprehensive header validation tests.The test class thoroughly validates
ModelEventHeadersbehavior including field defaults, auto-generation of IDs/timestamps, validation rules, immutability, and the asyncvalidate_headers()method. All tests are well-structured and properly usepytest.raisesfor error cases.
250-371: LGTM! Thorough message validation tests.The test class comprehensively validates
ModelEventMessagebehavior including required fields, optional fields, immutability, and the asyncack()method. Proper validation error checking withpytest.raises.
379-448: LGTM! Comprehensive invalid schema rejection tests.The test class thoroughly validates that invalid schemas are properly rejected, including missing required fields and type validation. Good use of
pytest.raiseswith detailed error message checking.
456-591: LGTM! Excellent end-to-end header completeness tests.The test class validates header integrity through the full publish/subscribe cycle, ensuring headers are complete, custom headers are preserved, metadata is maintained, and IDs are unique across sequential messages. These integration tests provide valuable coverage of real-world event bus behavior.
602-670: LGTM! Comprehensive serialization tests.The test methods thoroughly validate JSON serialization and deserialization using Pydantic v2 patterns (
model_dump(mode="json")andmodel_validate_json). The round-trip serialization test is particularly valuable for ensuring data integrity.tests/performance/event_bus/__init__.py (1)
1-19: LGTM!Well-documented package initializer with clear categorization of test types (Throughput, Latency, Load) and appropriate references to the related issue and implementations.
tests/performance/event_bus/test_event_bus_load.py (4)
48-167: LGTM!The
TestSustainedLoadclass properly validates throughput stability over time with reasonable variance thresholds. Resource management (start/close) is correctly handled, and the async lock usage for the counter is appropriate.
175-312: LGTM!The
TestMemoryStabilityclass provides good coverage of memory-related behaviors. The use ofgc.get_objects()for leak detection is a reasonable heuristic for the in-memory bus, and the subscriber cleanup test properly verifies that unsubscribe functions release resources.
320-457: LGTM!The
TestMultipleSubscriberLoadclass properly validates high fan-out scenarios. Themake_handlerfactory pattern correctly captures the index via function parameters, avoiding the common closure-in-loop pitfall.
525-626: LGTM!The circuit breaker and graceful shutdown tests are well-structured. The shutdown test correctly uses a flag to coordinate task termination and validates that shutdown completes within acceptable time bounds.
tests/performance/event_bus/conftest.py (3)
35-83: LGTM!The event bus fixtures are well-designed with proper async lifecycle management (start/close). The different configurations (default, high-volume, low-latency) appropriately serve their intended testing scenarios. Based on learnings, fixtures should provide reusable sample data, and these do exactly that.
91-125: LGTM!Message and header fixtures are appropriately designed. The
sample_headersfixture correctly provides the requiredsourceandevent_typefields forModelEventHeaders.
202-223: LGTM!Utility functions are well-designed and documented.
generate_unique_topicensures test isolation via UUID, andgenerate_batch_messagesprovides a reusable batch generation pattern.tests/performance/event_bus/test_event_bus_latency.py (4)
50-106: LGTM!The
test_publish_latency_distribution_1000correctly usesquantiles(latencies, n=100)to calculate percentiles. The performance thresholds are appropriately lenient for CI environments as documented.
107-205: LGTM!The cold vs warm latency test and header overhead test are well-structured. The 50x cold/warm ratio threshold accounts for CI environment variability, and the 50% header overhead limit is reasonable.
213-383: LGTM!The
TestEndToEndLatencyclass provides thorough end-to-end latency measurement. The publish-time correlation viapublish_timesdictionary is well-designed, and the degradation check comparing first/last batch averages is a good stability indicator.
391-569: LGTM!The
TestLatencyUnderLoadclass comprehensively tests latency characteristics under various load conditions. The concurrency test usingasyncio.gather, history pressure test with pre-filled buffer, and subscriber impact test with isolated topics are all well-designed approaches.tests/performance/event_bus/test_event_bus_throughput.py (4)
50-166: LGTM!The
TestSinglePublisherThroughputclass provides solid baseline throughput measurements. The inclusion ofget_topic_offsetverification ensures messages are actually stored, not just processed.
174-277: LGTM!The
TestBatchPublishingclass appropriately tests sequential batch publishing patterns. The large message throughput test includes a useful data rate calculation for understanding memory bandwidth characteristics.
285-433: LGTM!The
TestConcurrentPublishersclass properly usesasyncio.gatherfor concurrent execution and verifies both message counts and topic offsets. The multi-topic test design correctly isolates topics to measure cross-topic concurrency behavior.
441-589: LGTM!The
TestPublishWithSubscribersclass comprehensively tests throughput with active subscribers. The fan-out test correctly verifies total deliveries (subscribers × messages) and provides useful metrics for both publish rate and delivery rate.docs/design/MVP_EVENT_CATALOG.md (7)
27-52: Excellent clarification of message categories vs node output types.The distinction between
EnumMessageCategory(for routing) andEnumNodeOutputType(for validation) is clearly explained, with correct emphasis thatPROJECTIONis not a message category. This guidance aligns with the architectural constraints outlined in the learnings.
646-690: Schema evolution guidelines are well-designed.The versioning strategy, field modification patterns, and version bump guidelines align with industry best practices. The examples clearly distinguish safe changes (optional fields with defaults) from breaking changes (new required fields, type narrowing).
No changes needed here.
802-808: Verify that the referenced documentation files exist in the repository.The "Related Documentation" section references four documents:
CLAUDE.md- enum usage guidelinesONEX_RUNTIME_REGISTRATION_TICKET_PLAN.md- C1 orchestrator designcorrelation_id_tracking.md- distributed tracing patternserror_handling_patterns.md- error context and sanitizationPlease verify these files exist in the codebase. If any are missing, either create them or remove the reference from this section.
54-114: All referenced source files exist in the codebase with the documented paths. No action required.
601-623: No changes needed. RUNTIME_HOST is a valid EnumNodeKind value with full architectural support, and all factory methods (for_reducer, for_orchestrator, for_effect) exist and are correctly documented in ModelDispatchContext. The documentation in MVP_EVENT_CATALOG.md is accurate.Likely an incorrect or invalid review comment.
693-735: Timestamp injection is correctly implemented throughout the registration orchestrator.The documentation guidance (lines 722-727) is confirmed by the implementation:
ModelOrchestratorContextinjectsnowand handlers must use it (never calldatetime.now()directly)HandlerNodeRegistrationAcked._emit_activation_events()correctly instantiates events withemitted_at=now(the injected parameter)ModelDispatchContext.for_reducer()enforcesnow=Nonefor reducers with validation- Event model docstring examples show
datetime.now(UTC), but actual handler calls use the injected time parameterNo changes needed; implementation aligns with documented best practices.
738-798: All import paths documented in the quick reference are correct and properly exported. Verification confirms:
- Registration events (
omnibase_infra.models.registration): All 9 event models properly exported- Registration commands (
omnibase_infra.models.registration.commands): ModelNodeRegistrationAcked properly exported- Dispatch models (
omnibase_infra.models.dispatch): ModelDispatchResult, ModelDispatchContext, ModelParsedTopic, and ModelTopicParser all properly exported- Event bus models (
omnibase_infra.event_bus.models): ModelEventMessage and ModelEventHeaders properly exported- Enums (
omnibase_infra.enums): All four enums (EnumMessageCategory, EnumNodeOutputType, EnumTopicStandard, EnumDispatchStatus) properly exportedModelTopicParser is a legitimate utility class for topic parsing with caching support, properly included in the dispatch exports.
| ## Registration Domain Events | ||
|
|
||
| The registration domain implements the ONEX 2-way registration pattern for node lifecycle management. | ||
|
|
||
| ### Event Flow Diagram | ||
|
|
||
| ``` | ||
| Node Orchestrator Reducer Projection | ||
| | | | | | ||
| |--NodeIntrospected-------->| | | | ||
| | |--RegistrationInitiated-->|------------------>| | ||
| | | | | | ||
| | |--RegistrationAccepted--->|------------------>| | ||
| |<------(ack deadline)------| | | | ||
| | | | | | ||
| |--RegistrationAcked------->| | | | ||
| | |--AckReceived------------>|------------------>| | ||
| | |--NodeBecameActive------->|------------------>| | ||
| | | | | | ||
| |--Heartbeat--------------->| | | | ||
| |--Heartbeat--------------->| (liveness monitoring)| | | ||
| ``` | ||
|
|
||
| ### ModelNodeIntrospectionEvent | ||
|
|
||
| **Purpose**: Node announces its presence and capabilities to the cluster. | ||
|
|
||
| **Topic**: `onex.registration.events` or `dev.node.events.v1` | ||
|
|
||
| **Category**: EVENT | ||
|
|
||
| ```python | ||
| class ModelNodeIntrospectionEvent(BaseModel): | ||
| # Identity | ||
| node_id: UUID # Unique node identifier | ||
| node_type: Literal["effect", "compute", "reducer", "orchestrator"] | ||
| node_version: str = "1.0.0" # Semantic version | ||
|
|
||
| # Capabilities | ||
| capabilities: ModelNodeCapabilities # Node capabilities dict | ||
| endpoints: dict[str, str] # Exposed endpoints (name -> URL) | ||
|
|
||
| # Metadata | ||
| node_role: str | None = None # Optional role (registry, adapter) | ||
| metadata: ModelNodeMetadata # Additional node metadata | ||
| correlation_id: UUID # Required for idempotency | ||
|
|
||
| # Deployment | ||
| network_id: str | None = None # Network/cluster identifier | ||
| deployment_id: str | None = None # Deployment/release identifier | ||
| epoch: int | None = None # Registration epoch for ordering | ||
|
|
||
| # Timing | ||
| timestamp: datetime # Event timestamp (injected) | ||
| ``` | ||
|
|
||
| **Example**: | ||
| ```json | ||
| { | ||
| "node_id": "550e8400-e29b-41d4-a716-446655440000", | ||
| "node_type": "effect", | ||
| "node_version": "1.2.3", | ||
| "capabilities": {"postgres": true, "read": true, "write": true}, | ||
| "endpoints": {"health": "http://localhost:8080/health"}, | ||
| "correlation_id": "660e8400-e29b-41d4-a716-446655440001", | ||
| "timestamp": "2025-01-15T10:30:00Z" | ||
| } | ||
| ``` | ||
|
|
||
| **Source File**: `src/omnibase_infra/models/registration/model_node_introspection_event.py` | ||
|
|
||
| --- | ||
|
|
||
| ### ModelNodeHeartbeatEvent | ||
|
|
||
| **Purpose**: Periodic liveness signal with health metrics. | ||
|
|
||
| **Topic**: `onex.registration.events` or `onex.heartbeat.events` | ||
|
|
||
| **Category**: EVENT | ||
|
|
||
| ```python | ||
| class ModelNodeHeartbeatEvent(BaseModel): | ||
| # Identity | ||
| node_id: UUID # Node identifier | ||
| node_type: str # ONEX node type (relaxed validation) | ||
| node_version: str = "1.0.0" | ||
|
|
||
| # Health Metrics | ||
| uptime_seconds: float # Node uptime (>= 0) | ||
| active_operations_count: int = 0 # Active operations (>= 0) | ||
| memory_usage_mb: float | None = None # Optional memory usage | ||
| cpu_usage_percent: float | None = None # Optional CPU usage (0-100) | ||
|
|
||
| # Metadata | ||
| correlation_id: UUID | None = None | ||
| timestamp: datetime # Event timestamp (injected) | ||
| ``` | ||
|
|
||
| **Example**: | ||
| ```json | ||
| { | ||
| "node_id": "550e8400-e29b-41d4-a716-446655440000", | ||
| "node_type": "effect", | ||
| "node_version": "1.2.3", | ||
| "uptime_seconds": 3600.5, | ||
| "active_operations_count": 5, | ||
| "memory_usage_mb": 256.0, | ||
| "cpu_usage_percent": 15.5, | ||
| "timestamp": "2025-01-15T11:30:00Z" | ||
| } | ||
| ``` | ||
|
|
||
| **Source File**: `src/omnibase_infra/models/registration/model_node_heartbeat_event.py` | ||
|
|
||
| --- | ||
|
|
||
| ### ModelNodeRegistrationInitiated | ||
|
|
||
| **Purpose**: Orchestrator signals start of registration attempt. | ||
|
|
||
| **Topic**: `onex.registration.events` | ||
|
|
||
| **Category**: EVENT | ||
|
|
||
| ```python | ||
| class ModelNodeRegistrationInitiated(BaseModel): | ||
| entity_id: UUID # Entity identifier (= node_id) | ||
| node_id: UUID # Node being registered | ||
| correlation_id: UUID # Distributed tracing | ||
| causation_id: UUID # Triggering NodeIntrospected message_id | ||
| emitted_at: datetime # Orchestrator emission time (injected) | ||
| registration_attempt_id: UUID # Unique attempt identifier | ||
| ``` | ||
|
|
||
| **Triggering Event**: `NodeIntrospectionEvent` | ||
| **FSM Transition**: N/A -> INITIATED | ||
|
|
||
| **Source File**: `src/omnibase_infra/models/registration/events/model_node_registration_initiated.py` | ||
|
|
||
| --- | ||
|
|
||
| ### ModelNodeRegistrationAccepted | ||
|
|
||
| **Purpose**: Orchestrator accepts node registration. | ||
|
|
||
| **Topic**: `onex.registration.events` | ||
|
|
||
| **Category**: EVENT | ||
|
|
||
| ```python | ||
| class ModelNodeRegistrationAccepted(BaseModel): | ||
| entity_id: UUID # Entity identifier (= node_id) | ||
| node_id: UUID # Node being registered | ||
| correlation_id: UUID # Distributed tracing | ||
| causation_id: UUID # Triggering event message_id | ||
| emitted_at: datetime # Orchestrator emission time (injected) | ||
| ack_deadline: datetime # Deadline for node acknowledgment | ||
| ``` | ||
|
|
||
| **FSM Transition**: INITIATED -> AWAITING_ACK | ||
|
|
||
| **Source File**: `src/omnibase_infra/models/registration/events/model_node_registration_accepted.py` | ||
|
|
||
| --- | ||
|
|
||
| ### ModelNodeRegistrationRejected | ||
|
|
||
| **Purpose**: Orchestrator rejects node registration. | ||
|
|
||
| **Topic**: `onex.registration.events` | ||
|
|
||
| **Category**: EVENT | ||
|
|
||
| ```python | ||
| class ModelNodeRegistrationRejected(BaseModel): | ||
| entity_id: UUID # Entity identifier (= node_id) | ||
| node_id: UUID # Node being rejected | ||
| correlation_id: UUID # Distributed tracing | ||
| causation_id: UUID # Triggering event message_id | ||
| emitted_at: datetime # Orchestrator emission time (injected) | ||
| rejection_reason: str # Human-readable explanation (1-1024 chars) | ||
| ``` | ||
|
|
||
| **FSM Transition**: INITIATED -> REJECTED (terminal) | ||
|
|
||
| **Common Rejection Reasons**: | ||
| - Node version incompatibility | ||
| - Capability requirements not met | ||
| - Rate limiting exceeded | ||
| - Duplicate registration attempt | ||
| - Policy violation | ||
|
|
||
| **Source File**: `src/omnibase_infra/models/registration/events/model_node_registration_rejected.py` | ||
|
|
||
| --- | ||
|
|
||
| ### ModelNodeRegistrationAckReceived | ||
|
|
||
| **Purpose**: Orchestrator confirms receipt of node acknowledgment. | ||
|
|
||
| **Topic**: `onex.registration.events` | ||
|
|
||
| **Category**: EVENT | ||
|
|
||
| ```python | ||
| class ModelNodeRegistrationAckReceived(BaseModel): | ||
| entity_id: UUID # Entity identifier (= node_id) | ||
| node_id: UUID # Node that acknowledged | ||
| correlation_id: UUID # Distributed tracing | ||
| causation_id: UUID # NodeRegistrationAcked command message_id | ||
| emitted_at: datetime # Orchestrator emission time (injected) | ||
| liveness_deadline: datetime # Deadline for next heartbeat | ||
| ``` | ||
|
|
||
| **Triggering Command**: `NodeRegistrationAcked` | ||
| **FSM Transition**: AWAITING_ACK -> ACTIVE | ||
|
|
||
| **Source File**: `src/omnibase_infra/models/registration/events/model_node_registration_ack_received.py` | ||
|
|
||
| --- | ||
|
|
||
| ### ModelNodeBecameActive | ||
|
|
||
| **Purpose**: Node transitions to active state. | ||
|
|
||
| **Topic**: `onex.registration.events` | ||
|
|
||
| **Category**: EVENT | ||
|
|
||
| ```python | ||
| class ModelNodeBecameActive(BaseModel): | ||
| entity_id: UUID # Entity identifier (= node_id) | ||
| node_id: UUID # Activated node | ||
| correlation_id: UUID # Distributed tracing | ||
| causation_id: UUID # Triggering event message_id | ||
| emitted_at: datetime # Orchestrator emission time (injected) | ||
| capabilities: ModelNodeCapabilities # Node capabilities at activation | ||
| ``` | ||
|
|
||
| **FSM Transition**: AWAITING_ACK -> ACTIVE | ||
|
|
||
| **Source File**: `src/omnibase_infra/models/registration/events/model_node_became_active.py` | ||
|
|
||
| --- | ||
|
|
||
| ### ModelNodeRegistrationAckTimedOut | ||
|
|
||
| **Purpose**: Node failed to acknowledge within deadline. | ||
|
|
||
| **Topic**: `onex.registration.events` | ||
|
|
||
| **Category**: EVENT | ||
|
|
||
| ```python | ||
| class ModelNodeRegistrationAckTimedOut(BaseModel): | ||
| entity_id: UUID # Entity identifier (= node_id) | ||
| node_id: UUID # Node that failed to acknowledge | ||
| correlation_id: UUID # Distributed tracing | ||
| causation_id: UUID # RuntimeTick that triggered this | ||
| emitted_at: datetime # Detection time (from RuntimeTick.now) | ||
| deadline_at: datetime # Original ack deadline that was exceeded | ||
| ``` | ||
|
|
||
| **Trigger**: RuntimeTick processing detects expired ack_deadline | ||
| **FSM Transition**: AWAITING_ACK -> ACK_TIMED_OUT (terminal) | ||
| **Deduplication**: Uses `ack_timeout_emitted_at` marker in projection | ||
|
|
||
| **Source File**: `src/omnibase_infra/models/registration/events/model_node_registration_ack_timed_out.py` | ||
|
|
||
| --- | ||
|
|
||
| ### ModelNodeLivenessExpired | ||
|
|
||
| **Purpose**: Active node failed heartbeat check. | ||
|
|
||
| **Topic**: `onex.registration.events` | ||
|
|
||
| **Category**: EVENT | ||
|
|
||
| ```python | ||
| class ModelNodeLivenessExpired(BaseModel): | ||
| entity_id: UUID # Entity identifier (= node_id) | ||
| node_id: UUID # Node that failed liveness | ||
| correlation_id: UUID # Distributed tracing | ||
| causation_id: UUID # RuntimeTick that triggered this | ||
| emitted_at: datetime # Detection time (from RuntimeTick.now) | ||
| last_heartbeat_at: datetime | None # Last received heartbeat (or None) | ||
| ``` | ||
|
|
||
| **Trigger**: RuntimeTick processing detects expired liveness_deadline | ||
| **FSM Transition**: ACTIVE -> LIVENESS_EXPIRED (terminal) | ||
| **Deduplication**: Uses `liveness_timeout_emitted_at` marker in projection | ||
|
|
||
| **Source File**: `src/omnibase_infra/models/registration/events/model_node_liveness_expired.py` | ||
|
|
||
| --- |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if registration events directory exists
echo "=== Checking registration events directory structure ==="
find src -type d -name "registration" 2>/dev/null | head -20
# List all files in registration/events if it exists
echo -e "\n=== Files in registration/events/ ==="
find src -path "*/registration/events/*.py" 2>/dev/null
# Also check the broader registration models structure
echo -e "\n=== All .py files under registration/ ==="
find src -path "*/registration/*.py" 2>/dev/null | sortRepository: OmniNode-ai/omnibase_infra
Length of output: 2758
🏁 Script executed:
#!/bin/bash
# Check the actual field definitions in the model files
echo "=== ModelNodeIntrospectionEvent fields ==="
cat -n src/omnibase_infra/models/registration/model_node_introspection_event.py
echo -e "\n=== ModelNodeHeartbeatEvent fields ==="
cat -n src/omnibase_infra/models/registration/model_node_heartbeat_event.py
echo -e "\n=== ModelNodeRegistrationRejected fields ==="
cat -n src/omnibase_infra/models/registration/events/model_node_registration_rejected.pyRepository: OmniNode-ai/omnibase_infra
Length of output: 14459
🏁 Script executed:
#!/bin/bash
# Check the other event models
echo "=== ModelNodeRegistrationInitiated fields ==="
head -80 src/omnibase_infra/models/registration/events/model_node_registration_initiated.py | cat -n
echo -e "\n=== ModelNodeRegistrationAccepted fields ==="
head -80 src/omnibase_infra/models/registration/events/model_node_registration_accepted.py | cat -n
echo -e "\n=== ModelNodeRegistrationAckTimed Out fields ==="
head -100 src/omnibase_infra/models/registration/events/model_node_registration_ack_timed_out.py | cat -n
echo -e "\n=== Search for deduplication markers in projection/state ==="
rg -n "ack_timeout_emitted_at|liveness_timeout_emitted_at" --type pythonRepository: OmniNode-ai/omnibase_infra
Length of output: 156
🏁 Script executed:
#!/bin/bash
# Check one file at a time to avoid timeout
echo "=== ModelNodeRegistrationAckTimedOut ==="
cat -n src/omnibase_infra/models/registration/events/model_node_registration_ack_timed_out.py
echo -e "\n=== Search for deduplication in orchestrator ==="
find src -name "*.py" -path "*/orchestrators/registration/*" | xargs grep -l "ack_timeout_emitted_at\|liveness_timeout_emitted_at" 2>/dev/null
echo -e "\n=== Search for projection state files ==="
find src -name "*projection*" -o -name "*state*" | grep -i registrRepository: OmniNode-ai/omnibase_infra
Length of output: 4387
🏁 Script executed:
#!/bin/bash
# Check the registration state enum for FSM states
echo "=== FSM States in enum_registration_state.py ==="
cat -n src/omnibase_infra/enums/enum_registration_state.py
echo -e "\n=== Registration Projection Model (first 150 lines) ==="
head -150 src/omnibase_infra/models/projection/model_registration_projection.py | cat -nRepository: OmniNode-ai/omnibase_infra
Length of output: 17821
Fix source file paths for ModelNodeIntrospectionEvent and ModelNodeHeartbeatEvent.
The documented source file locations for these two events are incorrect:
- Line 237 (ModelNodeIntrospectionEvent): Change
src/omnibase_infra/models/registration/events/model_node_introspection_event.pytosrc/omnibase_infra/models/registration/model_node_introspection_event.py - Line 281 (ModelNodeHeartbeatEvent): Change
src/omnibase_infra/models/registration/events/model_node_heartbeat_event.pytosrc/omnibase_infra/models/registration/model_node_heartbeat_event.py
All other event models are correctly located in the events/ subdirectory. Field definitions, FSM transitions, and deduplication markers (stored in the projection via ack_timeout_emitted_at and liveness_timeout_emitted_at) are all accurately documented and implemented.
🤖 Prompt for AI Agents
In docs/design/MVP_EVENT_CATALOG.md around lines 237 and 281, the Source File
paths for ModelNodeIntrospectionEvent and ModelNodeHeartbeatEvent are incorrect;
update the path at line ~237 from
src/omnibase_infra/models/registration/events/model_node_introspection_event.py
to src/omnibase_infra/models/registration/model_node_introspection_event.py, and
update the path at line ~281 from
src/omnibase_infra/models/registration/events/model_node_heartbeat_event.py to
src/omnibase_infra/models/registration/model_node_heartbeat_event.py so the
documented locations match the actual source files.
Take main's INFRA_MAX_UNIONS=580 threshold as the current baseline.
Code Review: Registration Orchestrator Implementation [C1]SummaryThis PR implements the first orchestrator node in omnibase_infra following ONEX architectural patterns. The implementation is exceptionally well-architected and demonstrates deep understanding of ONEX principles. The code quality is production-ready with minor suggestions for enhancement. Recommendation: ✅ APPROVE with minor suggestions Strengths1. Architectural Compliance ⭐⭐⭐⭐⭐The orchestrator perfectly adheres to ONEX constraints:
Example from async def handle(
self,
envelope: ModelEventEnvelope[object],
now: datetime, # ✅ Injected time
correlation_id: UUID | None = None,
) -> list[BaseModel]: # ✅ Returns events only
"""Route to appropriate handler and return emitted events."""
# ✅ No I/O operations - only routing logic2. Type Safety ⭐⭐⭐⭐⭐
Example from class ModelOrchestratorContext(BaseModel):
model_config = ConfigDict(
frozen=True, # ✅ Immutable for thread safety
extra="forbid", # ✅ Strict validation
)
now: datetime = Field(...) # ✅ No default_factory - forces explicit injection
correlation_id: UUID = Field(...)
trace_id: UUID | None = Field(default=None) # ✅ PEP 604 syntax3. Handler Separation ⭐⭐⭐⭐⭐The orchestrator delegates to specialized handlers with clear responsibilities:
This separation follows Single Responsibility Principle and enables focused unit testing. 4. State Decision Logic ⭐⭐⭐⭐⭐The handlers implement crystal-clear state decision matrices:
_RETRIABLE_STATES: frozenset[EnumRegistrationState] = frozenset({
EnumRegistrationState.LIVENESS_EXPIRED,
EnumRegistrationState.REJECTED,
EnumRegistrationState.ACK_TIMED_OUT,
})
_BLOCKING_STATES: frozenset[EnumRegistrationState] = frozenset({
EnumRegistrationState.PENDING_REGISTRATION,
EnumRegistrationState.ACCEPTED,
EnumRegistrationState.AWAITING_ACK,
EnumRegistrationState.ACK_RECEIVED,
EnumRegistrationState.ACTIVE,
})This approach is:
5. Test Coverage ⭐⭐⭐⭐⭐The PR includes 60 unit tests covering:
Example from @pytest.mark.asyncio
async def test_orchestrator_emits_events_only_no_io_introspection(self) -> None:
"""Given orchestrator with mock projection reader,
When processing introspection event with injected `now`,
Then output contains ONLY events (no intents, no projections)."""
# ✅ Clear test documentation
# ✅ Verifies architectural constraints
# ✅ Uses mocks to verify no I/O6. Documentation Quality ⭐⭐⭐⭐⭐
The new documentation files are exceptional:
Suggestions for Enhancement1. Type Narrowing in HandlerRuntimeTick (Minor)Location: Current Code: # Type narrowing: needs_ack_timeout_event() checks ack_deadline is not None,
# but the type checker doesn't know this. Explicit narrowing required.
ack_deadline = projection.ack_deadline
if ack_deadline is None:
logger.warning(
"Unexpected None ack_deadline for overdue projection",
extra={"entity_id": str(projection.entity_id)},
)
continueSuggestion: Consider using # Type narrowing: needs_ack_timeout_event() guarantees ack_deadline is not None
ack_deadline = projection.ack_deadline
assert ack_deadline is not None, \
f"needs_ack_timeout_event() guarantees ack_deadline: {projection.entity_id}"Rationale:
Same applies to: Line 277 for 2. Liveness Interval Configuration (Minor)Location: Current Code: # Default liveness interval in seconds
# This should be configurable, but for now using a reasonable default
_DEFAULT_LIVENESS_INTERVAL_SECONDS: int = 60Suggestion: Add a TODO with ticket reference: # TODO(OMN-XXX): Make liveness interval configurable via container
# For MVP, using reasonable default of 60 seconds
_DEFAULT_LIVENESS_INTERVAL_SECONDS: int = 60Rationale: Tracks the tech debt and makes it discoverable for future work. 3. Correlation ID Resolution (Minor)Location: Current Code: corr_id = correlation_id or getattr(envelope, "correlation_id", None) or uuid4()Suggestion: Extract to a helper method for clarity: def _resolve_correlation_id(
explicit: UUID | None,
envelope: ModelEventEnvelope[object],
) -> UUID:
"""Resolve correlation ID from explicit param, envelope, or generate new."""
return explicit or getattr(envelope, "correlation_id", None) or uuid4()
# Usage
corr_id = self._resolve_correlation_id(correlation_id, envelope)Rationale:
4. Event Model Timestamp Fields (Documentation)Location: All event models use Observation: This is correct per ONEX principles (no auto-generated timestamps), but worth documenting why. Suggestion: Add a module-level comment in one event model (e.g., """Node Registration Initiated Event Model.
IMPORTANT: emitted_at has NO default_factory (no datetime.now()).
This is intentional per ONEX architecture - orchestrators use injected
`now` parameter from RuntimeTick or dispatch context. This ensures:
- Deterministic testing (fixed time in tests)
- Consistent ordering (no clock skew)
- Explicit time injection (no hidden time dependencies)
"""Rationale: Helps future developers understand why the pattern differs from typical event sourcing implementations. Security Considerations✅ No security concerns identified
Performance Considerations✅ Performance looks excellent
Potential future optimization (not required for this PR):
Test Coverage Assessment✅ 60 unit tests - Comprehensive coverage What's tested well:
Suggested additional tests (nice-to-have, not blocking):
Documentation Assessment✅ Outstanding documentation The new guides are production-ready:
Minor suggestion: Add a "Quick Links" section to ## 📚 Event Bus & Orchestration
- **Event Bus Integration**: `docs/architecture/EVENT_BUS_INTEGRATION_GUIDE.md`
- **Event Catalog**: `docs/design/MVP_EVENT_CATALOG.md`
- **Operations Runbook**: `docs/operations/EVENT_BUS_OPERATIONS_RUNBOOK.md`ONEX Pattern ValidationI've validated this implementation against CLAUDE.md requirements:
ConclusionThis PR represents exemplary ONEX architecture. The implementation demonstrates:
The suggestions above are minor enhancements and do not block merge. This code is ready for production. Great work! 🎉 Checklist
Final Recommendation: ✅ APPROVE |
Code Quality Enhancements: - handler_runtime_tick.py: Replace defensive log+continue with assert for type narrowing (needs_ack_timeout_event guarantees non-null) - handler_node_registration_acked.py: Add TODO(OMN-XXX) ticket reference for liveness interval configurability - node_registration_orchestrator.py: Extract _resolve_correlation_id() helper method with docstring for clarity - model_node_registration_initiated.py: Add IMPORTANT docstring block explaining why emitted_at has no default_factory (ONEX time injection) CI Fix: - test_handler_vault_concurrency.py: Use itertools.cycle() instead of finite list for side_effect to avoid StopIteration in Python 3.12+ when retries exceed expected call count
Code Review: Registration Orchestrator Implementation [C1]This is a well-architected, production-ready implementation of the first orchestrator node in omnibase_infra. The code demonstrates excellent adherence to ONEX principles and establishes strong patterns for future orchestrators. ✅ Strengths1. Architectural Compliance
2. Code Quality
3. Test Coverage
4. Documentation Excellence
🔍 Code Quality ObservationsExcellent PatternsCorrelation ID Resolution Pattern# node_registration_orchestrator.py:72-90
def _resolve_correlation_id(
explicit: UUID | None,
envelope: ModelEventEnvelope[object],
) -> UUID:
"""Resolve correlation ID with clear precedence: explicit > envelope > generate."""
return explicit or getattr(envelope, "correlation_id", None) or uuid4()Why this is good: Clear resolution order, defensive State Machine Guards# handler_node_introspected.py:56-74
_RETRIABLE_STATES: frozenset[EnumRegistrationState] = frozenset({
EnumRegistrationState.LIVENESS_EXPIRED,
EnumRegistrationState.REJECTED,
EnumRegistrationState.ACK_TIMED_OUT,
})
_BLOCKING_STATES: frozenset[EnumRegistrationState] = frozenset({
EnumRegistrationState.PENDING_REGISTRATION,
EnumRegistrationState.ACCEPTED,
# ...
})Why this is good: Explicit FSM state sets improve maintainability and testability. Type Narrowing with Assertions# handler_runtime_tick.py:194-198
if not projection.needs_ack_timeout_event(now):
continue
ack_deadline = projection.ack_deadline
assert ack_deadline is not None, (
f"needs_ack_timeout_event() guarantees ack_deadline is not None: {projection.entity_id}"
)Why this is good: Defensive programming that helps type checkers and catches logic errors early. 🚨 Issues FoundCritical Issues: None ✅High Priority1. Missing Heartbeat Timestamp TrackingLocation: # TODO: Add last_heartbeat_at field to ModelRegistrationProjection
last_heartbeat_at = None # Hardcoded NoneIssue: Impact: Operators cannot determine when the last heartbeat was received during liveness expiry investigations. Recommendation:
Medium Priority2. Deduplication Logic Relies on Projection FilteringLocation: # Double-check with projection helper (defensive)
if not projection.needs_ack_timeout_event(now):
continueIssue: The handler trusts that Impact: If the projection reader has a bug, the defensive check might silently suppress events that should be investigated. Recommendation:
3. Envelope Type Parameter Uses
|
| Area | Coverage | Notes |
|---|---|---|
| Orchestrator routing | ✅ Excellent | All payload types tested |
| Handler state transitions | ✅ Excellent | All FSM states covered |
| Deduplication logic | ✅ Good | Projection helpers tested |
| Time injection | ✅ Excellent | Fixed timestamps used throughout |
| Error handling | Missing tests for projection query failures | |
| Integration tests | ✅ Excellent | Event bus, dispatch flow, schema validation |
| Performance tests | ✅ Excellent | Throughput, latency, load scenarios |
Missing Test Scenarios:
- What happens if
projection_reader.get_entity_state()raisesRuntimeHostError? - What happens if
get_overdue_ack_registrations()returns a projection withack_deadline=None? (Should be impossible, but defensive test would catch schema bugs)
💡 Recommendations
Must Fix Before Merge
- ✅ None - This PR is merge-ready as-is.
Should Fix Soon (Next PR)
- Track
last_heartbeat_atin projection schema (blocks liveness debugging) - Add error handling tests for projection query failures
- Document deduplication strategy in projection reader vs. handler
Nice to Have
- Extract correlation ID resolution to shared helper in convenience methods
- Add pagination for timeout event emission (if expecting >1000 nodes)
- Consider typed union for envelope payloads (improves type safety)
🏆 Overall Assessment
Rating: ⭐⭐⭐⭐⭐ (5/5 - Excellent)
This PR establishes a gold standard for ONEX orchestrators:
- Clean architecture with event-driven handlers
- Comprehensive test coverage (60 unit + integration + performance tests)
- Excellent documentation (2500+ lines of guides and runbooks)
- Strong adherence to ONEX principles (no Any, events-only, injected time)
The missing last_heartbeat_at field is the only significant gap, and it's already documented with a TODO. I recommend merging this PR and addressing the heartbeat tracking in a follow-up ticket.
Congratulations to the team on a stellar implementation! 🎉
📝 Checklist
- ✅ Code quality and best practices
- ✅ No critical bugs or issues
- ✅ Performance considerations addressed
- ✅ Security concerns evaluated
- ✅ Test coverage is comprehensive
- ✅ Documentation is excellent
- ✅ ONEX architectural compliance verified
Recommendation: ✅ APPROVE - Ready to merge.
…sts [OMN-952] ## PR Review Fixes Documentation: - Update "thread safety" terminology to "coroutine safety" in CLAUDE.md - Clarify concurrency model in CIRCUIT_BREAKER_THREAD_SAFETY.md - Update mixin docstrings for coroutine-safe async operations Test Fixes: - Add missing `timestamp` field to ModelEventHeaders in test fixtures - Fix division by zero guard in test_event_bus_load.py - Remove unused variables (success_after_open, handlers) - Convert unnecessary async make_handler to sync function - Update test date from 2024 to 2025 ## Kafka Integration Test Fixes - Add conftest.py with explicit topic creation fixtures - Update test_kafka_event_bus_integration.py to use topic fixtures - Update test_dlq_integration.py to use topic fixtures - Topics are now created via admin API before tests run - Proper cleanup of test topics after test completion This fixes all Kafka integration tests which were failing because the Redpanda broker has topic auto-creation disabled. Test Results: 4347 passed, 134 skipped
Pull Request Review: Registration Orchestrator Implementation [C1]SummaryThis PR implements the first orchestrator node in omnibase_infra, establishing critical patterns for event-driven registration workflows. The implementation is architecturally sound and adheres to ONEX principles, with strong declarative patterns and comprehensive testing. ✅ Strengths1. Excellent Adherence to Declarative Node PatternThe orchestrator correctly extends class NodeRegistrationOrchestrator(NodeOrchestrator):
def __init__(self, container: ModelONEXContainer) -> None:
super().__init__(container)
# Minimal initialization - behavior driven by contractImpact: Sets excellent precedent for future orchestrators. 2. Proper Container-Based Dependency InjectionThe code correctly uses
Compliance: ✅ CLAUDE.md Section "Container-Based Dependency Injection" 3. Strong Time Injection PatternAll handlers receive
Related: OMN-973 time injection via RuntimeTick 4. Comprehensive Test Coverage60 unit tests covering:
5. Excellent Documentation
6. Proper Error Handling
🔍 Code Quality Observations1. Handler Routing: Manual vs Contract-Driven
|
| Rule | Status | Evidence |
|---|---|---|
No Any types |
✅ | Uses ModelEventEnvelope[object] for generic payloads |
| Container injection | ✅ | def __init__(self, container: ModelONEXContainer) |
| One model per file | ✅ | All event models in separate files |
| PEP 604 unions | ✅ | Uses X | None not Optional[X] |
| Declarative nodes | Contract.yaml present but routing is manual (see issue #1) | |
| No versioned directories | ✅ | Flat structure, version in contract.yaml |
| Error hierarchy | ✅ | Propagates RuntimeHostError from projection reader |
| Correlation ID tracking | ✅ | All handlers accept and propagate correlation_id |
🎯 Recommendations
Priority 1 (Before Merge)
None - PR is merge-ready as-is.
Priority 2 (Follow-up Tickets)
- Extract routing logic to base class - Make orchestrators fully declarative
- Standardize container resolution - Simplify projection reader wiring
- Add database indexes - Optimize timeout scans for large clusters
- Extract correlation ID helper - Share across orchestrators
Priority 3 (Nice to Have)
- Add concurrency load tests
- Monitor projection query performance in production
- Consider batching timeout events if volume is high
🎉 Final Verdict
APPROVE ✅
This is excellent work that establishes strong patterns for ONEX orchestrators:
- Clean separation of concerns (handlers, orchestrator, projection)
- Proper dependency injection and time injection
- Comprehensive testing and documentation
- No critical bugs or security issues
The manual routing pattern is a minor deviation from ideal declarative design, but acceptable for the first orchestrator implementation. This should be addressed in future iterations as the base class matures.
Unblocks: C2 (Durable Timeout Handling), G2 (Orchestrator Tests) per PR description.
📚 References
- OMN-888: Registration Orchestrator (C1)
- OMN-930: ProtocolProjectionReader Integration
- OMN-973: Time Injection via RuntimeTick
- CLAUDE.md: Declarative Nodes, Container Injection patterns
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
tests/integration/event_bus/test_dlq_integration.py (1)
79-88: Remove unused fixturesunique_topicandunique_dlq_topic.These fixtures at lines 79-88 are not referenced anywhere in the test file. They have been replaced by
created_unique_topicandcreated_unique_dlq_topic. Removing them will clean up the code and prevent confusion.tests/integration/event_bus/test_kafka_event_bus_integration.py (1)
69-72: Remove the unusedunique_topicfixture.This fixture is superseded by
created_unique_topicfromconftest.py, which is used by all test methods in this file. The localunique_groupfixture should be retained as it is actively used.
🧹 Nitpick comments (8)
CLAUDE.md (1)
39-80: Clarify the declarative node pattern and base class responsibilities.The "CORRECT" example shows an entirely empty class with just
pass. While this aligns with the "no custom logic" principle, it may mislead developers who wonder where base class initialization, event deserialization, routing, and validation happen.Consider adding a brief note explaining:
- What the base class (
NodeOrchestrator, etc.) provides by default- Whether
super().__init__(container)or any initialization is required- Where contract.yaml-driven behavior is invoked (e.g., during
handle()or module load)- A realistic minimal example with required initialization (if any)
This would help developers understand the boundary between "contract-driven behavior" and "class boilerplate."
tests/performance/event_bus/test_event_bus_load.py (1)
237-251: Optional: Define handler once outside loops.The no-op handler is defined 1,000 times inside nested loops (lines 243-244). Since it doesn't capture any loop variables, it could be defined once before line 237 for slightly better efficiency. However, the current approach may intentionally stress-test handler cleanup, so this is a minor optimization.
🔎 Optional refactor
+ async def handler(msg: ModelEventMessage) -> None: + pass + # Add and remove many subscribers for iteration in range(100): unsubscribes = [] # Create 10 subscribers for i in range(10): - - async def handler(msg: ModelEventMessage) -> None: - pass - unsub = await bus.subscribe(topic, f"group-{iteration}-{i}", handler) unsubscribes.append(unsub)src/omnibase_infra/nodes/node_registration_orchestrator/contract.yaml (1)
1-434: Consider subcontract architecture for growing complexity.The contract.yaml file has grown to 434 lines with the addition of the comprehensive handler_routing section. While the current structure is well-organized and documented, the file now contains multiple concerns (workflow coordination, handler routing, event definitions, error handling, dependencies).
Based on learnings, complex contracts benefit from the subcontract architecture pattern, splitting into:
contract_actions.yaml(handler routing, workflow steps)contract_models.yaml(input/output models, event schemas)contract_validation.yaml(state transitions, validation rules)This would improve maintainability and modularity as the orchestrator evolves. However, if this monolithic structure better serves the orchestrator's unique requirements, document the deviation and justification in the node's README.md per project standards.
Based on learnings: Node contract architecture patterns recommend subcontract separation for complex nodes.
src/omnibase_infra/orchestrators/__init__.py (1)
27-27: Clarify the dual NodeRegistrationOrchestrator implementations and their distinct purposes.Verification confirms two separate
NodeRegistrationOrchestratorimplementations exist with genuinely different responsibilities:
- orchestrators/registration/node_registration_orchestrator.py: Event-driven orchestrator handling event routing (
handle(),handle_introspection(),handle_runtime_tick(),handle_registration_ack())- nodes/node_registration_orchestrator/node.py: Declarative orchestrator with timeout/heartbeat coordination (
set_timeout_coordinator(),set_heartbeat_handler()) that wraps workflow executionWhile the separation may be intentional, sharing the same class name across two independent modules creates import ambiguity and confusion about which implementation to use. Both are exported as public APIs via
__all__, making accidental cross-imports possible.Consider either: (a) renaming one to reflect its specific role (e.g.,
NodeRegistrationOrchestratorWithCoordination), or (b) consolidating into a single implementation with optional coordinator injection.tests/integration/event_bus/test_event_schema_validation.py (1)
43-56: Unused fixture missing requiredtimestampfield.The
sample_headersfixture creates a dictionary forModelEventHeadersbut omits the requiredtimestampfield. While this fixture doesn't appear to be used in the current file, it would fail if any test attempts to constructModelEventHeadersfrom it.Consider removing the unused fixture or adding the required
timestamp:🔎 Proposed fix
@pytest.fixture def sample_headers() -> dict[str, object]: """Create sample valid headers for testing.""" from omnibase_infra.event_bus.models import ModelEventHeaders return { "source": "test-service", "event_type": "test.event.created", "correlation_id": uuid4(), "trace_id": "trace-123", "span_id": "span-456", "priority": "normal", "schema_version": "1.0.0", + "timestamp": datetime(2025, 1, 1, tzinfo=UTC), }tests/integration/event_bus/conftest.py (3)
29-29: Hardcoded IP address may cause issues in different environments.The default
KAFKA_BOOTSTRAP_SERVERSvalue"192.168.86.200:29092"appears to be a specific development/test environment IP. This could cause confusion or failures when running tests in other environments. Consider using a more standard default like"localhost:9092"or documenting this requirement clearly.🔎 Proposed fix
-KAFKA_BOOTSTRAP_SERVERS = os.getenv("KAFKA_BOOTSTRAP_SERVERS", "192.168.86.200:29092") +KAFKA_BOOTSTRAP_SERVERS = os.getenv("KAFKA_BOOTSTRAP_SERVERS", "localhost:9092")
84-85: Deprecatedasyncio.get_event_loop()usage.
asyncio.get_event_loop()is deprecated since Python 3.10 and may emit warnings. Consider usingasyncio.get_running_loop()ortime.monotonic()for timing:🔎 Proposed fix
+ import time + async def _wait_for_topic_metadata( admin_client: AIOKafkaAdminClient, topic_name: str, timeout: float = 10.0, ) -> bool: - start_time = asyncio.get_event_loop().time() - while (asyncio.get_event_loop().time() - start_time) < timeout: + start_time = time.monotonic() + while (time.monotonic() - start_time) < timeout: try: description = await admin_client.describe_topics([topic_name]) if description: return True except Exception: pass await asyncio.sleep(0.5) return False
128-132: Consider logging exceptions for easier debugging.While ignoring exceptions for pre-existing topics is appropriate, logging them at debug level would help diagnose issues when topic creation fails for other reasons (e.g., permissions, quota).
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Lite
📒 Files selected for processing (18)
CLAUDE.mddocs/architecture/CIRCUIT_BREAKER_THREAD_SAFETY.mdsrc/omnibase_infra/mixins/__init__.pysrc/omnibase_infra/models/projection/model_registration_projection.pysrc/omnibase_infra/nodes/node_registration_orchestrator/contract.yamlsrc/omnibase_infra/orchestrators/__init__.pysrc/omnibase_infra/orchestrators/registration/__init__.pysrc/omnibase_infra/orchestrators/registration/handlers/__init__.pysrc/omnibase_infra/projectors/projection_reader_registration.pysrc/omnibase_infra/projectors/projector_registration.pysrc/omnibase_infra/validation/infra_validators.pytests/integration/event_bus/conftest.pytests/integration/event_bus/test_dlq_integration.pytests/integration/event_bus/test_event_schema_validation.pytests/integration/event_bus/test_kafka_event_bus_integration.pytests/integration/handlers/test_http_handler_integration.pytests/performance/event_bus/test_event_bus_load.pytests/unit/validation/test_validator_defaults.py
✅ Files skipped from review due to trivial changes (1)
- tests/integration/handlers/test_http_handler_integration.py
🚧 Files skipped from review as they are similar to previous changes (2)
- src/omnibase_infra/orchestrators/registration/handlers/init.py
- src/omnibase_infra/validation/infra_validators.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.py: NEVER useAnytypes in Python - Always use specific types, useobjectfor generic dispatchers instead
All data structures must be proper Pydantic models - one model per file
Use nullable type annotationX | None(PEP 604 union syntax) overOptional[X]for null types in Python
All services MUST useModelONEXContainerfor container-based dependency injection
Error classes must raiseOnexErrornot base Exception - useraise OnexError(...) from epattern
Never useisinstancefor protocol resolution - use duck typing through protocols instead
NEVER include passwords, API keys, tokens, secrets, full connection strings with credentials, PII, or private keys in error messages or context
Files:
src/omnibase_infra/projectors/projector_registration.pysrc/omnibase_infra/orchestrators/__init__.pysrc/omnibase_infra/mixins/__init__.pytests/integration/event_bus/test_kafka_event_bus_integration.pysrc/omnibase_infra/orchestrators/registration/__init__.pytests/performance/event_bus/test_event_bus_load.pysrc/omnibase_infra/models/projection/model_registration_projection.pytests/integration/event_bus/test_dlq_integration.pytests/integration/event_bus/test_event_schema_validation.pysrc/omnibase_infra/projectors/projection_reader_registration.pytests/unit/validation/test_validator_defaults.pytests/integration/event_bus/conftest.py
🧠 Learnings (52)
📚 Learning: 2025-11-30T21:55:10.298Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: Applies to src/metadata_stamping/database/**/*.py : Database layer MUST use connection pooling (10-50 connections), prepared statements, and circuit breaker pattern for resilience. Monitor pool exhaustion at >90% utilization.
Applied to files:
src/omnibase_infra/projectors/projector_registration.py
📚 Learning: 2025-11-30T21:55:10.298Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: Applies to src/metadata_stamping/database/**/*.py : All input validation MUST prevent SQL injection using prepared statements and parameterized queries. Use asyncpg for PostgreSQL operations.
Applied to files:
src/omnibase_infra/projectors/projector_registration.py
📚 Learning: 2025-12-25T19:10:27.034Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-25T19:10:27.034Z
Learning: Applies to **/*adapter*.py **/*handler*.py : Implement `MixinAsyncCircuitBreaker` for all external service integrations (Kafka, Consul, Vault, Redis, PostgreSQL) to provide automatic fault recovery
Applied to files:
src/omnibase_infra/projectors/projector_registration.pysrc/omnibase_infra/mixins/__init__.pydocs/architecture/CIRCUIT_BREAKER_THREAD_SAFETY.mdCLAUDE.md
📚 Learning: 2025-11-24T16:32:55.606Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T16:32:55.606Z
Learning: ORCHESTRATOR Nodes must inherit from `NodeOrchestrator` or use `NodeOrchestratorService` and must coordinate workflows, manage node interactions, and handle process/event orchestration
Applied to files:
src/omnibase_infra/orchestrators/__init__.pysrc/omnibase_infra/orchestrators/registration/__init__.py
📚 Learning: 2025-12-25T19:10:27.034Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-25T19:10:27.034Z
Learning: Applies to nodes/**/node.py : Node archetypes and I/O models must be imported from `omnibase_core.nodes`, never defined in infra - NodeEffect, NodeCompute, NodeReducer, NodeOrchestrator
Applied to files:
src/omnibase_infra/orchestrators/__init__.py
📚 Learning: 2025-12-03T16:55:49.755Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T16:55:49.755Z
Learning: Applies to agents/**/*.py : Implement ONEX-compliant agent architecture with four node types: Effect (External I/O), Compute (Pure transforms), Reducer (State/persistence), and Orchestrator (Workflow coordination)
Applied to files:
src/omnibase_infra/orchestrators/__init__.pyCLAUDE.md
📚 Learning: 2025-11-24T16:32:55.606Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T16:32:55.606Z
Learning: All ONEX nodes must conform to the 4-Node Architecture pattern with clear separation of concerns and unidirectional data flow (EFFECT → COMPUTE → REDUCER → ORCHESTRATOR)
Applied to files:
src/omnibase_infra/orchestrators/__init__.pyCLAUDE.md
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: All ONEX nodes must conform to the canonical structure, code generation, and interface patterns established in the `node_cli` node, using it as the primary source of truth for directory structure, contract schema patterns, linked document architecture, base state patterns, shared schema references, extensibility patterns, CLI interface declarations, code generation, dependency injection, error handling, testing, and documentation
Applied to files:
src/omnibase_infra/orchestrators/__init__.pyCLAUDE.md
📚 Learning: 2025-12-07T17:50:13.678Z
Learnt from: CR
Repo: OmniNode-ai/omniintelligence PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-07T17:50:13.678Z
Learning: Decompose intelligence operations into specialized ONEX nodes following a four-node pattern: Orchestrator (coordinate workflows), Reducer (manage state, FSM transitions), Compute (pure data processing), and Effect (external I/O)
Applied to files:
src/omnibase_infra/orchestrators/__init__.pyCLAUDE.md
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/contracts/contract_*.yaml : All ONEX node contract definitions must use the new subcontract architecture pattern, breaking down complex contracts into separate contract_actions.yaml, contract_models.yaml, contract_validation.yaml, and optional contract_cli.yaml and contract_capabilities.yaml files for separation of concerns, maintainability, reusability, modularity, and future tool-as-a-service readiness
Applied to files:
src/omnibase_infra/nodes/node_registration_orchestrator/contract.yamlCLAUDE.md
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/contract.yaml : All ONEX node contract definitions must follow the linked document architecture pattern with contract.yaml linking to node_config.yaml and deployment_config.yaml as associated documents
Applied to files:
src/omnibase_infra/nodes/node_registration_orchestrator/contract.yamlCLAUDE.md
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/contracts/contract_capabilities.yaml : All ONEX node execution capability definitions, if applicable, must be included in contract_capabilities.yaml with supported_node_types, supported_delivery_modes, and performance_constraints specifications
Applied to files:
src/omnibase_infra/nodes/node_registration_orchestrator/contract.yaml
📚 Learning: 2025-11-30T21:55:10.298Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: Applies to src/omninode_bridge/nodes/**/contract.yaml : All contract YAML files for ONEX v2.0 nodes MUST define subcontract references, input/output models, and FSM configurations. Use YAML 1.2 syntax.
Applied to files:
src/omnibase_infra/nodes/node_registration_orchestrator/contract.yaml
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/contract.yaml : All ONEX node contract schemas must use the canonical base state inheritance pattern with input_state containing only node-specific fields (inheriting from OnexInputState) and output_state containing only node-specific fields (inheriting from OnexOutputState)
Applied to files:
src/omnibase_infra/nodes/node_registration_orchestrator/contract.yamlCLAUDE.md
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/contract.yaml : All ONEX node contract definitions must support optional documents pattern with optional flag and required_capability field for future extensibility
Applied to files:
src/omnibase_infra/nodes/node_registration_orchestrator/contract.yaml
📚 Learning: 2025-11-24T16:32:55.606Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T16:32:55.606Z
Learning: Applies to **/*contract*.yaml : All ONEX nodes must have validated YAML contracts following the contract-driven development pattern with input_state and output_state schema definitions
Applied to files:
src/omnibase_infra/nodes/node_registration_orchestrator/contract.yaml
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: All ONEX node deviations from canonical patterns must be documented and justified in the node's root-level README.md and subject to maintainer review
Applied to files:
src/omnibase_infra/nodes/node_registration_orchestrator/contract.yamlCLAUDE.md
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/contracts/contract_cli.yaml : All ONEX node CLI interface definitions, if applicable, must be included in contract_cli.yaml with entrypoint and commands specifications
Applied to files:
src/omnibase_infra/nodes/node_registration_orchestrator/contract.yaml
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/introspection.py : All ONEX nodes must include an `introspection.py` file implementing standards-compliant introspection logic
Applied to files:
src/omnibase_infra/nodes/node_registration_orchestrator/contract.yaml
📚 Learning: 2025-11-24T17:22:32.195Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/canonical_patterns.mdc:0-0
Timestamp: 2025-11-24T17:22:32.195Z
Learning: Follow canonical patterns from reference implementations: use node_cli/v1_0_0/ as primary reference and node_kafka_event_bus/v1_0_0/ for complex backend patterns
Applied to files:
src/omnibase_infra/nodes/node_registration_orchestrator/contract.yaml
📚 Learning: 2025-11-30T21:55:10.298Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: Applies to src/omninode_bridge/events/**/*.py : Kafka event publishing MUST use OnexEnvelopeV1 format with 13 topics for event streaming at all workflow lifecycle stages
Applied to files:
src/omnibase_infra/nodes/node_registration_orchestrator/contract.yamltests/integration/event_bus/test_kafka_event_bus_integration.py
📚 Learning: 2025-11-30T21:55:10.298Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: Applies to src/omninode_bridge/nodes/**/*.py : Import mixins from omnibase_core.mixins.* and use Mixin* naming pattern (e.g., MixinHealthCheck, MixinMetrics, MixinEventBus) - never use local custom mixins unless experimental and documented
Applied to files:
src/omnibase_infra/mixins/__init__.py
📚 Learning: 2025-12-06T22:21:32.649Z
Learnt from: CR
Repo: OmniNode-ai/omniagent PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T22:21:32.649Z
Learning: Applies to nodes/**/*.py : Use event bus mixins from `omnibase_core` for Kafka publishing instead of direct Kafka clients
Applied to files:
src/omnibase_infra/mixins/__init__.pytests/integration/event_bus/test_kafka_event_bus_integration.pytests/integration/event_bus/test_dlq_integration.pytests/integration/event_bus/conftest.py
📚 Learning: 2025-11-24T16:32:55.606Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T16:32:55.606Z
Learning: Node implementations must use mixin-based composition from `omnibase_core.mixins` (e.g., `MixinHealthCheck`, `MixinNodeExecutor`) to add capabilities
Applied to files:
src/omnibase_infra/mixins/__init__.pyCLAUDE.md
📚 Learning: 2025-12-25T19:10:27.034Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-25T19:10:27.034Z
Learning: Applies to **/*adapter*.py **/*handler*.py : Circuit breaker methods REQUIRE caller to hold `_circuit_breaker_lock` - always use `async with self._circuit_breaker_lock:` before calling circuit breaker methods
Applied to files:
docs/architecture/CIRCUIT_BREAKER_THREAD_SAFETY.mdCLAUDE.md
📚 Learning: 2025-12-25T19:10:27.034Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-25T19:10:27.034Z
Learning: Applies to **/*dispatcher*.py **/*handler*.py : Dispatcher implementations do NOT require circuit breaker wrapping from engine - each dispatcher owns its own resilience through MixinAsyncCircuitBreaker
Applied to files:
docs/architecture/CIRCUIT_BREAKER_THREAD_SAFETY.mdCLAUDE.md
📚 Learning: 2025-12-25T19:10:27.034Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-25T19:10:27.034Z
Learning: Applies to **/*adapter*.py **/*handler*.py : Use circuit breaker pattern for `InfraUnavailableError` to prevent cascading failures - prevent requests when circuit is open, give service time to recover
Applied to files:
docs/architecture/CIRCUIT_BREAKER_THREAD_SAFETY.mdCLAUDE.md
📚 Learning: 2025-12-03T16:55:49.755Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T16:55:49.755Z
Learning: Applies to **/*.py : Publish intelligence requests to Kafka event bus using topics: dev.archon-intelligence.intelligence.code-analysis-{requested,completed,failed}.v1 for consistency and event-driven architecture
Applied to files:
tests/integration/event_bus/test_kafka_event_bus_integration.pytests/integration/event_bus/test_dlq_integration.pytests/integration/event_bus/conftest.py
📚 Learning: 2025-12-25T19:10:27.034Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-25T19:10:27.034Z
Learning: KafkaEventBus intentionally violates pattern validator thresholds (14 methods, 10 __init__ parameters) due to event bus pattern requirements and backwards compatibility - this is an accepted exception
Applied to files:
tests/integration/event_bus/test_kafka_event_bus_integration.pytests/integration/event_bus/test_dlq_integration.pytests/integration/event_bus/test_event_schema_validation.py
📚 Learning: 2025-12-07T17:50:13.678Z
Learnt from: CR
Repo: OmniNode-ai/omniintelligence PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-07T17:50:13.678Z
Learning: Implement Kafka event-driven architecture with proper topic naming using prefix dev.archon-intelligence. and proper event flow pattern with Effect nodes consuming events, processing, and publishing results with Dead Letter Queue routing
Applied to files:
tests/integration/event_bus/test_dlq_integration.py
📚 Learning: 2025-11-29T22:07:25.230Z
Learnt from: CR
Repo: OmniNode-ai/omniintelligence PR: 0
File: migration_sources/omniarchon/CLAUDE.md:0-0
Timestamp: 2025-11-29T22:07:25.230Z
Learning: Applies to migration_sources/omniarchon/**/tests/**/*.py : All integration tests must verify correct Kafka port usage for context (9092 for Docker, 29092 for host). Test both local (qdrant, memgraph) and remote (PostgreSQL, Redpanda) database connectivity. Never assume test environment configuration.
Applied to files:
tests/integration/event_bus/test_dlq_integration.pytests/integration/event_bus/conftest.py
📚 Learning: 2025-12-06T22:21:32.649Z
Learnt from: CR
Repo: OmniNode-ai/omniagent PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T22:21:32.649Z
Learning: OmniClaude imports agent routing logic, polymorphic coordination, and parallel execution from OmniAgent while maintaining Claude Code-specific components (shell hooks, skills system, adapter layer, .claude/ configuration) separately
Applied to files:
CLAUDE.md
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/*.py : All ONEX node implementations must follow dependency injection and protocol-first design patterns as established in the node_cli canonical reference
Applied to files:
CLAUDE.md
📚 Learning: 2025-11-28T18:58:53.781Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/canonical_patterns.mdc:0-0
Timestamp: 2025-11-28T18:58:53.781Z
Learning: Remove all backward compatibility patterns and legacy support code; use proper ONEX patterns from day one
Applied to files:
CLAUDE.md
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/models/error_codes.py : All ONEX node error handling must use auto-generated error codes defined in `models/error_codes.py` from contract definitions
Applied to files:
CLAUDE.md
📚 Learning: 2025-11-24T16:33:51.604Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-24T16:33:51.604Z
Learning: All Python code must have comprehensive test coverage following ONEX Core testing patterns with tests organized by domain, using proper fixtures, and achieving high coverage while maintaining code quality
Applied to files:
CLAUDE.md
📚 Learning: 2025-12-25T19:10:27.034Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-25T19:10:27.034Z
Learning: Applies to **/*adapter*.py **/*handler*.py : Use `InfraConnectionError` for connection failures, with transport-aware error codes (DATABASE_CONNECTION_ERROR for database, NETWORK_ERROR for HTTP/GRPC, SERVICE_UNAVAILABLE for Kafka/Consul/Vault/Valkey)
Applied to files:
CLAUDE.md
📚 Learning: 2025-12-25T19:10:27.033Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-25T19:10:27.033Z
Learning: Applies to **/*adapter*.py **/*handler*.py : Use `EnumInfraTransportType` to specify transport type in error context (HTTP, DATABASE, KAFKA, CONSUL, VAULT, VALKEY, GRPC)
Applied to files:
CLAUDE.md
📚 Learning: 2025-12-25T19:10:27.033Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-25T19:10:27.033Z
Learning: Applies to **/*adapter*.py **/*handler*.py **/*service*.py : Use `ModelInfraErrorContext` with `transport_type` when raising infrastructure errors
Applied to files:
CLAUDE.md
📚 Learning: 2025-12-25T19:10:27.034Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-25T19:10:27.034Z
Learning: Applies to **/*adapter*.py **/*handler*.py : Use `InfraUnavailableError` for service unavailable conditions, including when circuit breaker is open
Applied to files:
CLAUDE.md
📚 Learning: 2025-12-25T19:10:27.034Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-25T19:10:27.034Z
Learning: Applies to **/*adapter*.py **/*handler*.py : Use graceful degradation for `InfraTimeoutError` - fallback to secondary data source (cache, secondary database) when primary times out
Applied to files:
CLAUDE.md
📚 Learning: 2025-12-25T19:10:27.034Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-25T19:10:27.034Z
Learning: Applies to **/*adapter*.py **/*handler*.py : Use `InfraTimeoutError` for operation timeouts
Applied to files:
CLAUDE.md
📚 Learning: 2025-12-25T19:10:27.034Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-25T19:10:27.034Z
Learning: Applies to **/*adapter*.py **/*handler*.py : Use `InfraAuthenticationError` for authentication/authorization failures
Applied to files:
CLAUDE.md
📚 Learning: 2025-12-25T19:10:27.034Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-25T19:10:27.034Z
Learning: Applies to **/mixin_*.py nodes/**/node.py : Use `@(<operation_keywords>)` pattern matching for method filtering in node introspection, filtering out private methods (prefixed with `_`) and utility methods (get_*, set_*, initialize*, start_*, stop_*)
Applied to files:
CLAUDE.md
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/models/model_contract_*.py : All ONEX node auto-generated Pydantic models must be organized in a `models/` directory with files for state.py, model_contract_actions.py, model_contract_models.py, model_contract_validation.py, model_contract_cli.py (optional), model_contract_capabilities.py (optional), and error_codes.py, generated from the corresponding contract definitions
Applied to files:
CLAUDE.md
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/contracts/contract_*.yaml : All ONEX node subcontracts must be organized in a `contracts/` subdirectory within the versioned implementation directory with separate files for contract_actions.yaml, contract_models.yaml, contract_validation.yaml, contract_cli.yaml (optional), and contract_capabilities.yaml (optional)
Applied to files:
CLAUDE.md
📚 Learning: 2025-12-07T17:50:13.678Z
Learnt from: CR
Repo: OmniNode-ai/omniintelligence PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-07T17:50:13.678Z
Learning: Applies to **/nodes/**/*compute*.py : Enforce ONEX node purity by preventing compute nodes from importing network/database clients (confluent_kafka, httpx, asyncpg, etc.), accessing environment variables (os.environ, os.getenv), or performing file system operations (open(), Path.read_text(), FileHandler)
Applied to files:
CLAUDE.md
📚 Learning: 2025-12-07T17:50:13.678Z
Learnt from: CR
Repo: OmniNode-ai/omniintelligence PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-07T17:50:13.678Z
Learning: Organize tests following the structure: tests/conftest.py for shared fixtures, tests/unit/ for unit tests (no infrastructure), tests/integration/ for integration tests (requires Kafka/DBs), tests/nodes/ for node-specific tests
Applied to files:
tests/integration/event_bus/conftest.py
📚 Learning: 2025-11-24T16:33:51.604Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-24T16:33:51.604Z
Learning: Applies to tests/**/conftest.py : Test fixtures must be defined in `conftest.py` and should provide reusable sample data, UUIDs, semantic versions, and model data
Applied to files:
tests/integration/event_bus/conftest.py
📚 Learning: 2025-11-24T17:24:54.193Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-24T17:24:54.193Z
Learning: Applies to **/*test*.py : Use context-based fixtures with pytest.param and conditional dependency injection (e.g., UNIT_CONTEXT vs INTEGRATION_CONTEXT) for mock and integration tests
Applied to files:
tests/integration/event_bus/conftest.py
📚 Learning: 2025-11-29T17:13:38.776Z
Learnt from: CR
Repo: OmniNode-ai/omniarchon PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-29T17:13:38.776Z
Learning: Applies to **/*.py : All Kafka topics must use the prefix `dev.archon-intelligence` for development/staging environments.
Applied to files:
tests/integration/event_bus/conftest.py
📚 Learning: 2025-12-03T16:55:49.755Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T16:55:49.755Z
Learning: Applies to scripts/tests/**/*.sh : Implement comprehensive test suites in scripts/tests/ with separate test files for Kafka, PostgreSQL, Intelligence, and Routing functionality
Applied to files:
tests/integration/event_bus/conftest.py
🧬 Code graph analysis (7)
src/omnibase_infra/orchestrators/__init__.py (2)
src/omnibase_infra/nodes/node_registration_orchestrator/node.py (1)
NodeRegistrationOrchestrator(124-321)src/omnibase_infra/orchestrators/registration/node_registration_orchestrator.py (1)
NodeRegistrationOrchestrator(116-494)
src/omnibase_infra/mixins/__init__.py (3)
src/omnibase_infra/mixins/mixin_node_introspection.py (3)
IntrospectionCacheDict(246-271)MixinNodeIntrospection(274-1974)PerformanceMetricsCacheDict(215-243)src/omnibase_infra/mixins/protocol_event_bus_like.py (1)
ProtocolEventBusLike(23-48)src/omnibase_infra/models/discovery/model_introspection_config.py (1)
ModelIntrospectionConfig(57-265)
tests/integration/event_bus/test_kafka_event_bus_integration.py (1)
tests/integration/event_bus/conftest.py (3)
created_unique_topic(152-171)created_broadcast_topic(193-203)ensure_test_topic(38-148)
src/omnibase_infra/orchestrators/registration/__init__.py (5)
src/omnibase_infra/orchestrators/registration/handlers/handler_node_heartbeat.py (2)
HandlerNodeHeartbeat(102-321)ModelHeartbeatHandlerResult(49-99)src/omnibase_infra/orchestrators/registration/handlers/handler_node_introspected.py (1)
HandlerNodeIntrospected(77-214)src/omnibase_infra/orchestrators/registration/handlers/handler_node_registration_acked.py (1)
HandlerNodeRegistrationAcked(69-294)src/omnibase_infra/orchestrators/registration/handlers/handler_runtime_tick.py (1)
HandlerRuntimeTick(62-299)src/omnibase_infra/nodes/node_registration_orchestrator/node.py (1)
NodeRegistrationOrchestrator(124-321)
tests/performance/event_bus/test_event_bus_load.py (3)
tests/performance/event_bus/conftest.py (3)
event_bus(38-51)generate_unique_topic(203-209)sample_message_bytes(94-100)src/omnibase_infra/event_bus/inmemory_event_bus.py (3)
InMemoryEventBus(69-692)get_event_history(572-598)get_subscriber_count(609-621)src/omnibase_infra/event_bus/models/model_event_message.py (1)
ModelEventMessage(14-60)
tests/integration/event_bus/test_dlq_integration.py (1)
tests/integration/event_bus/conftest.py (2)
created_unique_dlq_topic(175-189)created_unique_topic(152-171)
tests/integration/event_bus/test_event_schema_validation.py (2)
src/omnibase_infra/event_bus/models/model_event_headers.py (2)
ModelEventHeaders(16-123)validate_headers(117-123)src/omnibase_infra/event_bus/models/model_event_message.py (2)
ModelEventMessage(14-60)ack(55-60)
🔇 Additional comments (45)
docs/architecture/CIRCUIT_BREAKER_THREAD_SAFETY.md (4)
1-11: Excellent clarification of coroutine safety vs thread safety terminology.The rebranding and distinction between asyncio.Lock (coroutine safety within a single event loop) and threading.Lock (thread safety across OS threads) is critically important and well-articulated. This accurately reflects the runtime model and aligns perfectly with the PR's emphasis on coroutine-safe patterns throughout the codebase.
31-46: Clear documentation of the caller-held locking pattern.The "Correct Usage" and "Incorrect Usage" examples clearly communicate the non-negotiable requirement to hold the lock before calling circuit breaker methods. This directly supports the learnings on circuit breaker implementation constraints and should help prevent misuse.
88-134: Excellent VaultHandler integration example.The five-step pattern (circuit breaker check, success recording, failure recording, shutdown reset, health check) is comprehensive and demonstrates proper caller-held lock usage in real contexts. This provides a reference implementation that developers can follow.
197-207: Verify the < 10us performance measurement is representative.The claim of < 10us overhead per circuit breaker operation is specific. Confirm this measurement reflects actual asyncio.Lock performance in your infrastructure environment, especially under contention or within heavy I/O workloads. If these are estimates or benchmarks from a specific scenario, consider documenting the measurement methodology or conditions.
tests/unit/validation/test_validator_defaults.py (1)
56-68: LGTM! Threshold updates are well-documented and consistent.The threshold history and assertion updates are properly coordinated. The documentation clearly tracks the evolution from 620 to 630, with the ~626 baseline and appropriate buffer. The small buffer (4 unions) indicates close monitoring of union count growth, which aligns with the stated goal of eventual reduction to <200 through ongoing migrations.
src/omnibase_infra/models/projection/model_registration_projection.py (3)
9-13: Documentation improvement: Concurrency Safety clarification.The updated header correctly distinguishes between coroutine-safety (asyncio.Lock) and thread-safety (threading.Lock), providing clearer guidance for callers. This is more precise than the previous "Thread Safety" label.
66-66: Documentation improvement: last_heartbeat_at clarification.The added clarification "(None if never received, for liveness reporting)" helpfully explains the None state semantics.
141-141: Documentation improvement: Field description consistency.The Field description matches the docstring clarification at line 66, maintaining consistency throughout the model documentation.
CLAUDE.md (6)
1-24: LGTM!The Quick Start and Agent-Driven Development section clearly establishes mandatory patterns with appropriate task categorization. The guidance is actionable and aligns well with the PR's shift to contract-driven development.
25-37: LGTM!The critical policies are well-articulated with clear formatting. The "No Versioned Directories" guidance and prohibition on background agents provide strong, actionable guardrails aligned with the PR's contract-first architecture.
82-131: LGTM!The Core ONEX Principles section is well-structured with clear naming conventions, strong typing guidance, and explicit container DI requirements. The recommendation to use
objectinstead ofAnyand PEP 604 unions is modern and enforces type safety effectively.
139-318: LGTM!The infrastructure error patterns and circuit breaker implementation guidance are comprehensive and production-ready. The detailed configuration examples, monitoring patterns, and the elegant resolution of the "no Any" rule via
ModelEventEnvelope[object]demonstrate thoughtful API design. The separation of concerns for dispatcher resilience (dispatchers own their resilience, engine does not wrap them) is clearly articulated.
381-562: LGTM!The Node Introspection Security section is exceptionally thorough, with a well-reasoned threat model, clear exposure surface documentation, and practical deployment guidance. The new concurrency safety section (lines 511–560) is particularly valuable—it clearly distinguishes single-threaded asyncio coroutine safety from multi-threaded thread safety, explains cache semantics, and provides migration patterns for multi-threaded contexts. This prevents a common source of bugs when developers assume asyncio code is automatically thread-safe.
577-622: LGTM!The Node Structure and Zero Tolerance sections provide clear canonical patterns and explicit enforcement of key policies. The contract requirements table is well-organized and the agent architecture reference maintains consistency with earlier sections.
tests/performance/event_bus/test_event_bus_load.py (10)
1-41: LGTM: Clean imports and comprehensive documentation.The module header, docstring, and imports are well-structured. Type hints properly use
collections.abcfor generic types, and there are noAnytypes.
98-104: Past issue resolved: Division by zero guard added.The guard against division by zero (lines 100-103) correctly addresses the previous review comment. The code now safely handles the edge case where
avg_countmight be zero.
117-171: LGTM: Proper concurrency handling with asyncio.Lock.The test correctly uses
asyncio.Lockto protect shared state (received_count) across async handler invocations. The logic validates that all published messages are received by the subscriber.
183-222: LGTM: Validates history bounding correctly.The test properly validates that the event bus respects the
max_historylimit by publishing 10x the limit and asserting the history size remains bounded.
263-314: LGTM: Sound memory leak detection approach.The test uses forced garbage collection and object count tracking to detect memory leaks. The conservative threshold (< 0.1 objects per operation) ensures the system doesn't leak memory under sustained load.
326-391: LGTM: Correct factory pattern for handler closures.The test properly uses a factory function (
make_handler, lines 350-357) to capture the loop index in each handler's closure. This is the correct pattern to avoid late-binding issues with loop variables in Python closures.
392-459: LGTM: Multi-topic scalability test is well-structured.The test correctly validates cross-topic subscriber behavior using proper factory functions for closures and appropriate data structures (dict.fromkeys for initialization).
471-527: LGTM: Validates resilience to subscriber errors.The test correctly verifies that a failing subscriber doesn't prevent other subscribers from receiving messages. The high circuit breaker threshold ensures the test focuses on error isolation rather than circuit breaking.
528-580: Past issue resolved: Unused variable removed.The previously mentioned unused variable
success_after_openhas been removed. The test now correctly validates circuit breaker behavior by checking that the circuit opens after reaching the failure threshold.
581-628: LGTM: Properly tests graceful shutdown under load.The test correctly uses asyncio tasks to simulate concurrent publishing during shutdown. The shutdown time assertion (< 1 second) validates that the event bus can cleanly shut down even during active operations.
src/omnibase_infra/projectors/projection_reader_registration.py (1)
9-15: LGTM: Documentation clarification enhances understanding.The renaming from "Thread Safety" to "Concurrency Safety" with explicit mention of coroutine-safety and the asyncio.Lock mechanism provides clearer guidance for users of this component. The note about thread-safety limitations is helpful.
src/omnibase_infra/projectors/projector_registration.py (1)
10-16: LGTM: Consistent concurrency documentation.The documentation update matches the pattern from
projection_reader_registration.py, providing consistent terminology and clarity across projection components. The coroutine-safety guarantees align with asyncpg's characteristics.src/omnibase_infra/nodes/node_registration_orchestrator/contract.yaml (1)
221-329: Well-structured handler routing configuration.The new
handler_routingsection is comprehensive and clearly documented:
- Explicit routing strategy declaration
- Thorough state decision matrices for each handler
- Well-defined output events and dependencies
- Clear separation of concerns between handlers
The documentation explaining payload-based routing and the distinction between event_type names (consumed_events) and model class names (handler_routing) is particularly helpful.
src/omnibase_infra/orchestrators/__init__.py (1)
3-35: LGTM! Clean export structure with comprehensive documentation.The module docstring effectively describes ONEX orchestrator constraints (event-only emissions, time injection, no I/O), and the export of
NodeRegistrationOrchestratoris properly structured with correct type annotations.src/omnibase_infra/orchestrators/registration/__init__.py (1)
39-59: LGTM! Well-structured registration orchestrator package exports.The module properly exports the registration orchestrator and its associated handlers with comprehensive documentation. The import structure is clean, all exports are properly listed in
__all__, and type annotations follow conventions.src/omnibase_infra/mixins/__init__.py (1)
6-6: LGTM - Accurate terminology update.The change from "Thread-safe" to "Coroutine-safe" is technically correct.
asyncio.Lockprovides synchronization for coroutines within a single event loop, not for multi-threaded access. The explicit mention ofasyncio.Lockadds helpful clarity.tests/integration/event_bus/test_event_schema_validation.py (4)
75-294: LGTM!Comprehensive test coverage for
ModelEventHeadersvalidation. All tests correctly use timezone-aware timestamps as required by the model, and the tests properly verify required fields, defaults, immutability, and validation constraints.
301-450: LGTM!Well-structured tests for
ModelEventMessagevalidation covering required fields, immutability, and schema constraints. Theack()method test correctly verifies the async no-op behavior.
544-680: LGTM!Thorough tests for header completeness through publish/subscribe cycles. Custom headers are correctly constructed with timezone-aware timestamps, and the sequential message uniqueness test properly validates distinct IDs.
688-765: LGTM!Serialization tests correctly verify JSON round-trip for both headers and messages, ensuring schema stability across serialization boundaries.
tests/integration/event_bus/test_dlq_integration.py (5)
31-32: LGTM!Appropriate imports added for the new typing hints and timestamp handling required by the fixture and model changes.
97-132: LGTM!The fixture correctly uses the pre-created DLQ topic, ensuring topic existence before bus operations on brokers with auto-creation disabled.
276-310: LGTM!Test correctly updated to use the pre-created DLQ topic and includes the required timestamp in headers.
322-416: LGTM!The DLQ publish test correctly uses pre-created topics and timezone-aware timestamps. The test flow properly validates handler failure leading to DLQ message delivery.
648-715: LGTM!Good practice using direct
_publish_to_dlqcall for deterministic metric testing as noted in the PR #90 feedback. Assertions properly verify all metric increments including per-topic counts.tests/integration/event_bus/conftest.py (2)
151-203: LGTM!Well-structured convenience fixtures that combine topic name generation with automatic creation. The docstrings clearly explain usage patterns with helpful examples.
206-276: LGTM!The
topic_factoryfixture provides flexibility for custom topic configurations while following the same cleanup pattern asensure_test_topic.tests/integration/event_bus/test_kafka_event_bus_integration.py (4)
25-26: LGTM!Appropriate imports added for typing hints and timestamp handling.
200-255: LGTM!Test correctly updated to use the pre-created topic fixture, ensuring reliable message delivery on brokers with auto-creation disabled.
624-683: LGTM!Header round-trip test correctly includes timezone-aware timestamp in custom headers and properly validates header preservation through the publish/subscribe cycle.
805-854: LGTM!Good improvement to pre-create the group topic via
ensure_test_topicbefore subscribing. This ensures test reliability on brokers without auto-topic-creation.
Address all PR review feedback including critical, major, minor, and nitpick issues: **Time Injection & Docstrings:** - Fix docstring examples to use explicit timestamps instead of datetime.now() - Add time injection pattern comments to event model examples - Update handler docstrings with explicit timestamp examples **Terminology & Code Quality:** - Update "Thread Safety" → "Coroutine Safety" across 10 files - Remove unused imports from mixins/__init__.py - Fix discover_capabilities_ms never being populated **Tests:** - Add missing timestamp fields to validation rejection tests - Convert async make_handler() to sync where not needed - Remove unused handlers variable **Documentation:** - Fix event_type naming: ModelNodeHeartbeatEvent → NodeHeartbeatEvent - Add DUAL IMPLEMENTATION NOTE to both orchestrator implementations - Add subcontract architecture comments to contract.yaml - Add registered_at to dispatch __init__.py docstring example
PR Review: Registration Orchestrator Implementation [C1]Overall AssessmentThis is an excellent implementation of the first orchestrator node in omnibase_infra. The PR successfully implements the registration orchestrator following ONEX principles with strong architectural discipline. The dual orchestrator pattern (declarative + imperative) is well-justified and properly documented. ✅ Strengths1. Exemplary ONEX Compliance
2. Dual Orchestrator PatternThe PR includes two
This is well-documented in both files (lines 5-26) explaining the rationale. The imperative version provides backward compatibility and explicit control for tests, while the declarative version represents the target ONEX architecture. 3. Strong Error Handling
4. Excellent Documentation
5. Test Coverage
🔍 Issues FoundCritical IssuesNone - No critical blocking issues found. High Priority1. Inconsistent Correlation ID Handling
|
- Standardize docstring examples to use `from datetime import UTC` pattern - Remove unused imports (F401): ModelRegistrationProjection, uuid4, ProtocolEventBusLike, ModelTimeoutEmissionResult, ModelTimeoutQueryResult - Update MVP_EVENT_CATALOG.md date to 2025-12-26
… [OMN-952] Resolve conflicts: - mixin_async_circuit_breaker.py: Keep coroutine-safe terminology with typed signatures - test_registration_reducer.py: Use shared create_introspection_event from tests.helpers - conftest.py: Use shared create_introspection_event from tests.helpers
PR Review: Registration Orchestrator Implementation [C1]OverviewThis PR implements the first orchestrator node in omnibase_infra, establishing the foundation for event-driven registration workflows. The implementation follows ONEX architectural patterns with strong typing, declarative contracts, and proper event-driven design. ✅ Strengths1. Excellent ONEX Compliance
2. Robust Handler DesignThe three core handlers are well-designed:
3. Excellent Documentation
4. Comprehensive Testing
5. Good Error Handling
|
- Delete imperative NodeRegistrationOrchestrator (dual implementation violation) - Removed orchestrators/registration/node_registration_orchestrator.py - Removed associated test file - Updated __init__.py exports to point to declarative version - Add TODO comment to contract.yaml noting complexity (~460 lines) - Suggests extracting handler_routing, error_recovery, timeout_config - Make DEFAULT_LIVENESS_INTERVAL_SECONDS configurable - Added get_liveness_interval_seconds() helper function - Supports ONEX_LIVENESS_INTERVAL_SECONDS env var - Constant remains as fallback default - Added 6 tests for configuration resolution
🔍 Pull Request Review - C1: Registration OrchestratorSummaryThis PR implements the first orchestrator node in omnibase_infra following the ONEX declarative pattern. The implementation is architecturally sound and demonstrates excellent adherence to ONEX principles. I've identified several areas for improvement across code quality, architecture, and testing. ✅ Strengths1. Excellent Declarative ArchitectureThe node follows the ONEX declarative pattern perfectly:
class NodeRegistrationOrchestrator(NodeOrchestrator):
"""Declarative orchestrator - all behavior defined in contract.yaml."""
pass # Perfect - no custom code2. Strong Type SafetyConsistent use of Pydantic models throughout:
3. Comprehensive DocumentationOutstanding documentation quality:
4. Excellent Test Coverage
5. Time Injection PatternPerfect implementation of deterministic time handling:
🔴 Critical Issues1. Missing Error Context in Handlers (PRIORITY: HIGH)The handlers don't create Location: Current: projection = await self._projection_reader.get_entity_state(
entity_id=node_id,
domain="registration",
correlation_id=correlation_id,
)
# If this fails, error has no handler-specific contextRecommended: from omnibase_infra.errors import InfraConnectionError, ModelInfraErrorContext
from omnibase_infra.enums import EnumInfraTransportType
try:
projection = await self._projection_reader.get_entity_state(
entity_id=node_id,
domain="registration",
correlation_id=correlation_id,
)
except Exception as e:
context = ModelInfraErrorContext(
transport_type=EnumInfraTransportType.DATABASE,
operation="get_entity_state",
correlation_id=correlation_id,
)
raise InfraConnectionError(
"Failed to query registration projection",
context=context,
) from eAlso affects:
2. Inconsistent Correlation ID Handling (PRIORITY: HIGH)Some handlers don't auto-generate correlation IDs when missing: Location: Issue: causation_id=event.correlation_id, # What if event.correlation_id is None?Per CLAUDE.md:
Recommended: from uuid import uuid4
causation_id = event.correlation_id or uuid4()Also check: All three handlers for consistent correlation ID handling 🟡 Major Issues3. Handler State Decision Logic Not Defensive (PRIORITY: MEDIUM)Location: The handler assumes all states are either in if current_state in _RETRIABLE_STATES:
should_initiate = True
elif current_state in _BLOCKING_STATES:
should_initiate = False
# What if current_state is neither? Falls through silentlyRecommended: if current_state in _RETRIABLE_STATES:
should_initiate = True
elif current_state in _BLOCKING_STATES:
should_initiate = False
else:
# Defensive: Log unexpected state and default to safe behavior
logger.warning(
"Unexpected registration state, defaulting to no-op",
extra={"node_id": str(node_id), "state": str(current_state)},
)
should_initiate = False4. Circuit Breaker Not Used in Handlers (PRIORITY: MEDIUM)Per CLAUDE.md, handlers that query external services should use circuit breaker pattern: Location: All three handlers query projection reader without circuit breaker Current: Direct projection queries without resilience Recommendation: 5. Missing Assertions in Type Narrowing (PRIORITY: LOW)Location: Good defensive programming, but could be clearer: Current: assert ack_deadline is not None, (
f"needs_ack_timeout_event() guarantees ack_deadline is not None: "
f"{projection.entity_id}"
)Recommended: Add comment explaining this is type narrowing for mypy: # Type narrowing: needs_ack_timeout_event() guarantees ack_deadline is not None
# This assert helps mypy understand the invariant
assert ack_deadline is not None, (
f"Invariant violation: ack_deadline must be set when needs_ack_timeout_event() returns True. "
f"node_id={projection.entity_id}"
)🟢 Minor Issues / Nitpicks6. Contract.yaml Complexity (PRIORITY: LOW)Location: The contract includes a TODO about extracting sections to subcontracts. At 466 lines, this is reasonable, but the plan is sound: Recommendation:
7. Logging Level Inconsistency (PRIORITY: LOW)Location: Mix of
Recommendation: Use 8. Frozen Set Performance (PRIORITY: NEGLIGIBLE)Location: Using # Frozen sets provide O(1) membership testing and immutability guarantees
# for these constant state collections used in hot code paths
_RETRIABLE_STATES: frozenset[EnumRegistrationState] = frozenset({...})🔒 Security Review✅ No Security Issues Found
🧪 Test Coverage Review✅ Excellent CoverageUnit Tests (
Integration Tests:
Performance Tests:
Recommendation: Add edge case tests for:
📊 Performance ConsiderationsPotential Optimizations (Future Work)
📝 CLAUDE.md Compliance✅ Full Compliance
🎯 Recommendations SummaryBefore Merge (Critical):
Follow-Up (Post-Merge):
🏆 Overall AssessmentRating: ⭐⭐⭐⭐ (4/5 - Excellent with minor improvements needed) This is high-quality work that establishes an excellent pattern for future orchestrators. The declarative architecture, comprehensive testing, and documentation are exemplary. The critical issues are straightforward to address and don't affect the core design. Recommendation: ✅ Approve with requested changes The requested changes (error context, correlation ID handling, defensive state checks) are important for production robustness but don't require architectural changes. Once addressed, this PR is ready to merge. Review completed using ONEX standards from CLAUDE.md. Great work on the first orchestrator! 🚀 |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/omnibase_infra/nodes/node_registration_orchestrator/timeout_coordinator.py (1)
158-197: DocstringRaisessection doesn’t matchcoordinateimplementation
TimeoutCoordinator.coordinatecatches all exceptions, logs them, and returns aModelTimeoutCoordinationResult(success=False, error=...), but the docstring still advertises thatInfraConnectionError,InfraTimeoutError, andInfraUnavailableErrormay be raised. Either:
- Let those infra exceptions propagate (and only catch/log non-infra errors), or
- Update the Raises section to describe the current behavior (no exceptions, error encoded in the result).
Right now callers relying on the documented exceptions will never see them.
Also applies to: 219-364
🧹 Nitpick comments (6)
src/omnibase_infra/event_bus/inmemory_event_bus.py (1)
368-384: Consider simplifying the envelope serialization pattern.The current pattern uses
hasattrfollowed bygetattrto access methods:if hasattr(envelope, "model_dump"): model_dump_method = envelope.model_dump envelope_dict = model_dump_method(mode="json")This can be simplified to direct attribute access after the
hasattrcheck:if hasattr(envelope, "model_dump"): envelope_dict = envelope.model_dump(mode="json") elif hasattr(envelope, "dict"): envelope_dict = envelope.dict()The intermediate variable assignment adds no type safety benefit and makes the code more verbose.
🔎 Proposed simplification
envelope_dict: object if hasattr(envelope, "model_dump"): - # Use getattr for type-safe method access after hasattr check - model_dump_method = envelope.model_dump - envelope_dict = model_dump_method(mode="json") + envelope_dict = envelope.model_dump(mode="json") elif hasattr(envelope, "dict"): - # Use getattr for type-safe method access after hasattr check - dict_method = envelope.dict - envelope_dict = dict_method() + envelope_dict = envelope.dict() elif isinstance(envelope, dict): envelope_dict = envelopesrc/omnibase_infra/event_bus/kafka_event_bus.py (2)
400-420: Clarify scope of_lockcomment vs other locksThe comment says the lock “protects all shared state”, but several shared structures use their own locks (
_producer_lock,_dlq_metrics_lock,_dlq_callbacks_lock). Consider rewording to “primary state lock” (or similar) to avoid implying it is the only synchronization primitive.
858-865: Explicit header timestamps are consistent with newModelEventHeaderscontractAll call sites now pass an explicit, timezone-aware
timestampwhen constructingModelEventHeaders(including publish, envelope publish, broadcast, group send, and DLQ headers), which is required by the updated header model and its validator. The only tradeoff is tight coupling todatetime.now(UTC)at the event bus layer; if you later need fully deterministic timing in tests, you might want to inject a clock into this class instead of callingdatetime.now(UTC)directly.Also applies to: 1051-1056, 1484-1489, 1512-1517, 1919-1925, 2199-2205
src/omnibase_infra/mixins/mixin_node_introspection.py (1)
1193-1204: Explicit timestamps on introspection and heartbeat eventsBoth
ModelNodeIntrospectionEventandModelNodeHeartbeatEventnow receive an explicit, timezone-awaretimestamp(usingdatetime.now(UTC)), which matches the new event schemas and enforces tz-awareness. If you later need deterministic timing (e.g., with aDeterministicClock), consider threading a clock dependency into this mixin so callers can overridenow, but the current approach is correct and safe.Also applies to: 1383-1399
src/omnibase_infra/nodes/node_registration_orchestrator/contract.yaml (1)
4-33: Consider the TODO for future refactoring (optional).The TODO comment (lines 5-33) provides excellent guidance for extracting sections into subcontracts as complexity grows. Current size (~460 lines) is manageable, but the extraction candidates are well-identified:
- handler_routing section (246 lines) → routing_subcontract
- consumed_events/published_events → event_subcontract
- coordination_rules → state_subcontract
This is good architectural documentation. No immediate action required, but the guidance will be valuable when the contract grows beyond ~600 lines.
tests/performance/event_bus/test_event_bus_throughput.py (1)
191-201: Misleading "batch pattern" comment — this is sequential execution.The comment states "Execute sequentially (batch pattern)" but this is contradictory. Creating coroutines in a list then awaiting them one-by-one is functionally identical to a regular sequential
forloop. For actual batch/concurrent execution, useasyncio.gather():🔎 Suggested fix for true batch execution
- tasks = [ + # Execute concurrently (actual batch pattern) + await asyncio.gather(*[ event_bus.publish( topic=topic, key=f"key-{i}".encode(), value=sample_message_bytes, ) for i in range(100) - ] - # Execute sequentially (batch pattern) - for task in tasks: - await task + ])Alternatively, if sequential execution is intentional for this test, update the comment to reflect the actual behavior.
…952] Time injection & documentation: - Add UTC import and update docstring example in model_event_headers.py - Fix timestamp field documentation in MVP_EVENT_CATALOG.md - Update protocol_runtime_scheduler.py examples with correct fields - Enhance handler_runtime_tick.py docstring for time injection pattern Terminology consistency (thread-safe → coroutine-safe): - Update contract.yaml, README.md, and validation_exemptions.yaml - Align terminology with asyncio concurrency model Cleanup: - Remove unused ModelIntrospectionConfig re-export from mixins/__init__.py - Remove unused imports in test files
Merge origin/main into feature branch, resolving conflicts in: - model_node_introspection_event.py: Combined EnumNodeKind import with field_validator - model_node_heartbeat_event.py: Combined datetime/timezone import with EnumNodeKind - model_registry_request.py: Keep datetime import only (Literal unused) - test_model_node_heartbeat_event.py: Updated tests to use EnumNodeKind and required timestamp
Pull Request Review: Registration Orchestrator (C1)OverviewThis PR implements the first orchestrator node in omnibase_infra with 13,220 additions. Overall, this is excellent architectural work with strong type safety, comprehensive testing, and proper time injection patterns. However, there is one critical issue that must be addressed before merge. ⛔ Critical Issue (Blocking)Violation of Declarative Node PatternLocation: The node contains custom handler methods (
Current Implementation: class NodeRegistrationOrchestrator(NodeOrchestrator):
async def handle_runtime_tick(self, tick, domain="registration"):
"""Handle a RuntimeTick event for timeout coordination."""
if self._timeout_coordinator is None:
raise RuntimeError(...)
return await self._timeout_coordinator.coordinate(tick, domain=domain)Expected Declarative Pattern: class NodeRegistrationOrchestrator(NodeOrchestrator):
"""Declarative orchestrator - all behavior defined in contract.yaml."""
def __init__(self, container: ModelONEXContainer) -> None:
super().__init__(container)
# Only container injection, no custom methodsWhy This Matters: This is the first orchestrator in omnibase_infra. The pattern established here will be followed by all future orchestrators. We must get the declarative pattern right before merging. Recommendation: Move handler routing logic into 🔶 Major Issues (Should Fix Before Merge)1. Missing Circuit Breaker ProtectionLocation: Handlers query projection readers (database operations) without circuit breaker protection. CLAUDE.md recommends:
Recommendation: Either implement 2. Contract.yaml ComplexityLocation: The contract acknowledges its complexity (lines 5-33) but hasn't addressed it. Recommendation: Extract into subcontracts as suggested:
3. Inconsistent Error DocumentationHandler docstrings document "Raises: RuntimeHostError" generically. Should be more specific per CLAUDE.md error hierarchy: Raises:
InfraConnectionError: If database connection fails.
InfraTimeoutError: If database operation times out.
InfraUnavailableError: If circuit breaker is open.
RuntimeHostError: For other infrastructure errors.4. Missing Handler in PR DescriptionPR description lists 3 handlers but implementation includes 4: Recommendation: Update PR description for completeness. 🔷 Minor Issues (Nice to Have)1. Test Coverage MetricsThe PR claims "60 unit tests passing" but doesn't quantify coverage percentage. Consider adding coverage metrics to validate completeness. 2. Time Injection Handler SignaturesWhile all event models correctly enforce required ✅ Strengths (Excellent Work!)Time Injection Pattern Compliance
Type Safety
Architecture
Documentation
Testing
VerdictStatus: This is excellent work that demonstrates deep understanding of ONEX principles. The critical issue is fixable and once addressed, this PR will serve as the gold standard for all future orchestrators. Required Before Merge:
Impact: As the first orchestrator in omnibase_infra, this sets the pattern for all future orchestrators. Let's get the declarative pattern right! Great work overall! 🎉 |
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
tests/unit/models/registration/test_model_node_heartbeat_event.py (2)
3-12: Update outdated docstring reference to timestamp auto-generation.Line 10 states "Timestamp auto-generation" as a validation target, but this is inconsistent with the new time-injection pattern implemented in this PR. Timestamps are now required and must be explicitly provided by callers (as confirmed by the test at lines 583-597 and the comment at line 581).
🔎 Proposed fix
"""Unit tests for ModelNodeHeartbeatEvent. Tests validate: - Required field instantiation - Optional field handling - Non-negative constraint validation for uptime_seconds, active_operations_count, and memory_usage_mb - JSON serialization/deserialization roundtrip -- Timestamp auto-generation +- Explicit timestamp injection (time-injection pattern) - Frozen model immutability """
317-336: Add timestamp parameter to validation error tests for clarity.These tests validate constraint violations on specific fields (negative values, None values, etc.), but they omit the
timestampparameter. Since timestamp is now required per the time-injection pattern, Pydantic will include a "missing timestamp" error in the ValidationError along with the intended constraint violation. While the tests may still pass because both errors appear instr(exc_info.value), it's clearer to provide all required fields except the one being tested to isolate the specific validation concern.🔎 Proposed fix (example for one test, apply pattern to others)
def test_negative_uptime_seconds_raises_validation_error(self) -> None: """Test that negative uptime_seconds raises ValidationError.""" test_node_id = uuid4() with pytest.raises(ValidationError) as exc_info: ModelNodeHeartbeatEvent( node_id=test_node_id, node_type=EnumNodeKind.EFFECT, uptime_seconds=-1.0, + timestamp=TEST_TIMESTAMP, ) assert "uptime_seconds" in str(exc_info.value)Apply this pattern to:
- Lines 328-336 (test_negative_uptime_seconds_large_negative)
- Lines 375-385 (test_negative_active_operations_count_raises_validation_error)
- Lines 387-396 (test_negative_active_operations_large_negative)
- Lines 438-448 (test_negative_memory_usage_mb_raises_validation_error)
- Lines 450-459 (test_negative_memory_usage_mb_large_negative)
- Lines 814-824 (test_cpu_usage_negative_raises_validation_error)
- Lines 899-908 (test_none_uptime_seconds_raises_validation_error)
Also applies to: 375-396, 438-459, 814-824, 899-908
src/omnibase_infra/nodes/effects/models/model_registry_request.py (1)
57-69: Update the docstring example to include the required timestamp parameter.The example instantiates
ModelRegistryRequestwithout thetimestampparameter (lines 60-67), buttimestampis now a required field (line 112). This example would fail with a Pydantic validation error.🔎 Proposed fix
Example: >>> from uuid import uuid4 + >>> from datetime import datetime, UTC >>> from omnibase_core.enums.enum_node_kind import EnumNodeKind >>> request = ModelRegistryRequest( ... node_id=uuid4(), ... node_type=EnumNodeKind.EFFECT, ... node_version="1.0.0", ... correlation_id=uuid4(), ... service_name="onex-effect", ... endpoints={"health": "http://localhost:8080/health"}, + ... timestamp=datetime.now(UTC), ... ) >>> request.node_type <EnumNodeKind.EFFECT: 'effect'>
🧹 Nitpick comments (9)
src/omnibase_infra/orchestrators/registration/handlers/handler_runtime_tick.py (2)
209-212: Consider replacing assertion with explicit check.Assertions can be disabled in optimized Python (
python -O), making them unsuitable for runtime validation. While the defensive check at line 204 should prevent this case, consider using an explicit check or documenting why the assertion pattern is safe here.Alternative approach:
if ack_deadline is None: # This should never happen due to needs_ack_timeout_event() check above logger.error( "Unexpected None ack_deadline after needs_ack_timeout_event check", extra={"node_id": str(projection.entity_id)}, ) continueThis ensures the check is always enforced and provides better diagnostics if the invariant is violated.
202-205: Consider clarifying the defensive double-check pattern.The defensive recheck with
needs_ack_timeout_event()is good for safety, but it would be helpful to document why the projection query might return entities that don't need timeout events. For example:# Double-check with projection helper (defensive). # The query returns candidates, but concurrent updates or edge cases # around deadline timestamps may require verification. if not projection.needs_ack_timeout_event(now): continueThis helps future maintainers understand whether the query precision could be improved or if the pattern is inherently necessary.
tests/unit/models/registration/test_model_node_heartbeat_event.py (1)
54-54: Consider using TEST_TIMESTAMP for consistency and determinism.Several tests use
datetime.now(UTC)to generate timestamps dynamically. While not incorrect, using the deterministicTEST_TIMESTAMPconstant (defined at line 26) would improve test reproducibility and consistency with the time-injection pattern demonstrated throughout the file. The tests at lines 1301, 1335, 1366, 1384, and 1410 correctly use dynamic timestamps for equality/hashing tests where the same timestamp must be shared across instances.Example locations to update:
- Line 54:
test_valid_instantiation_all_fields- Lines 980, 994, 1038, 1062, 1085, 1108, 1131: Various
from_attributestests- Lines 1200, 1222, 1244, 1266, 1288: Boundary value tests in
from_attributesAlso applies to: 980-980, 994-994, 1038-1038, 1062-1062, 1085-1085, 1108-1108, 1131-1131, 1200-1200, 1222-1222, 1244-1244, 1266-1266, 1288-1288
src/omnibase_infra/runtime/protocols/protocol_runtime_scheduler.py (1)
42-86: Consider showing imports and using modern UTC pattern in example.The example implementation is functionally correct and addresses past review comments (correct field names now match
ModelRuntimeSchedulerMetrics). However, for better clarity:
- Line 51 uses
asyncio.Lock()and line 75 usestimezone.utcwithout showing imports at the top- Line 80 imports
EnumSchedulerStatusinline, creating inconsistency- Line 75 uses
timezone.utc(valid but older) instead ofUTCfrom datetime (Python 3.11+ pattern)🔎 Optional: Add imports and modernize timezone usage
Add imports at the top of the example class docstring:
class InMemoryScheduler: '''Simple in-memory scheduler for testing.''' + + import asyncio + from datetime import UTC + from omnibase_infra.runtime.enums import EnumSchedulerStatus def __init__(self, interval_seconds: float = 1.0) -> None:Then update timezone usage:
async def emit_tick(self, now: datetime | None = None) -> None: self._sequence += 1 self._total_ticks_emitted += 1 - tick_time = now or datetime.now(timezone.utc) + tick_time = now or datetime.now(UTC) # Emit event to Kafka...And remove the inline import:
async def get_metrics(self) -> ModelRuntimeSchedulerMetrics: # Lock ensures consistent snapshot of all metrics - from omnibase_infra.runtime.enums import EnumSchedulerStatus async with self._state_lock:tests/performance/event_bus/test_event_bus_load.py (1)
320-458: LGTM! Multi-subscriber load tests correctly handle closure captures.Both test methods properly validate fanout and multi-topic scenarios. The
make_handlerclosure pattern (lines 349-356, 419-426) correctly captures loop variables to avoid late-binding issues.💡 Optional: Consider dict comprehension for clarity
Line 412 uses
dict.fromkeys(topics, 0)which works correctly for immutable ints, but a dict comprehension would be more explicit:- counters: dict[str, int] = dict.fromkeys(topics, 0) + counters: dict[str, int] = {t: 0 for t in topics}This makes the intent clearer without relying on knowledge of int immutability.
src/omnibase_infra/mixins/mixin_node_introspection.py (3)
1134-1140: Consider clarifying the measurement purpose.The
discover_capabilities_msmetric measures class-level signature discovery time separately from the overallget_capabilities()execution. While this is useful for performance analysis (showing cache population cost), the relationship between this measurement and the internal timing inget_capabilities()could be clearer.The current implementation is correct, but consider adding a brief comment explaining why this is measured separately from the
get_capabilities()call below.
1327-1346: Consider removing redundant assertion.The type narrowing pattern works correctly, but line 1329's assertion is redundant since line 1302 already checks
if self._introspection_event_bus is None:and returns early. The local variable assignment at line 1328 is sufficient for type narrowing.🔎 Optional simplification
# Type narrowing: we've already checked _introspection_event_bus is not None above event_bus = self._introspection_event_bus -assert event_bus is not None # Redundant but helps mypy topic = self._introspection_topic
1434-1451: Same redundant assertion pattern as earlier.This segment has the same redundant assertion issue as lines 1327-1346. The assertion at line 1436 is unnecessary since lines 1382-1383 already validate the event bus and return early if None.
🔎 Optional simplification
# Type narrowing: we've already checked _introspection_event_bus is not None above event_bus = self._introspection_event_bus -assert event_bus is not None # Redundant but helps mypy topic = self._heartbeat_topicsrc/omnibase_infra/nodes/node_registration_orchestrator/contract.yaml (1)
5-7: Minor: Update line count estimate.The comment mentions "Current size: ~460 lines" but the file is actually 465 lines. Consider updating this estimate for accuracy.
🔎 Proposed fix
-# as this contract grows. Current size: ~460 lines. +# as this contract grows. Current size: ~465 lines.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Lite
📒 Files selected for processing (26)
docs/design/MVP_EVENT_CATALOG.mdpyproject.tomlsrc/omnibase_infra/event_bus/models/model_event_headers.pysrc/omnibase_infra/mixins/__init__.pysrc/omnibase_infra/mixins/mixin_node_introspection.pysrc/omnibase_infra/models/discovery/model_node_introspection_event.pysrc/omnibase_infra/models/projection/model_registration_projection.pysrc/omnibase_infra/models/registration/model_node_heartbeat_event.pysrc/omnibase_infra/nodes/effects/models/model_registry_request.pysrc/omnibase_infra/nodes/effects/protocol_consul_client.pysrc/omnibase_infra/nodes/effects/protocol_postgres_adapter.pysrc/omnibase_infra/nodes/node_registration_orchestrator/README.mdsrc/omnibase_infra/nodes/node_registration_orchestrator/contract.yamlsrc/omnibase_infra/orchestrators/registration/handlers/handler_runtime_tick.pysrc/omnibase_infra/protocols/protocol_snapshot_publisher.pysrc/omnibase_infra/runtime/protocols/protocol_runtime_scheduler.pysrc/omnibase_infra/validation/validation_exemptions.yamltests/integration/event_bus/test_event_schema_validation.pytests/integration/nodes/test_registration_orchestrator_integration.pytests/integration/nodes/test_registration_orchestrator_runtime_execution.pytests/integration/registration/effect/conftest.pytests/integration/runtime/test_dispatch_context_integration.pytests/performance/event_bus/test_event_bus_load.pytests/unit/event_bus/test_kafka_event_bus.pytests/unit/models/registration/test_model_node_heartbeat_event.pytests/unit/nodes/reducers/test_registration_reducer.py
✅ Files skipped from review due to trivial changes (1)
- tests/integration/nodes/test_registration_orchestrator_runtime_execution.py
🚧 Files skipped from review as they are similar to previous changes (8)
- src/omnibase_infra/protocols/protocol_snapshot_publisher.py
- src/omnibase_infra/models/projection/model_registration_projection.py
- tests/unit/event_bus/test_kafka_event_bus.py
- tests/integration/event_bus/test_event_schema_validation.py
- src/omnibase_infra/nodes/effects/protocol_consul_client.py
- src/omnibase_infra/nodes/effects/protocol_postgres_adapter.py
- tests/integration/nodes/test_registration_orchestrator_integration.py
- src/omnibase_infra/validation/validation_exemptions.yaml
🧰 Additional context used
📓 Path-based instructions (4)
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.py: NEVER useAnytype - Always use specific types. For generic dispatchers accepting any payload type, useModelEventEnvelope[object]instead ofAny.
All data structures must be proper Pydantic models
Each file contains exactly oneModel*class - One model per file
UseX | None(PEP 604 union syntax) for nullable types instead ofOptional[X]
For generic dispatchers and protocol definitions accepting any payload type, useModelEventEnvelope[object]instead ofModelEventEnvelope[Any]to satisfy the 'no Any types' rule while maintaining necessary flexibility
All services MUST useModelONEXContainerfor dependency injection via container initialization patterncontainer = ModelONEXContainer()followed by service resolution
RaiseOnexError(...) from e- Only use OnexError for error propagation, never use other exception types
Use Protocol resolution through duck typing viaisinstance(obj, ProtocolType)pattern - never use direct type checking for protocol implementations
Node Archetypes and Core Models (NodeEffect, NodeCompute, NodeReducer, NodeOrchestrator and their I/O models) must be imported fromomnibase_core.nodes. Infrastructure extends base archetypes from core - never define new node archetypes in infra layer.
UseEnumMessageCategory(values: EVENT, COMMAND, INTENT) for message routing, topic parsing, and dispatcher selection. UseEnumNodeOutputType(values: EVENT, COMMAND, INTENT, PROJECTION) for execution shape validation and handler return type validation. PROJECTION is only valid for REDUCER nodes.
All infrastructure adapters and services MUST useMixinAsyncCircuitBreakerfor fault tolerance. Use_init_circuit_breaker()in init with appropriate threshold and reset_timeout. Always holdself._circuit_breaker_lockwhen calling circuit breaker methods.
Correlation IDs must be UUID format. Always propagatecorrelation_idfrom incoming requests to error context. Auto-generate usinguuid4()if not present. Include...
Files:
src/omnibase_infra/mixins/__init__.pysrc/omnibase_infra/nodes/effects/models/model_registry_request.pysrc/omnibase_infra/models/registration/model_node_heartbeat_event.pytests/integration/runtime/test_dispatch_context_integration.pysrc/omnibase_infra/mixins/mixin_node_introspection.pysrc/omnibase_infra/runtime/protocols/protocol_runtime_scheduler.pysrc/omnibase_infra/event_bus/models/model_event_headers.pytests/integration/registration/effect/conftest.pytests/unit/models/registration/test_model_node_heartbeat_event.pytests/performance/event_bus/test_event_bus_load.pytests/unit/nodes/reducers/test_registration_reducer.pysrc/omnibase_infra/orchestrators/registration/handlers/handler_runtime_tick.pysrc/omnibase_infra/models/discovery/model_node_introspection_event.py
**/model_*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Model files must follow naming convention
model_<name>.pywith class nameModel<Name>(e.g.,model_kafka_message.py→ModelKafkaMessage)
Files:
src/omnibase_infra/nodes/effects/models/model_registry_request.pysrc/omnibase_infra/models/registration/model_node_heartbeat_event.pysrc/omnibase_infra/event_bus/models/model_event_headers.pysrc/omnibase_infra/models/discovery/model_node_introspection_event.py
**/mixin_*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Mixin files must follow naming convention
mixin_<name>.pywith class nameMixin<Name>(e.g.,mixin_health_check.py→MixinHealthCheck)
Files:
src/omnibase_infra/mixins/mixin_node_introspection.py
**/protocol_*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Protocol files must follow naming convention
protocol_<name>.pywith class nameProtocol<Name>for standalone protocols (e.g.,protocol_event_bus.py→ProtocolEventBus)
Files:
src/omnibase_infra/runtime/protocols/protocol_runtime_scheduler.py
🧠 Learnings (58)
📓 Common learnings
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T16:32:55.606Z
Learning: All ONEX nodes must conform to the 4-Node Architecture pattern with clear separation of concerns and unidirectional data flow (EFFECT → COMPUTE → REDUCER → ORCHESTRATOR)
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: All ONEX nodes must conform to the canonical structure, code generation, and interface patterns established in the `node_cli` node, using it as the primary source of truth for directory structure, contract schema patterns, linked document architecture, base state patterns, shared schema references, extensibility patterns, CLI interface declarations, code generation, dependency injection, error handling, testing, and documentation
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: All ONEX nodes must use the node_kafka_event_bus as a secondary reference only for complex backend and event bus logic and advanced configuration patterns
Learnt from: CR
Repo: OmniNode-ai/omniintelligence PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-07T17:50:13.678Z
Learning: Decompose intelligence operations into specialized ONEX nodes following a four-node pattern: Orchestrator (coordinate workflows), Reducer (manage state, FSM transitions), Compute (pure data processing), and Effect (external I/O)
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T16:55:49.755Z
Learning: Applies to agents/**/*.py : Implement ONEX-compliant agent architecture with four node types: Effect (External I/O), Compute (Pure transforms), Reducer (State/persistence), and Orchestrator (Workflow coordination)
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: NodeBridgeOrchestrator MUST support multi-step execution workflow coordination with service routing. Target performance: <50ms standard workflows, <150ms with OnexTree intelligence
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: All ONEX node deviations from canonical patterns must be documented and justified in the node's root-level README.md and subject to maintainer review
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/*.py : All ONEX node implementations must follow dependency injection and protocol-first design patterns as established in the node_cli canonical reference
📚 Learning: 2025-11-30T21:55:10.298Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: Applies to src/omninode_bridge/nodes/**/*.py : Import mixins from omnibase_core.mixins.* and use Mixin* naming pattern (e.g., MixinHealthCheck, MixinMetrics, MixinEventBus) - never use local custom mixins unless experimental and documented
Applied to files:
src/omnibase_infra/mixins/__init__.pysrc/omnibase_infra/mixins/mixin_node_introspection.py
📚 Learning: 2025-12-26T13:16:11.773Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-26T13:16:11.773Z
Learning: Applies to **/*.py : Node Introspection cache is instance-level (not thread-safe without external synchronization). Designed for single-threaded asyncio usage. For multi-threaded access, external synchronization required. Background tasks (heartbeat, registry listener) run as asyncio tasks within event loop.
Applied to files:
src/omnibase_infra/mixins/__init__.pysrc/omnibase_infra/mixins/mixin_node_introspection.py
📚 Learning: 2025-12-26T13:16:11.773Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-26T13:16:11.773Z
Learning: Applies to **/*.py : Node Introspection via `MixinNodeIntrospection`: Prefix internal/sensitive methods with `_` to exclude from introspection. Avoid exposing sensitive business logic in method names. Use generic parameter names instead of revealing implementation details.
Applied to files:
src/omnibase_infra/mixins/__init__.pysrc/omnibase_infra/mixins/mixin_node_introspection.py
📚 Learning: 2025-12-26T13:16:11.773Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-26T13:16:11.773Z
Learning: Applies to **/*.py : All infrastructure adapters and services MUST use `MixinAsyncCircuitBreaker` for fault tolerance. Use `_init_circuit_breaker()` in __init__ with appropriate threshold and reset_timeout. Always hold `self._circuit_breaker_lock` when calling circuit breaker methods.
Applied to files:
src/omnibase_infra/mixins/__init__.py
📚 Learning: 2025-12-20T04:09:41.832Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-20T04:09:41.832Z
Learning: Applies to **/*.py : Use EnumNodeKind for architectural role classification (EFFECT, COMPUTE, REDUCER, ORCHESTRATOR, RUNTIME_HOST) and EnumNodeType for implementation type discovery
Applied to files:
src/omnibase_infra/nodes/effects/models/model_registry_request.py
📚 Learning: 2025-11-28T18:58:53.781Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/canonical_patterns.mdc:0-0
Timestamp: 2025-11-28T18:58:53.781Z
Learning: Applies to **/*.py : Implement Node classes by inheriting from `NodeBase` with proper UUID and `ModelSemVer` fields
Applied to files:
src/omnibase_infra/nodes/effects/models/model_registry_request.pysrc/omnibase_infra/models/registration/model_node_heartbeat_event.py
📚 Learning: 2025-11-24T17:24:10.209Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/pr.mdc:0-0
Timestamp: 2025-11-24T17:24:10.209Z
Learning: Applies to docs_private/dev_logs/jonah/pr/pr_description_*.md : PR description files must be stamped with an ONEX metadata block at the top using HTML comments format (`<!-- === OmniNode:Metadata === ... <!-- === /OmniNode:Metadata === -->`), and stamping must be idempotent and policy-driven. Do NOT use manual metadata blocks with hash comments.
Applied to files:
docs/design/MVP_EVENT_CATALOG.md
📚 Learning: 2025-11-24T16:33:09.011Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/pr.mdc:0-0
Timestamp: 2025-11-24T16:33:09.011Z
Learning: Applies to docs_private/dev_logs/jonah/pr/pr_description_*.md : All PR description files must be stamped with an ONEX metadata block at the top using HTML comments format (`<!-- === OmniNode:Metadata === ... <!-- === /OmniNode:Metadata === -->`), not hash comments. Stamping must be idempotent and policy-driven.
Applied to files:
docs/design/MVP_EVENT_CATALOG.md
📚 Learning: 2025-11-30T21:55:10.298Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: Deviations from omnibase_core standards are only acceptable for: (1) Orchestrator/Reducer nodes (ModelService* disabled), (2) Experimental features being prototyped for upstream, (3) Performance-critical optimizations with benchmark proof, (4) Bridge-specific unique patterns. All deviations require explicit documentation and justification.
Applied to files:
docs/design/MVP_EVENT_CATALOG.md
📚 Learning: 2025-11-30T21:55:10.298Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: Applies to src/omninode_bridge/events/**/*.py : Kafka event publishing MUST use OnexEnvelopeV1 format with 13 topics for event streaming at all workflow lifecycle stages
Applied to files:
docs/design/MVP_EVENT_CATALOG.md
📚 Learning: 2025-11-28T18:58:53.781Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/canonical_patterns.mdc:0-0
Timestamp: 2025-11-28T18:58:53.781Z
Learning: Organize models under `src/omnibase_core/models/` by domain including: base, cli, common, config, core, contracts, discovery, health, infrastructure, logging, metadata, nodes, operations, results, security, service, tools, validation, and workflows
Applied to files:
docs/design/MVP_EVENT_CATALOG.md
📚 Learning: 2025-11-24T17:22:32.195Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/canonical_patterns.mdc:0-0
Timestamp: 2025-11-24T17:22:32.195Z
Learning: Follow canonical patterns from reference implementations: use node_cli/v1_0_0/ as primary reference and node_kafka_event_bus/v1_0_0/ for complex backend patterns
Applied to files:
docs/design/MVP_EVENT_CATALOG.mdsrc/omnibase_infra/nodes/node_registration_orchestrator/contract.yaml
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: All ONEX nodes must conform to the canonical structure, code generation, and interface patterns established in the `node_cli` node, using it as the primary source of truth for directory structure, contract schema patterns, linked document architecture, base state patterns, shared schema references, extensibility patterns, CLI interface declarations, code generation, dependency injection, error handling, testing, and documentation
Applied to files:
docs/design/MVP_EVENT_CATALOG.mdsrc/omnibase_infra/nodes/node_registration_orchestrator/contract.yaml
📚 Learning: 2025-12-26T13:16:11.773Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-26T13:16:11.773Z
Learning: Applies to **/*.py : Use `EnumMessageCategory` (values: EVENT, COMMAND, INTENT) for message routing, topic parsing, and dispatcher selection. Use `EnumNodeOutputType` (values: EVENT, COMMAND, INTENT, PROJECTION) for execution shape validation and handler return type validation. PROJECTION is only valid for REDUCER nodes.
Applied to files:
docs/design/MVP_EVENT_CATALOG.md
📚 Learning: 2025-11-24T16:32:55.606Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T16:32:55.606Z
Learning: Node communication must use event-driven patterns through `ModelEventEnvelope` from `omnibase_core.models.events.model_event_envelope`
Applied to files:
docs/design/MVP_EVENT_CATALOG.md
📚 Learning: 2025-11-30T21:55:10.298Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: Applies to src/omninode_bridge/nodes/**/*.py : All nodes in omninode_bridge MUST use omnibase_core standards (ModelServiceEffect, ModelServiceCompute for effect/compute nodes; NodeOrchestrator, NodeReducer with mixins for orchestrator/reducer nodes)
Applied to files:
docs/design/MVP_EVENT_CATALOG.md
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/SCHEMA_DECISIONS.md : Each versioned ONEX node implementation directory must include a `SCHEMA_DECISIONS.md` file documenting schema-specific design decisions, implementation notes, and validation strategies
Applied to files:
docs/design/MVP_EVENT_CATALOG.md
📚 Learning: 2025-11-24T16:32:55.606Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T16:32:55.606Z
Learning: ORCHESTRATOR Nodes must inherit from `NodeOrchestrator` or use `NodeOrchestratorService` and must coordinate workflows, manage node interactions, and handle process/event orchestration
Applied to files:
src/omnibase_infra/nodes/node_registration_orchestrator/README.md
📚 Learning: 2025-11-30T21:55:10.298Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: NodeBridgeOrchestrator MUST support multi-step execution workflow coordination with service routing. Target performance: <50ms standard workflows, <150ms with OnexTree intelligence
Applied to files:
src/omnibase_infra/nodes/node_registration_orchestrator/README.md
📚 Learning: 2025-11-24T16:33:32.747Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/standards.mdc:0-0
Timestamp: 2025-11-24T16:33:32.747Z
Learning: Applies to **/*.py : Import enums from `omnibase.enums` package
Applied to files:
src/omnibase_infra/models/registration/model_node_heartbeat_event.py
📚 Learning: 2025-11-24T17:24:41.687Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/standards.mdc:0-0
Timestamp: 2025-11-24T17:24:41.687Z
Learning: Applies to **/*.py : Import enums from `omnibase.enums` module
Applied to files:
src/omnibase_infra/models/registration/model_node_heartbeat_event.py
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/contracts/contract_*.yaml : All ONEX node contract definitions must use the new subcontract architecture pattern, breaking down complex contracts into separate contract_actions.yaml, contract_models.yaml, contract_validation.yaml, and optional contract_cli.yaml and contract_capabilities.yaml files for separation of concerns, maintainability, reusability, modularity, and future tool-as-a-service readiness
Applied to files:
src/omnibase_infra/nodes/node_registration_orchestrator/contract.yaml
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/contract.yaml : All ONEX node contract definitions must follow the linked document architecture pattern with contract.yaml linking to node_config.yaml and deployment_config.yaml as associated documents
Applied to files:
src/omnibase_infra/nodes/node_registration_orchestrator/contract.yaml
📚 Learning: 2025-11-30T21:55:10.298Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: Applies to src/omninode_bridge/nodes/**/contract.yaml : All contract YAML files for ONEX v2.0 nodes MUST define subcontract references, input/output models, and FSM configurations. Use YAML 1.2 syntax.
Applied to files:
src/omnibase_infra/nodes/node_registration_orchestrator/contract.yaml
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/contracts/contract_capabilities.yaml : All ONEX node execution capability definitions, if applicable, must be included in contract_capabilities.yaml with supported_node_types, supported_delivery_modes, and performance_constraints specifications
Applied to files:
src/omnibase_infra/nodes/node_registration_orchestrator/contract.yaml
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/contract.yaml : All ONEX node contract schemas must use the canonical base state inheritance pattern with input_state containing only node-specific fields (inheriting from OnexInputState) and output_state containing only node-specific fields (inheriting from OnexOutputState)
Applied to files:
src/omnibase_infra/nodes/node_registration_orchestrator/contract.yaml
📚 Learning: 2025-11-24T16:32:55.606Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T16:32:55.606Z
Learning: Applies to **/*contract*.yaml : All ONEX nodes must have validated YAML contracts following the contract-driven development pattern with input_state and output_state schema definitions
Applied to files:
src/omnibase_infra/nodes/node_registration_orchestrator/contract.yaml
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/contracts/contract_cli.yaml : All ONEX node CLI interface definitions, if applicable, must be included in contract_cli.yaml with entrypoint and commands specifications
Applied to files:
src/omnibase_infra/nodes/node_registration_orchestrator/contract.yaml
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/contract.yaml : All ONEX node contract definitions must support optional documents pattern with optional flag and required_capability field for future extensibility
Applied to files:
src/omnibase_infra/nodes/node_registration_orchestrator/contract.yaml
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/contracts/contract_*.yaml : All ONEX node subcontracts must be organized in a `contracts/` subdirectory within the versioned implementation directory with separate files for contract_actions.yaml, contract_models.yaml, contract_validation.yaml, contract_cli.yaml (optional), and contract_capabilities.yaml (optional)
Applied to files:
src/omnibase_infra/nodes/node_registration_orchestrator/contract.yaml
📚 Learning: 2025-12-26T13:16:11.773Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-26T13:16:11.773Z
Learning: Applies to nodes/**/*.yaml : Node contracts must specify node type as one of: EFFECT, COMPUTE, REDUCER, ORCHESTRATOR in the contract definition
Applied to files:
src/omnibase_infra/nodes/node_registration_orchestrator/contract.yaml
📚 Learning: 2025-12-08T00:48:30.737Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_spi PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-08T00:48:30.737Z
Learning: Applies to src/omnibase_spi/protocols/nodes/*.py : Use Protocol naming convention `Protocol{Type}Node` for node protocols (e.g., `ProtocolComputeNode`, `ProtocolEffectNode`)
Applied to files:
src/omnibase_infra/nodes/node_registration_orchestrator/contract.yaml
📚 Learning: 2025-12-26T13:16:11.773Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-26T13:16:11.773Z
Learning: Applies to **/node.py : Node implementation files must be named `node.py` with class name `Node<Name><Type>` where Type is one of EFFECT/COMPUTE/REDUCER/ORCHESTRATOR (e.g., `NodePostgresAdapterEffect`)
Applied to files:
src/omnibase_infra/nodes/node_registration_orchestrator/contract.yaml
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/introspection.py : All ONEX nodes must include an `introspection.py` file implementing standards-compliant introspection logic
Applied to files:
src/omnibase_infra/nodes/node_registration_orchestrator/contract.yaml
📚 Learning: 2025-12-06T22:21:32.649Z
Learnt from: CR
Repo: OmniNode-ai/omniagent PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T22:21:32.649Z
Learning: Applies to nodes/**/*.py : Use event bus mixins from `omnibase_core` for Kafka publishing instead of direct Kafka clients
Applied to files:
src/omnibase_infra/mixins/mixin_node_introspection.py
📚 Learning: 2025-12-03T16:55:49.755Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T16:55:49.755Z
Learning: Applies to **/*.py : Publish intelligence requests to Kafka event bus using topics: dev.archon-intelligence.intelligence.code-analysis-{requested,completed,failed}.v1 for consistency and event-driven architecture
Applied to files:
src/omnibase_infra/mixins/mixin_node_introspection.py
📚 Learning: 2025-12-08T00:48:30.737Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_spi PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-08T00:48:30.737Z
Learning: Applies to src/omnibase_spi/protocols/**/*.py : All public protocols must be decorated with `runtime_checkable`
Applied to files:
src/omnibase_infra/runtime/protocols/protocol_runtime_scheduler.py
📚 Learning: 2025-12-08T00:48:30.737Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_spi PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-08T00:48:30.737Z
Learning: Import `omnibase_core` models and types only for type hints and runtime usage - follow the SPI → Core dependency direction
Applied to files:
src/omnibase_infra/runtime/protocols/protocol_runtime_scheduler.py
📚 Learning: 2025-11-24T16:33:32.747Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/standards.mdc:0-0
Timestamp: 2025-11-24T16:33:32.747Z
Learning: Applies to **/protocols/protocol_*.py : Use TYPE_CHECKING guards and forward references for circular import prevention in protocol files
Applied to files:
src/omnibase_infra/runtime/protocols/protocol_runtime_scheduler.py
📚 Learning: 2025-11-24T16:33:51.604Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-24T16:33:51.604Z
Learning: Applies to tests/**/conftest.py : Test fixtures must be defined in `conftest.py` and should provide reusable sample data, UUIDs, semantic versions, and model data
Applied to files:
tests/integration/registration/effect/conftest.py
📚 Learning: 2025-12-03T16:55:49.755Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T16:55:49.755Z
Learning: Applies to agents/**/*.py : Use correlation_id UUID for end-to-end traceability across all agent routing, manifest injection, and execution events
Applied to files:
tests/unit/models/registration/test_model_node_heartbeat_event.py
📚 Learning: 2025-12-06T22:21:32.649Z
Learnt from: CR
Repo: OmniNode-ai/omniagent PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T22:21:32.649Z
Learning: Applies to tests/**/*.py : Use pytest markers `pytest.mark.unit`, `pytest.mark.integration`, `pytest.mark.slow`, and `pytest.mark.performance` for test categorization
Applied to files:
pyproject.toml
📚 Learning: 2025-12-07T17:50:13.678Z
Learnt from: CR
Repo: OmniNode-ai/omniintelligence PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-07T17:50:13.678Z
Learning: Use pytest markers for test organization: pytest -m unit for unit tests only, pytest -m integration for integration tests, pytest -m slow for slow tests, pytest -m performance for performance benchmarks
Applied to files:
pyproject.toml
📚 Learning: 2025-12-20T04:09:41.832Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-20T04:09:41.832Z
Learning: Applies to tests/**/*.py : Use pytest markers pytest.mark.unit, pytest.mark.integration, pytest.mark.slow, pytest.mark.smoke, pytest.mark.performance to classify tests
Applied to files:
pyproject.toml
📚 Learning: 2025-11-24T17:24:54.193Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-24T17:24:54.193Z
Learning: Applies to **/*test*.py : Apply pytest markers (mock, integration) ONLY to fixture parameters using pytest.param, never directly on test functions or classes
Applied to files:
pyproject.toml
📚 Learning: 2025-10-14T12:06:38.965Z
Learnt from: jonahgabriel
Repo: OmniNode-ai/omninode_bridge PR: 0
File: :0-0
Timestamp: 2025-10-14T12:06:38.965Z
Learning: In pyproject.toml for OmniNode Bridge: Dev dependencies are pytest ^8.4.0, pytest-asyncio ^0.25.0, mypy ^1.13.0, black ^24.10.0, and ruff ^0.8.0, all compatible with Python 3.12.
Applied to files:
pyproject.toml
📚 Learning: 2025-11-29T17:13:38.776Z
Learnt from: CR
Repo: OmniNode-ai/omniarchon PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-29T17:13:38.776Z
Learning: Applies to {**/*.py,!docs/**,!scripts/examples/**} : Ensure 100% test coverage for production code, with fail-closed security configuration as documented in `IMPROVEMENTS.md`.
Applied to files:
pyproject.toml
📚 Learning: 2025-11-24T17:24:54.193Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-24T17:24:54.193Z
Learning: Applies to **/*test*.py : Use dynamic fixture injection by detecting required fixtures from constructor using inspect.signature() to inject optional dependencies like logger_tool
Applied to files:
pyproject.toml
📚 Learning: 2025-11-24T17:24:54.193Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-24T17:24:54.193Z
Learning: Applies to **/*test*.py : Use context-based fixtures with pytest.param and conditional dependency injection (e.g., UNIT_CONTEXT vs INTEGRATION_CONTEXT) for mock and integration tests
Applied to files:
pyproject.toml
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/node_tests/**/*.py : All ONEX node tests must be organized in a `node_tests/` directory using scenario-driven testing patterns with fixture-injected tests
Applied to files:
pyproject.toml
📚 Learning: 2025-11-24T17:24:54.193Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-24T17:24:54.193Z
Learning: Applies to **/scenario_*.yaml : Use full Python path for tool configuration (e.g., 'omnibase.nodes.node_name.v1_0_0.tools.tool_class:ToolClass') and !!python/name syntax for registry tools
Applied to files:
pyproject.toml
📚 Learning: 2025-11-24T16:33:32.747Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/standards.mdc:0-0
Timestamp: 2025-11-24T16:33:32.747Z
Learning: Applies to **/tests/test_*.py : Test files must follow the naming pattern `test_<name>.py` and be located in `*/tests/` directories
Applied to files:
pyproject.toml
📚 Learning: 2025-12-06T22:21:32.649Z
Learnt from: CR
Repo: OmniNode-ai/omniagent PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T22:21:32.649Z
Learning: Applies to tests/**/*.py : Organize test files into `tests/unit/`, `tests/integration/`, and `tests/nodes/` directories
Applied to files:
pyproject.toml
📚 Learning: 2025-11-30T21:55:10.298Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: Applies to tests/bridge_nodes/**/*.py : All Bridge Node implementations MUST include comprehensive test coverage with focus on critical paths (event schemas, entity models). Target: 90%+ coverage for critical components.
Applied to files:
tests/unit/nodes/reducers/test_registration_reducer.py
📚 Learning: 2025-11-24T17:22:32.195Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/canonical_patterns.mdc:0-0
Timestamp: 2025-11-24T17:22:32.195Z
Learning: Applies to **/nodes/*/v[0-9]_[0-9]_[0-9]/node.py : Node classes must follow canonical reducer pattern with dependency injection: accept logger_tool and registry in constructor, validate they are not None
Applied to files:
tests/unit/nodes/reducers/test_registration_reducer.py
📚 Learning: 2025-11-24T17:24:10.209Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/pr.mdc:0-0
Timestamp: 2025-11-24T17:24:10.209Z
Learning: Applies to docs_private/dev_logs/jonah/pr/pr_description_*.md : Timestamps in PR descriptions must use ISO 8601 format with timezone (e.g., 2025-05-05T09:15:00-04:00)
Applied to files:
src/omnibase_infra/models/discovery/model_node_introspection_event.py
📚 Learning: 2025-11-24T16:32:20.400Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/debug_log.mdc:0-0
Timestamp: 2025-11-24T16:32:20.400Z
Learning: Applies to docs_private/dev_logs/**/debug_log_[0-9][0-9][0-9][0-9]_[0-9][0-9]_[0-9][0-9].md : Each debug log entry must include: timestamp with UTC timezone and engineer name, tags, checklist reference, linked issue, linked PR, prompt reminder section, context, problem statement, hypotheses, investigation steps, findings, and next steps
Applied to files:
src/omnibase_infra/models/discovery/model_node_introspection_event.py
🧬 Code graph analysis (6)
src/omnibase_infra/mixins/__init__.py (2)
src/omnibase_infra/mixins/mixin_node_introspection.py (1)
PerformanceMetricsCacheDict(218-246)src/omnibase_infra/mixins/protocol_event_bus_like.py (1)
ProtocolEventBusLike(23-48)
tests/integration/runtime/test_dispatch_context_integration.py (1)
tests/helpers/deterministic.py (1)
DeterministicClock(108-212)
src/omnibase_infra/mixins/mixin_node_introspection.py (3)
src/omnibase_infra/event_bus/inmemory_event_bus.py (2)
publish_envelope(353-395)publish(244-351)src/omnibase_infra/event_bus/kafka_event_bus.py (2)
publish_envelope(1024-1058)publish(821-879)src/omnibase_infra/protocols/protocol_event_bus_like.py (2)
publish_envelope(74-89)publish(91-108)
src/omnibase_infra/runtime/protocols/protocol_runtime_scheduler.py (3)
src/omnibase_infra/runtime/models/model_runtime_scheduler_metrics.py (1)
ModelRuntimeSchedulerMetrics(43-230)src/omnibase_infra/idempotency/store_postgres.py (1)
get_metrics(178-200)src/omnibase_infra/runtime/runtime_scheduler.py (1)
get_metrics(447-515)
src/omnibase_infra/event_bus/models/model_event_headers.py (2)
src/omnibase_infra/models/discovery/model_node_introspection_event.py (1)
validate_timestamp_timezone_aware(205-222)src/omnibase_infra/models/registration/model_node_introspection_event.py (1)
validate_timestamp_timezone_aware(147-164)
src/omnibase_infra/models/discovery/model_node_introspection_event.py (2)
src/omnibase_infra/event_bus/models/model_event_headers.py (1)
validate_timestamp_timezone_aware(71-88)src/omnibase_infra/models/registration/model_node_introspection_event.py (1)
validate_timestamp_timezone_aware(147-164)
…OMN-952] - Add missing timestamp field to workflow test fixtures and model constructions - Add timezone validation to handler_node_introspected, handler_runtime_tick, and handler_node_registration_acked with clear error messages - Add timezone validators to model_registry_request and model_node_heartbeat_event - Update MVP_EVENT_CATALOG.md with correct source paths, time-injection examples, and version bump to 1.0.2 - Add 6 new timezone validation unit tests for all three handlers Fixes 9 failing tests and 7 errors in CI workflow integration tests.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (3)
tests/integration/registration/workflow/test_workflow_a0_a2.py (1)
174-174: Consider using deterministic timestamps for test stability.The usage of
datetime.now(UTC)provides timezone-aware timestamps as required, but introduces non-determinism in tests. The codebase providesdeterministic_introspection_event_factoryandregistry_request_factoryfixtures (in conftest.py) that useDeterministicClockfor reproducible test execution.For tests that don't specifically need runtime timestamps, using these deterministic factories can improve test stability and make failures more reproducible.
Also applies to: 247-247, 719-719, 745-745
tests/integration/registration/workflow/test_workflow_a3_a4.py (1)
99-99: Consider using deterministic timestamps for test stability.Similar to test_workflow_a0_a2.py, these
ModelRegistryRequestconstructions usedatetime.now(UTC), which is timezone-aware but introduces non-determinism. Theregistry_request_factoryfixture in conftest.py provides deterministic timestamps viaDeterministicClock.For the helper function
_convert_intents_to_request(line 99), using a deterministic timestamp would make all tests calling it more reproducible.Also applies to: 448-448
docs/design/MVP_EVENT_CATALOG.md (1)
161-161: Standardize timezone imports across examples for consistency.The document shows two different approaches to timezone-aware datetime construction:
- Lines 161-167:
from datetime import UTCwithtzinfo=UTC(Python 3.11+)- Lines 286-287, 346-347:
from datetime import timezonewithtzinfo=timezone.utc(Python 3.9+)This inconsistency may confuse readers about best practices. Choose one pattern and apply it consistently across all examples, preferably the more compatible
timezone.utcapproach unless the codebase explicitly requires Python 3.11+.🔎 Proposed standardization
Update the example at lines 161-169 to use the more compatible pattern:
- from datetime import UTC, datetime + from datetime import datetime, timezone headers = ModelEventHeaders( source="order-service", event_type="order.created", routing_key="orders.us-east", - timestamp=datetime(2025, 1, 15, 12, 0, 0, tzinfo=UTC), # Must be timezone-aware + timestamp=datetime(2025, 1, 15, 12, 0, 0, tzinfo=timezone.utc), # Must be timezone-aware )Apply the same
timezone.utcpattern to all other examples (lines 295, 358, etc.) for consistency.Also applies to: 286-287
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Lite
📒 Files selected for processing (12)
docs/design/MVP_EVENT_CATALOG.mdsrc/omnibase_infra/models/registration/model_node_heartbeat_event.pysrc/omnibase_infra/nodes/effects/models/model_registry_request.pysrc/omnibase_infra/orchestrators/registration/handlers/handler_node_introspected.pysrc/omnibase_infra/orchestrators/registration/handlers/handler_node_registration_acked.pysrc/omnibase_infra/orchestrators/registration/handlers/handler_runtime_tick.pytests/integration/registration/workflow/conftest.pytests/integration/registration/workflow/test_workflow_a0_a2.pytests/integration/registration/workflow/test_workflow_a3_a4.pytests/unit/orchestrators/registration/test_handler_node_introspected.pytests/unit/orchestrators/registration/test_handler_node_registration_acked.pytests/unit/orchestrators/registration/test_handler_runtime_tick.py
🧰 Additional context used
📓 Path-based instructions (2)
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.py: NEVER useAnytype - Always use specific types. For generic dispatchers accepting any payload type, useModelEventEnvelope[object]instead ofAny.
All data structures must be proper Pydantic models
Each file contains exactly oneModel*class - One model per file
UseX | None(PEP 604 union syntax) for nullable types instead ofOptional[X]
For generic dispatchers and protocol definitions accepting any payload type, useModelEventEnvelope[object]instead ofModelEventEnvelope[Any]to satisfy the 'no Any types' rule while maintaining necessary flexibility
All services MUST useModelONEXContainerfor dependency injection via container initialization patterncontainer = ModelONEXContainer()followed by service resolution
RaiseOnexError(...) from e- Only use OnexError for error propagation, never use other exception types
Use Protocol resolution through duck typing viaisinstance(obj, ProtocolType)pattern - never use direct type checking for protocol implementations
Node Archetypes and Core Models (NodeEffect, NodeCompute, NodeReducer, NodeOrchestrator and their I/O models) must be imported fromomnibase_core.nodes. Infrastructure extends base archetypes from core - never define new node archetypes in infra layer.
UseEnumMessageCategory(values: EVENT, COMMAND, INTENT) for message routing, topic parsing, and dispatcher selection. UseEnumNodeOutputType(values: EVENT, COMMAND, INTENT, PROJECTION) for execution shape validation and handler return type validation. PROJECTION is only valid for REDUCER nodes.
All infrastructure adapters and services MUST useMixinAsyncCircuitBreakerfor fault tolerance. Use_init_circuit_breaker()in init with appropriate threshold and reset_timeout. Always holdself._circuit_breaker_lockwhen calling circuit breaker methods.
Correlation IDs must be UUID format. Always propagatecorrelation_idfrom incoming requests to error context. Auto-generate usinguuid4()if not present. Include...
Files:
tests/integration/registration/workflow/conftest.pytests/integration/registration/workflow/test_workflow_a3_a4.pysrc/omnibase_infra/models/registration/model_node_heartbeat_event.pytests/unit/orchestrators/registration/test_handler_runtime_tick.pytests/unit/orchestrators/registration/test_handler_node_registration_acked.pysrc/omnibase_infra/orchestrators/registration/handlers/handler_node_registration_acked.pytests/unit/orchestrators/registration/test_handler_node_introspected.pysrc/omnibase_infra/orchestrators/registration/handlers/handler_runtime_tick.pysrc/omnibase_infra/nodes/effects/models/model_registry_request.pysrc/omnibase_infra/orchestrators/registration/handlers/handler_node_introspected.pytests/integration/registration/workflow/test_workflow_a0_a2.py
**/model_*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Model files must follow naming convention
model_<name>.pywith class nameModel<Name>(e.g.,model_kafka_message.py→ModelKafkaMessage)
Files:
src/omnibase_infra/models/registration/model_node_heartbeat_event.pysrc/omnibase_infra/nodes/effects/models/model_registry_request.py
🧠 Learnings (18)
📓 Common learnings
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T16:55:49.755Z
Learning: Applies to agents/**/*.py : Implement ONEX-compliant agent architecture with four node types: Effect (External I/O), Compute (Pure transforms), Reducer (State/persistence), and Orchestrator (Workflow coordination)
Learnt from: CR
Repo: OmniNode-ai/omniintelligence PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-07T17:50:13.678Z
Learning: Decompose intelligence operations into specialized ONEX nodes following a four-node pattern: Orchestrator (coordinate workflows), Reducer (manage state, FSM transitions), Compute (pure data processing), and Effect (external I/O)
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: All ONEX nodes must conform to the canonical structure, code generation, and interface patterns established in the `node_cli` node, using it as the primary source of truth for directory structure, contract schema patterns, linked document architecture, base state patterns, shared schema references, extensibility patterns, CLI interface declarations, code generation, dependency injection, error handling, testing, and documentation
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: NodeBridgeOrchestrator MUST support multi-step execution workflow coordination with service routing. Target performance: <50ms standard workflows, <150ms with OnexTree intelligence
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T16:32:55.606Z
Learning: All ONEX nodes must conform to the 4-Node Architecture pattern with clear separation of concerns and unidirectional data flow (EFFECT → COMPUTE → REDUCER → ORCHESTRATOR)
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/*.py : All ONEX node implementations must follow dependency injection and protocol-first design patterns as established in the node_cli canonical reference
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: Applies to src/omninode_bridge/events/**/*.py : Kafka event publishing MUST use OnexEnvelopeV1 format with 13 topics for event streaming at all workflow lifecycle stages
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T16:32:55.606Z
Learning: ORCHESTRATOR Nodes must inherit from `NodeOrchestrator` or use `NodeOrchestratorService` and must coordinate workflows, manage node interactions, and handle process/event orchestration
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: Applies to src/omninode_bridge/codegen/**/*.py : Code generation service MUST auto-generate ONEX v2.0 compliant nodes with intelligent mixin injection and quality validation. Generate comprehensive test suites with 90%+ coverage.
📚 Learning: 2025-11-24T17:24:10.209Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/pr.mdc:0-0
Timestamp: 2025-11-24T17:24:10.209Z
Learning: Applies to docs_private/dev_logs/jonah/pr/pr_description_*.md : PR description files must be stamped with an ONEX metadata block at the top using HTML comments format (`<!-- === OmniNode:Metadata === ... <!-- === /OmniNode:Metadata === -->`), and stamping must be idempotent and policy-driven. Do NOT use manual metadata blocks with hash comments.
Applied to files:
docs/design/MVP_EVENT_CATALOG.md
📚 Learning: 2025-11-24T16:33:09.011Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/pr.mdc:0-0
Timestamp: 2025-11-24T16:33:09.011Z
Learning: Applies to docs_private/dev_logs/jonah/pr/pr_description_*.md : All PR description files must be stamped with an ONEX metadata block at the top using HTML comments format (`<!-- === OmniNode:Metadata === ... <!-- === /OmniNode:Metadata === -->`), not hash comments. Stamping must be idempotent and policy-driven.
Applied to files:
docs/design/MVP_EVENT_CATALOG.md
📚 Learning: 2025-12-26T13:16:11.773Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-26T13:16:11.773Z
Learning: Applies to **/*.py : Use `EnumMessageCategory` (values: EVENT, COMMAND, INTENT) for message routing, topic parsing, and dispatcher selection. Use `EnumNodeOutputType` (values: EVENT, COMMAND, INTENT, PROJECTION) for execution shape validation and handler return type validation. PROJECTION is only valid for REDUCER nodes.
Applied to files:
docs/design/MVP_EVENT_CATALOG.md
📚 Learning: 2025-11-30T21:55:10.298Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: Applies to src/omninode_bridge/events/**/*.py : Kafka event publishing MUST use OnexEnvelopeV1 format with 13 topics for event streaming at all workflow lifecycle stages
Applied to files:
docs/design/MVP_EVENT_CATALOG.md
📚 Learning: 2025-11-28T18:58:53.781Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/canonical_patterns.mdc:0-0
Timestamp: 2025-11-28T18:58:53.781Z
Learning: Organize models under `src/omnibase_core/models/` by domain including: base, cli, common, config, core, contracts, discovery, health, infrastructure, logging, metadata, nodes, operations, results, security, service, tools, validation, and workflows
Applied to files:
docs/design/MVP_EVENT_CATALOG.md
📚 Learning: 2025-11-30T21:55:10.298Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: Deviations from omnibase_core standards are only acceptable for: (1) Orchestrator/Reducer nodes (ModelService* disabled), (2) Experimental features being prototyped for upstream, (3) Performance-critical optimizations with benchmark proof, (4) Bridge-specific unique patterns. All deviations require explicit documentation and justification.
Applied to files:
docs/design/MVP_EVENT_CATALOG.md
📚 Learning: 2025-11-24T17:22:32.195Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/canonical_patterns.mdc:0-0
Timestamp: 2025-11-24T17:22:32.195Z
Learning: Follow canonical patterns from reference implementations: use node_cli/v1_0_0/ as primary reference and node_kafka_event_bus/v1_0_0/ for complex backend patterns
Applied to files:
docs/design/MVP_EVENT_CATALOG.md
📚 Learning: 2025-11-30T21:55:10.298Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: Applies to src/omninode_bridge/nodes/**/*.py : All nodes in omninode_bridge MUST use omnibase_core standards (ModelServiceEffect, ModelServiceCompute for effect/compute nodes; NodeOrchestrator, NodeReducer with mixins for orchestrator/reducer nodes)
Applied to files:
docs/design/MVP_EVENT_CATALOG.md
📚 Learning: 2025-11-24T16:32:55.606Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T16:32:55.606Z
Learning: Node communication must use event-driven patterns through `ModelEventEnvelope` from `omnibase_core.models.events.model_event_envelope`
Applied to files:
docs/design/MVP_EVENT_CATALOG.md
📚 Learning: 2025-12-07T17:50:13.678Z
Learnt from: CR
Repo: OmniNode-ai/omniintelligence PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-07T17:50:13.678Z
Learning: Implement Kafka event-driven architecture with proper topic naming using prefix dev.archon-intelligence. and proper event flow pattern with Effect nodes consuming events, processing, and publishing results with Dead Letter Queue routing
Applied to files:
docs/design/MVP_EVENT_CATALOG.md
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/*.py : All ONEX node implementations must follow dependency injection and protocol-first design patterns as established in the node_cli canonical reference
Applied to files:
docs/design/MVP_EVENT_CATALOG.md
📚 Learning: 2025-11-24T17:24:10.209Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/pr.mdc:0-0
Timestamp: 2025-11-24T17:24:10.209Z
Learning: Applies to docs_private/dev_logs/jonah/pr/pr_description_*.md : Timestamps in PR descriptions must use ISO 8601 format with timezone (e.g., 2025-05-05T09:15:00-04:00)
Applied to files:
src/omnibase_infra/models/registration/model_node_heartbeat_event.py
📚 Learning: 2025-11-24T16:32:55.606Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T16:32:55.606Z
Learning: Applies to tests/unit/infrastructure/**/test_*.py : All node implementations must have comprehensive unit tests following the testing pattern in `tests/unit/infrastructure/` with tests for node initialization and node execution
Applied to files:
tests/unit/orchestrators/registration/test_handler_runtime_tick.pytests/unit/orchestrators/registration/test_handler_node_introspected.py
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/introspection.py : All ONEX nodes must include an `introspection.py` file implementing standards-compliant introspection logic
Applied to files:
tests/unit/orchestrators/registration/test_handler_node_introspected.pysrc/omnibase_infra/orchestrators/registration/handlers/handler_node_introspected.py
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/node_tests/**/*.py : All ONEX node tests must be organized in a `node_tests/` directory using scenario-driven testing patterns with fixture-injected tests
Applied to files:
tests/unit/orchestrators/registration/test_handler_node_introspected.py
📚 Learning: 2025-11-28T18:58:53.781Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/canonical_patterns.mdc:0-0
Timestamp: 2025-11-28T18:58:53.781Z
Learning: Applies to **/*.py : Implement Node classes by inheriting from `NodeBase` with proper UUID and `ModelSemVer` fields
Applied to files:
src/omnibase_infra/nodes/effects/models/model_registry_request.py
📚 Learning: 2025-12-06T22:21:32.649Z
Learnt from: CR
Repo: OmniNode-ai/omniagent PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T22:21:32.649Z
Learning: Applies to nodes/**/*.py : Use `omnibase_infra` handlers for OmniIntelligence queries via HttpRestAdapter envelope pattern
Applied to files:
src/omnibase_infra/orchestrators/registration/handlers/handler_node_introspected.py
🧬 Code graph analysis (7)
tests/integration/registration/workflow/conftest.py (1)
tests/helpers/deterministic.py (1)
now(143-154)
src/omnibase_infra/models/registration/model_node_heartbeat_event.py (3)
src/omnibase_infra/nodes/effects/models/model_registry_request.py (1)
validate_timestamp_timezone_aware(120-137)src/omnibase_infra/models/discovery/model_node_introspection_event.py (1)
validate_timestamp_timezone_aware(205-222)src/omnibase_infra/models/registration/model_node_introspection_event.py (1)
validate_timestamp_timezone_aware(147-164)
tests/unit/orchestrators/registration/test_handler_runtime_tick.py (7)
src/omnibase_infra/enums/enum_registration_state.py (1)
EnumRegistrationState(24-258)src/omnibase_infra/models/projection/model_registration_projection.py (1)
ModelRegistrationProjection(39-344)src/omnibase_infra/models/registration/events/model_node_liveness_expired.py (1)
ModelNodeLivenessExpired(21-100)src/omnibase_infra/models/registration/events/model_node_registration_ack_timed_out.py (1)
ModelNodeRegistrationAckTimedOut(21-100)src/omnibase_infra/orchestrators/registration/handlers/handler_runtime_tick.py (2)
HandlerRuntimeTick(59-309)handle(116-177)src/omnibase_infra/projectors/projection_reader_registration.py (1)
ProjectionReaderRegistration(49-660)src/omnibase_infra/runtime/models/model_runtime_tick.py (1)
ModelRuntimeTick(61-190)
tests/unit/orchestrators/registration/test_handler_node_registration_acked.py (10)
src/omnibase_infra/enums/enum_registration_state.py (1)
EnumRegistrationState(24-258)src/omnibase_infra/models/projection/model_registration_projection.py (1)
ModelRegistrationProjection(39-344)src/omnibase_infra/models/registration/model_node_capabilities.py (1)
ModelNodeCapabilities(13-167)src/omnibase_infra/models/registration/commands/model_node_registration_acked.py (1)
ModelNodeRegistrationAcked(29-105)src/omnibase_infra/models/registration/events/model_node_became_active.py (1)
ModelNodeBecameActive(25-100)src/omnibase_infra/models/registration/events/model_node_registration_ack_received.py (1)
ModelNodeRegistrationAckReceived(21-95)src/omnibase_infra/orchestrators/registration/handlers/handler_node_registration_acked.py (3)
HandlerNodeRegistrationAcked(117-357)get_liveness_interval_seconds(74-114)handle(173-301)src/omnibase_infra/projectors/projection_reader_registration.py (1)
ProjectionReaderRegistration(49-660)tests/unit/registration/effect/conftest.py (1)
correlation_id(243-249)src/omnibase_infra/orchestrators/registration/handlers/handler_runtime_tick.py (1)
handle(116-177)
tests/unit/orchestrators/registration/test_handler_node_introspected.py (5)
src/omnibase_infra/enums/enum_registration_state.py (1)
EnumRegistrationState(24-258)src/omnibase_infra/models/registration/model_node_introspection_event.py (1)
ModelNodeIntrospectionEvent(24-164)src/omnibase_infra/models/registration/events/model_node_registration_initiated.py (1)
ModelNodeRegistrationInitiated(29-104)src/omnibase_infra/orchestrators/registration/handlers/handler_node_introspected.py (2)
HandlerNodeIntrospected(77-226)handle(123-226)src/omnibase_infra/projectors/projection_reader_registration.py (1)
ProjectionReaderRegistration(49-660)
src/omnibase_infra/nodes/effects/models/model_registry_request.py (3)
src/omnibase_infra/models/registration/model_node_heartbeat_event.py (1)
validate_timestamp_timezone_aware(103-120)src/omnibase_infra/event_bus/models/model_event_headers.py (1)
validate_timestamp_timezone_aware(71-88)src/omnibase_infra/models/discovery/model_node_introspection_event.py (1)
validate_timestamp_timezone_aware(205-222)
src/omnibase_infra/orchestrators/registration/handlers/handler_node_introspected.py (3)
src/omnibase_infra/enums/enum_registration_state.py (1)
EnumRegistrationState(24-258)src/omnibase_infra/models/registration/events/model_node_registration_initiated.py (1)
ModelNodeRegistrationInitiated(29-104)src/omnibase_infra/projectors/projection_reader_registration.py (1)
ProjectionReaderRegistration(49-660)
🔇 Additional comments (37)
src/omnibase_infra/models/registration/model_node_heartbeat_event.py (2)
41-53: LGTM! Example updated to reflect explicit timezone-aware timestamps.The example now correctly demonstrates the expected usage pattern with explicit UTC timezone and required timestamp injection, aligning with the new validation requirements.
98-120: Previous review comment addressed—excellent implementation!The timezone-aware validator has been correctly implemented and directly addresses the prior review feedback. The implementation:
- ✅ Enforces timezone-aware datetimes with clear validation logic
- ✅ Provides helpful error message with concrete examples
- ✅ Follows the exact pattern used in 3+ other files across the codebase (model_registry_request.py, model_node_introspection_event.py variants)
- ✅ Properly documented with complete docstring
- ✅ Removes default_factory to enforce explicit timestamp injection per PR objectives
The breaking change (requiring explicit timestamp) aligns with the stated goal of improving testability through explicit time injection.
src/omnibase_infra/nodes/effects/models/model_registry_request.py (1)
112-137: LGTM! Timezone validation now enforced.The timestamp field correctly requires explicit injection and includes a field validator that enforces timezone awareness, matching the canonical pattern used in
ModelNodeIntrospectionEvent,ModelNodeHeartbeatEvent, andModelEventHeaders. This addresses the previous review concern and aligns with the PR's claim of "pervasive...timezone validation."tests/integration/registration/workflow/conftest.py (1)
590-590: LGTM! Dual factory design provides flexibility.The
introspection_event_factoryfixture uses live timestamps (datetime.now(UTC)), while the separatedeterministic_introspection_event_factory(lines 1280-1336) usesdeterministic_clock.now(). This intentional design allows tests to choose between live timestamps (for quick integration tests) or deterministic timestamps (for reproducible unit tests).Both approaches satisfy the timezone-aware requirement enforced by the model's field validator.
Also applies to: 614-614
src/omnibase_infra/orchestrators/registration/handlers/handler_runtime_tick.py (5)
1-57: LGTM - Well-documented module header and imports.The module docstring clearly explains the detection logic, deduplication strategy, and coroutine safety guarantees. Imports are properly organized with TYPE_CHECKING for BaseModel.
59-106: LGTM - Clear class documentation with decision matrix.The docstring includes a comprehensive example demonstrating the time injection pattern and correctly notes that
last_heartbeat_atmay beNonewhen no heartbeats were ever received.
108-177: LGTM - Handle method follows time injection pattern correctly.The timezone validation at lines 142-146 addresses the past review concern. The method correctly:
- Validates timezone-awareness before processing
- Uses the injected
nowfor both ack and liveness checks- Logs event counts with correlation_id for tracing
179-245: LGTM - Ack timeout detection with defensive double-check.The defensive
needs_ack_timeout_event()check at line 212 provides deduplication safety even if the reader returns stale data. The assert at line 217 is appropriate as a programming invariant guard.
247-309: LGTM - Liveness expiry detection correctly uses projection.last_heartbeat_at.The comment at lines 283-285 correctly documents the semantic difference between
last_heartbeat_at(actual heartbeat) andregistered_at(registration time). This addresses the past review concern about incorrect fallback usage.tests/unit/orchestrators/registration/test_handler_runtime_tick.py (6)
1-93: LGTM - Well-structured test helpers and fixtures.The helpers provide clear, reusable test setup:
create_mock_projection_reader()properly mocks both ack and liveness methodscreate_projection()allows flexible state and deadline configuration- Deterministic
TEST_NOWensures reproducible tests
96-191: LGTM - Thorough ack timeout detection tests.Tests cover:
- G2 requirement 5: Ack timeout detection with field validation
- Both AWAITING_ACK and ACCEPTED states
- Correct causation_id linkage to tick_id
- Time injection verification (emitted_at == TEST_NOW)
193-259: LGTM - Deduplication tests validate emission marker behavior.Tests correctly verify that
ack_timeout_emitted_atprevents duplicate event emission, satisfying G2 requirement 6.
261-328: LGTM - Liveness expiry tests with correct last_heartbeat_at semantics.The comment at lines 298-302 correctly explains why
last_heartbeat_atisNone- aligning with the handler's documented behavior and theModelNodeLivenessExpiredcontract.
331-427: LGTM - Multiple timeout and no-event scenarios covered.Tests verify:
- Multiple ack timeouts emit multiple events
- Both ack and liveness timeouts can occur in the same tick
- Empty projection results yield empty event list
430-563: LGTM - Time injection and timezone validation tests.Tests verify:
- Injected
nowis passed to projection reader queriesemitted_aton timeout events uses injectednow- Naive datetime raises
ValueErrorwith descriptive message- Timezone-aware datetime is accepted
tests/unit/orchestrators/registration/test_handler_node_registration_acked.py (5)
1-93: LGTM - Well-organized test setup with clear helpers.The module properly imports the handler's configuration constants (
DEFAULT_LIVENESS_INTERVAL_SECONDS,ENV_LIVENESS_INTERVAL_SECONDS,get_liveness_interval_seconds) for testing configuration resolution.
95-184: LGTM - Activation event tests validate G2 requirement 7.Tests verify:
- Both
NodeRegistrationAckReceivedandNodeBecameActiveare emitted- Correct field values (node_id, entity_id, correlation_id, causation_id)
- Time injection pattern (emitted_at == TEST_NOW)
- Liveness deadline calculation (now + DEFAULT_LIVENESS_INTERVAL_SECONDS)
- Both AWAITING_ACK and ACCEPTED states trigger activation
186-351: LGTM - Comprehensive idempotency and state handling tests.Tests cover:
- G2 requirement 8: Duplicate ack handling (ACTIVE, ACK_RECEIVED states)
- Unknown node handling
- Premature ack (PENDING_REGISTRATION)
- Terminal states (parametrized: ACK_TIMED_OUT, REJECTED, LIVENESS_EXPIRED)
353-491: LGTM - Liveness deadline, capabilities, and causation tests.Tests verify:
- Liveness deadline uses injected
now- Custom liveness interval is respected
- Capabilities are captured in BecameActive event
- Both events link to command via causation_id
494-644: LGTM - Configuration resolution and timezone validation tests.Tests for
get_liveness_interval_seconds()verify:
- Default value (60 seconds)
- Explicit value priority over env var
- Env var usage when no explicit value
- Error handling for invalid env var
Timezone tests verify naive datetime rejection and aware datetime acceptance.
tests/unit/orchestrators/registration/test_handler_node_introspected.py (5)
1-82: LGTM - Clear test setup with deterministic helpers.Helpers create mock projection reader, projections with configurable state, and introspection events with optional node_id and timestamp.
85-143: LGTM - G2 requirement 3 tests verify registration initiation.Tests verify:
- New nodes (projection=None) trigger registration
- Emitted event has correct node_id, entity_id, correlation_id
- causation_id links to introspection event's correlation_id
- emitted_at equals injected
now- registration_attempt_id is generated
145-208: LGTM - G2 requirement 4 tests verify blocking state handling.Parametrized test covers all blocking states:
- PENDING_REGISTRATION, ACCEPTED, AWAITING_ACK, ACK_RECEIVED, ACTIVE
All return empty list (no registration initiated).
211-315: LGTM - Retriable state tests verify re-registration.Parametrized and individual tests verify:
- LIVENESS_EXPIRED, REJECTED, ACK_TIMED_OUT states trigger new registration
- Emitted event has correct node_id
318-473: LGTM - Event field validation and timezone tests.Tests verify:
- Unique registration_attempt_id per emission
- causation_id links to introspection event's correlation_id
- entity_id == node_id
- Projection query uses correct parameters
- Timezone validation (naive rejected, aware accepted)
src/omnibase_infra/orchestrators/registration/handlers/handler_node_introspected.py (4)
1-52: LGTM - Clear module documentation and organized imports.The docstring clearly explains the decision logic for when to emit vs. skip registration. Imports are properly organized with TYPE_CHECKING for BaseModel.
56-74: LGTM - State classification using immutable frozensets.Using
frozensetfor_RETRIABLE_STATESand_BLOCKING_STATESensures immutability at module level, which is good practice for constants used in decision logic.
77-121: LGTM - Handler class with clear state decision matrix.The docstring provides a complete decision matrix matching the implementation. The example demonstrates the time injection pattern correctly.
123-226: LGTM - Handle method correctly implements decision logic and time injection.Key observations:
- Timezone validation at lines 149-153 ensures consistent behavior
- State decision logic at lines 168-202 correctly handles all cases
- Event creation at lines 208-215 correctly:
- Sets
emitted_at=now(time injection pattern)- Links
causation_idto triggering event'scorrelation_id- Generates unique
registration_attempt_idThe
causation_id=event.correlation_idat line 212 is appropriate sinceModelNodeIntrospectionEventusescorrelation_idas its primary identifier for tracing purposes.src/omnibase_infra/orchestrators/registration/handlers/handler_node_registration_acked.py (5)
1-61: LGTM - Clear module documentation and organized imports.The docstring explains the processing logic for each possible state. The use of
Finalfor constants provides type safety.
64-114: LGTM - Configuration resolution with clear priority order.
get_liveness_interval_seconds()correctly:
- Prioritizes explicit value over environment variable
- Falls back to default constant
- Raises descriptive
ValueErrorfor invalid env var values- Chains the exception with
from efor proper traceback
117-171: LGTM - Handler initialization with configurable liveness interval.The constructor correctly resolves the liveness interval using the configuration function, allowing flexibility via constructor parameter, environment variable, or default.
173-301: LGTM - Handle method with comprehensive state coverage.The method correctly:
- Validates timezone-awareness at lines 198-202
- Handles all FSM states per the documented decision matrix:
- ACCEPTED/AWAITING_ACK → emit activation events
- ACK_RECEIVED/ACTIVE → duplicate ack (idempotent no-op)
- PENDING_REGISTRATION → ack too early
- ACK_TIMED_OUT → ack too late
- Terminal states → meaningless ack
- Unknown state → logged warning
- Uses appropriate log levels (warning for unexpected, debug for duplicates)
303-365: LGTM - Activation events correctly use time injection pattern.The
_emit_activation_events()method correctly:
- Calculates
liveness_deadlinefrom injectednow(line 326)- Sets
emitted_at=nowon both events (lines 334, 344)- Links
causation_idtocommand.command_id- Captures capabilities from projection
The
__all__export includes all public symbols.docs/design/MVP_EVENT_CATALOG.md (3)
312-312: Source file paths are correctly documented.The paths at lines 312 and 376 for
ModelNodeIntrospectionEventandModelNodeHeartbeatEventare accurate and resolve to the actual locations in the codebase (not underevents/subdirectory). These were correctly updated from prior review feedback.Also applies to: 376-376
159-171: Time-injection rules are clearly documented and aligned with code.The example properly shows explicit timestamp injection with timezone-aware datetime, and the clarification at line 171 correctly states that the
timestampfield has no default value and must be explicitly provided. This aligns well with the best practice guidance at line 808.
844-889: Import paths are comprehensive and correctly disambiguate registration vs discovery models.The import section clearly distinguishes between the two
ModelNodeIntrospectionEventvariants (registration vs discovery with alias), addressing potential confusion. All documented import paths are valid and exist in their source modules.
Pull Request #79 Review: C1 Registration OrchestratorExecutive SummaryRECOMMENDATION: APPROVE WITH MINOR OBSERVATIONS ✅ PR #79 successfully implements the first orchestrator node in omnibase_infra, establishing a strong declarative pattern for all future orchestrators. The implementation demonstrates excellent architectural compliance with ONEX principles and CLAUDE.md guidelines. Key Metrics:
1. ONEX Compliance: EXCELLENT ✅1.1 Declarative Node Pattern ✅Status: PERFECT IMPLEMENTATION The
Evidence from tests (test_node_registration_orchestrator.py:85-106): 1.2 Container-Based Dependency Injection ✅All handlers use constructor injection with proper typing. No direct instantiation. 1.3 Strong Typing (Zero
|
…irectory [OMN-952]
Move handlers from orchestrators/registration/ into nodes/node_registration_orchestrator/
following ONEX co-location principle. All node-related code now lives under one path.
Changes:
- Move handlers/ to nodes/node_registration_orchestrator/handlers/
- Move tests to tests/unit/nodes/node_registration_orchestrator/
- Update all imports from orchestrators.registration.handlers to
nodes.node_registration_orchestrator.handlers
- Remove empty orchestrators/ directory
New import pattern:
from omnibase_infra.nodes.node_registration_orchestrator.handlers import (
HandlerNodeIntrospected,
HandlerRuntimeTick,
)
Pull Request Review: Registration Orchestrator ImplementationOverviewThis PR implements the first orchestrator node in omnibase_infra, establishing a critical pattern for event-driven workflow coordination. The implementation demonstrates excellent adherence to ONEX principles with comprehensive test coverage (60 unit tests). Verdict: APPROVE with minor recommendations Strengths1. Exemplary Declarative Architecture
The NodeRegistrationOrchestrator class (node.py:131-208) is a clean shell with only setter methods, delegating all logic to base classes. 2. Robust Time Injection Pattern
This enables deterministic timeout evaluation and testability without mocking system clock. 3. Comprehensive Test Coverage60 unit tests covering:
4. Production-Ready Error Handling
5. Excellent Documentation
Issues and Recommendations1. Potential Race Condition in Projection Queries (MEDIUM)Location: handler_runtime_tick.py:179-245 If two RuntimeTick events process concurrently, both might emit the same timeout event before either updates the emission marker. Recommendation: Use PostgreSQL atomic UPDATE...RETURNING pattern to claim timeouts atomically. This ensures only one tick can claim each timeout. 2. Heartbeat Handler Integration Tests Missing (MEDIUM)Location: node.py:267-328 The handle_heartbeat() method needs integration tests validating:
3. Contract Complexity Warning (LOW)Location: contract.yaml:1-10 The TODO acknowledges potential complexity at 460 lines. Consider extracting to subcontracts when exceeding 500 lines or adding 3+ more handlers. 4. Performance Optimization Opportunity (LOW)Location: handler_runtime_tick.py:150-177 Use asyncio.gather for parallel timeout/liveness queries to reduce latency by ~50%. Security ConsiderationsNo critical security issues found.
Enhancement suggestion: Consider rate limiting registration attempts. Best Practices ValidationAll ONEX best practices followed:
Final VerdictAPPROVE This PR demonstrates exceptional quality and serves as a gold standard for ONEX orchestrator implementation. The identified issues are minor and can be addressed in follow-up PRs. Recommended Next Steps:
Congratulations on this excellent implementation! |
Combined exports from both branches: - ModelCircuitBreakerConfig (from main) - PerformanceMetricsCacheDict (from feature branch) - ProtocolEventBusLike (from feature branch)
PR Review: Registration Orchestrator Implementation [C1]OverviewThis PR implements the first ONEX orchestrator node for omnibase_infra, establishing patterns for all future orchestrators. The implementation demonstrates excellent adherence to ONEX principles with strong declarative design, comprehensive testing, and robust error handling. ✅ Strengths1. Exemplary Declarative ArchitectureThe orchestrator node perfectly follows the ONEX declarative pattern:
Example from node.py:332: class NodeRegistrationOrchestrator(NodeOrchestrator):
"""Declarative orchestrator - all behavior defined in contract.yaml."""
pass # No custom code - driven entirely by contract2. Robust Time Injection Pattern (OMN-973)All handlers correctly implement injected time for deterministic execution:
Example from handler_node_introspected.py:148-154: if now.tzinfo is None:
raise ValueError(
"now must be timezone-aware. Use datetime.now(UTC) or "
"datetime(..., tzinfo=timezone.utc) instead of naive datetime."
)3. Comprehensive Test Coverage60 unit tests covering all G2 acceptance criteria:
Test file: 4. Excellent Documentation
5. Strong Error Handling
📝 Areas for Improvement1. Contract ComplexityThe From contract.yaml:10-33: # SUBCONTRACT ARCHITECTURE NOTE
# Consider extracting:
# - handler_routing section (246 lines) -> routing_subcontract
# - consumed_events/published_events -> event_subcontract
# - coordination_rules -> state_subcontractRecommendation: This is a good future refactoring when the contract exceeds 500 lines. Current size is manageable. 2. Type Safety in Handler RoutingSome handlers use From handler_node_registration_acked.py:236-262: projection: object, # ModelRegistrationProjection
...
assert isinstance(projection, ModelRegistrationProjection)Recommendation: Use from typing import TYPE_CHECKING
if TYPE_CHECKING:
from omnibase_infra.models.projection.model_registration_projection import (
ModelRegistrationProjection,
)
def _emit_activation_events(
self,
projection: ModelRegistrationProjection, # Proper type
...
) -> list[BaseModel]:
# No assert needed3. Event Model Defaults Could Enforce Time InjectionEvent models have From model_node_registration_initiated.py:82-85: emitted_at: datetime = Field(
default_factory=lambda: datetime.now(UTC), # Convenient but risky
description="Timestamp when the orchestrator emitted this event (UTC)",
)Recommendation: Consider requiring explicit 4. Minor Test EnhancementTests verify event types and IDs but don't always verify Suggestion: Add assertions like: assert ack_received.emitted_at == TEST_NOW
assert became_active.emitted_at == TEST_NOWThis would catch violations of the time injection pattern more explicitly. 🔒 Security Review✅ No Security Issues Found
🎯 ONEX Compliance Check
📊 Test Coverage Analysis
Test distribution:
🚀 RecommendationsHigh Priority
Medium Priority (Future Iterations)
Low Priority (Nice to Have)
🎖️ ConclusionRating: ⭐⭐⭐⭐⭐ (5/5) This PR represents exemplary ONEX architecture and establishes the gold standard for future orchestrator implementations. The declarative design, comprehensive testing, and thorough documentation make this a model for the rest of the codebase. Key Achievements:
Recommendation: APPROVE ✅ This PR unblocks critical downstream work (C2: Durable Timeout Handling, G2: Orchestrator Tests) and sets a high bar for code quality. The minor improvements suggested are enhancements for future iterations, not blockers. Excellent work! 🎉 Reviewed by: Claude Sonnet 4.5 |
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/omnibase_infra/runtime/registry/model_message_type_entry.py (1)
62-68: Fix broken docstring examples - missing requiredregistered_atfield.All code examples in the docstrings construct
ModelMessageTypeEntrywithout providing the now-requiredregistered_atfield, causing them to fail.🔎 Proposed fix for all docstring examples
Example: + >>> from datetime import datetime, timezone >>> entry = ModelMessageTypeEntry( ... message_type="UserCreated", ... handler_ids=["user-event-handler", "audit-logger"], ... allowed_categories=[EnumMessageCategory.EVENT], ... domain_constraint=ModelDomainConstraint(owning_domain="user"), ... description="User creation event", + ... registered_at=datetime.now(timezone.utc), ... )Apply similar fixes to examples at:
- Lines 180-185 (supports_category example)
- Lines 208-213 (validate_category example)
- Lines 245-250 (with_additional_handler example)
Also applies to: 180-185, 208-213, 245-250
♻️ Duplicate comments (1)
src/omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_introspected.py (1)
208-215: Causation ID uses correlation_id from triggering event - verify this is intentional.Line 212 sets
causation_id=event.correlation_id. A past review comment noted thatcausation_idshould typically be themessage_idof the triggering event for proper causal tracing, not itscorrelation_id. However,ModelNodeIntrospectionEventmay not have amessage_idfield.If this is the intended design (using correlation_id as the causal link when message_id is unavailable), consider adding a brief inline comment documenting this architectural decision.
#!/bin/bash # Check if ModelNodeIntrospectionEvent has a message_id field ast-grep --pattern 'class ModelNodeIntrospectionEvent { $$$ }' # Also check the event model definition fd -t f "model_node_introspection_event.py" --exec cat {}
🧹 Nitpick comments (5)
src/omnibase_infra/runtime/registry/model_message_type_entry.py (2)
158-162: Consider adding validation for the UTC requirement.The field description states that
registered_atmust be UTC, but there's no validator to enforce this. While Python'sdatetimeobjects can be timezone-aware or naive, the requirement isn't validated.Optional: Add UTC timezone validation
+ @field_validator("registered_at") + @classmethod + def validate_registered_at_utc(cls, value: datetime) -> datetime: + """Validate that registered_at is timezone-aware and in UTC. + + Args: + value: The datetime to validate. + + Returns: + The validated datetime. + + Raises: + ValueError: If the datetime is naive or not in UTC. + """ + if value.tzinfo is None: + msg = "registered_at must be timezone-aware (UTC)" + raise ValueError(msg) + if value.utcoffset() != timedelta(0): + msg = "registered_at must be in UTC timezone" + raise ValueError(msg) + return value + # Timestamps - MUST be explicitly injected (no default_factory for testability) registered_at: datetime = Field(Note: This would require adding
from datetime import timedeltato the imports.
13-13: Update terminology to match codebase standards.The PR summary mentions updating terminology "from thread-safety to coroutine-safety across the codebase," but this file still uses "thread-safe" terminology in lines 13 and 75.
Suggested terminology update
Design Principles: - Each entry maps a message type to one or more handler implementations - Topic category constraints define where message types can appear - Domain ownership is tracked for cross-domain validation - - Immutable entries for thread-safe concurrent access + - Immutable entries for coroutine-safe concurrent access- Thread Safety: - This model is immutable (frozen=True) and thread-safe for concurrent access. + Coroutine Safety: + This model is immutable (frozen=True) and coroutine-safe for concurrent access.Also applies to: 75-75
tests/unit/runtime/test_container_wiring_registration.py (1)
24-144: Container wiring tests cover the key success and failure pathsThe tests for
wire_registration_handlersand theget_*_from_containerhelpers exercise all the important behaviors: registration summary contents, correct interface types passed toregister_instance, metadata propagation forliveness_interval_seconds, and the two main error modes (registry exception vs. missingservice_registry). Mocks are shaped correctly aroundProjectionReaderRegistrationand the handler classes, and theRuntimeErrormatch strings align with the documented contract incontainer_wiring.py. The implementation looks solid here.Also applies to: 146-297
src/omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_runtime_tick.py (2)
210-230: Consider removing redundant assertion or softening to a log.Line 217-220 uses
assertwith a message to guaranteeack_deadline is not Noneafterneeds_ack_timeout_event()returns True. While the invariant is documented, usingassertin production code can be disabled with-Oflag.Consider either:
- Keep the assertion (acceptable for invariant documentation)
- Use an explicit
ifwith earlycontinuefor defense-in-depthThe current implementation is acceptable given the well-documented invariant.
232-244: Minor: Logging usesprojection.ack_deadlineafter assertion guarantees it's not None.Lines 237-240 conditionally format
ack_deadlinewith anifcheck, but line 228 already usedack_deadline(assigned fromprojection.ack_deadline). The conditional formatting is defensive but slightly redundant given the assertion.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Lite
📒 Files selected for processing (27)
src/omnibase_infra/handlers/handler_consul.pysrc/omnibase_infra/handlers/handler_vault.pysrc/omnibase_infra/mixins/__init__.pysrc/omnibase_infra/mixins/mixin_async_circuit_breaker.pysrc/omnibase_infra/mixins/mixin_node_introspection.pysrc/omnibase_infra/models/dispatch/__init__.pysrc/omnibase_infra/nodes/node_registration_orchestrator/__init__.pysrc/omnibase_infra/nodes/node_registration_orchestrator/handlers/__init__.pysrc/omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_heartbeat.pysrc/omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_introspected.pysrc/omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_registration_acked.pysrc/omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_runtime_tick.pysrc/omnibase_infra/nodes/node_registration_orchestrator/node.pysrc/omnibase_infra/orchestrators/__init__.pysrc/omnibase_infra/orchestrators/registration/__init__.pysrc/omnibase_infra/runtime/container_wiring.pysrc/omnibase_infra/runtime/registry/model_message_type_entry.pysrc/omnibase_infra/validation/validation_exemptions.yamltests/integration/registration/handlers/conftest.pytests/integration/registration/handlers/test_handler_node_heartbeat_integration.pytests/unit/handlers/test_handler_http.pytests/unit/handlers/test_handler_vault.pytests/unit/handlers/test_handler_vault_concurrency.pytests/unit/nodes/node_registration_orchestrator/test_handler_node_introspected.pytests/unit/nodes/node_registration_orchestrator/test_handler_node_registration_acked.pytests/unit/nodes/node_registration_orchestrator/test_handler_runtime_tick.pytests/unit/runtime/test_container_wiring_registration.py
💤 Files with no reviewable changes (3)
- tests/unit/handlers/test_handler_vault.py
- src/omnibase_infra/orchestrators/registration/init.py
- src/omnibase_infra/orchestrators/init.py
✅ Files skipped from review due to trivial changes (1)
- src/omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_heartbeat.py
🚧 Files skipped from review as they are similar to previous changes (8)
- src/omnibase_infra/handlers/handler_vault.py
- src/omnibase_infra/handlers/handler_consul.py
- tests/unit/handlers/test_handler_http.py
- src/omnibase_infra/mixins/init.py
- src/omnibase_infra/models/dispatch/init.py
- src/omnibase_infra/nodes/node_registration_orchestrator/node.py
- tests/unit/handlers/test_handler_vault_concurrency.py
- src/omnibase_infra/validation/validation_exemptions.yaml
🧰 Additional context used
📓 Path-based instructions (3)
**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.py: NEVER useAnytype - Always use specific types. For generic dispatchers accepting any payload type, useModelEventEnvelope[object]instead ofAny.
All data structures must be proper Pydantic models
Each file contains exactly oneModel*class - One model per file
UseX | None(PEP 604 union syntax) for nullable types instead ofOptional[X]
For generic dispatchers and protocol definitions accepting any payload type, useModelEventEnvelope[object]instead ofModelEventEnvelope[Any]to satisfy the 'no Any types' rule while maintaining necessary flexibility
All services MUST useModelONEXContainerfor dependency injection via container initialization patterncontainer = ModelONEXContainer()followed by service resolution
RaiseOnexError(...) from e- Only use OnexError for error propagation, never use other exception types
Use Protocol resolution through duck typing viaisinstance(obj, ProtocolType)pattern - never use direct type checking for protocol implementations
Node Archetypes and Core Models (NodeEffect, NodeCompute, NodeReducer, NodeOrchestrator and their I/O models) must be imported fromomnibase_core.nodes. Infrastructure extends base archetypes from core - never define new node archetypes in infra layer.
UseEnumMessageCategory(values: EVENT, COMMAND, INTENT) for message routing, topic parsing, and dispatcher selection. UseEnumNodeOutputType(values: EVENT, COMMAND, INTENT, PROJECTION) for execution shape validation and handler return type validation. PROJECTION is only valid for REDUCER nodes.
All infrastructure adapters and services MUST useMixinAsyncCircuitBreakerfor fault tolerance. Use_init_circuit_breaker()in init with appropriate threshold and reset_timeout. Always holdself._circuit_breaker_lockwhen calling circuit breaker methods.
Correlation IDs must be UUID format. Always propagatecorrelation_idfrom incoming requests to error context. Auto-generate usinguuid4()if not present. Include...
Files:
tests/unit/nodes/node_registration_orchestrator/test_handler_node_introspected.pytests/unit/nodes/node_registration_orchestrator/test_handler_runtime_tick.pysrc/omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_runtime_tick.pytests/unit/runtime/test_container_wiring_registration.pytests/integration/registration/handlers/conftest.pysrc/omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_introspected.pysrc/omnibase_infra/mixins/mixin_async_circuit_breaker.pysrc/omnibase_infra/nodes/node_registration_orchestrator/__init__.pytests/unit/nodes/node_registration_orchestrator/test_handler_node_registration_acked.pysrc/omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_registration_acked.pysrc/omnibase_infra/nodes/node_registration_orchestrator/handlers/__init__.pysrc/omnibase_infra/mixins/mixin_node_introspection.pytests/integration/registration/handlers/test_handler_node_heartbeat_integration.pysrc/omnibase_infra/runtime/registry/model_message_type_entry.pysrc/omnibase_infra/runtime/container_wiring.py
**/mixin_*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Mixin files must follow naming convention
mixin_<name>.pywith class nameMixin<Name>(e.g.,mixin_health_check.py→MixinHealthCheck)
Files:
src/omnibase_infra/mixins/mixin_async_circuit_breaker.pysrc/omnibase_infra/mixins/mixin_node_introspection.py
**/model_*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Model files must follow naming convention
model_<name>.pywith class nameModel<Name>(e.g.,model_kafka_message.py→ModelKafkaMessage)
Files:
src/omnibase_infra/runtime/registry/model_message_type_entry.py
🧠 Learnings (23)
📓 Common learnings
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T16:32:55.606Z
Learning: ORCHESTRATOR Nodes must inherit from `NodeOrchestrator` or use `NodeOrchestratorService` and must coordinate workflows, manage node interactions, and handle process/event orchestration
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T16:55:49.755Z
Learning: Applies to agents/**/*.py : Implement ONEX-compliant agent architecture with four node types: Effect (External I/O), Compute (Pure transforms), Reducer (State/persistence), and Orchestrator (Workflow coordination)
Learnt from: CR
Repo: OmniNode-ai/omniintelligence PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-07T17:50:13.678Z
Learning: Implement Kafka event-driven architecture with proper topic naming using prefix dev.archon-intelligence. and proper event flow pattern with Effect nodes consuming events, processing, and publishing results with Dead Letter Queue routing
Learnt from: CR
Repo: OmniNode-ai/omniarchon PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-29T17:13:38.776Z
Learning: Use event-driven architecture with Kafka topics for asynchronous processing: enrichment, code analysis, manifest processing, and entity embedding pipelines.
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/canonical_patterns.mdc:0-0
Timestamp: 2025-11-24T17:22:32.195Z
Learning: Follow canonical patterns from reference implementations: use node_cli/v1_0_0/ as primary reference and node_kafka_event_bus/v1_0_0/ for complex backend patterns
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T16:55:49.755Z
Learning: Maintain complete event history with Kafka persistent storage for all agent routing, manifest injection, and execution log events
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: All ONEX nodes must use the node_kafka_event_bus as a secondary reference only for complex backend and event bus logic and advanced configuration patterns
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: Applies to src/omninode_bridge/events/**/*.py : Kafka event publishing MUST use OnexEnvelopeV1 format with 13 topics for event streaming at all workflow lifecycle stages
📚 Learning: 2025-11-24T16:32:55.606Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T16:32:55.606Z
Learning: Applies to tests/unit/infrastructure/**/test_*.py : All node implementations must have comprehensive unit tests following the testing pattern in `tests/unit/infrastructure/` with tests for node initialization and node execution
Applied to files:
tests/unit/nodes/node_registration_orchestrator/test_handler_node_introspected.pytests/unit/nodes/node_registration_orchestrator/test_handler_runtime_tick.pytests/unit/nodes/node_registration_orchestrator/test_handler_node_registration_acked.py
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/introspection.py : All ONEX nodes must include an `introspection.py` file implementing standards-compliant introspection logic
Applied to files:
tests/unit/nodes/node_registration_orchestrator/test_handler_node_introspected.pysrc/omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_introspected.py
📚 Learning: 2025-11-30T21:55:10.298Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: Applies to tests/bridge_nodes/**/*.py : All Bridge Node implementations MUST include comprehensive test coverage with focus on critical paths (event schemas, entity models). Target: 90%+ coverage for critical components.
Applied to files:
tests/unit/nodes/node_registration_orchestrator/test_handler_runtime_tick.py
📚 Learning: 2025-11-24T17:23:49.777Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T17:23:49.777Z
Learning: Applies to **/node_*/v[0-9]*_[0-9]*_[0-9]*/node_tests/**/*.py : All ONEX node tests must be organized in a `node_tests/` directory using scenario-driven testing patterns with fixture-injected tests
Applied to files:
tests/unit/nodes/node_registration_orchestrator/test_handler_runtime_tick.pytests/integration/registration/handlers/conftest.py
📚 Learning: 2025-12-07T17:50:13.678Z
Learnt from: CR
Repo: OmniNode-ai/omniintelligence PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-07T17:50:13.678Z
Learning: Organize tests following the structure: tests/conftest.py for shared fixtures, tests/unit/ for unit tests (no infrastructure), tests/integration/ for integration tests (requires Kafka/DBs), tests/nodes/ for node-specific tests
Applied to files:
tests/unit/nodes/node_registration_orchestrator/test_handler_runtime_tick.py
📚 Learning: 2025-12-06T22:21:32.649Z
Learnt from: CR
Repo: OmniNode-ai/omniagent PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T22:21:32.649Z
Learning: Applies to nodes/**/*.py : Use `omnibase_infra` handlers for OmniIntelligence queries via HttpRestAdapter envelope pattern
Applied to files:
tests/integration/registration/handlers/conftest.pysrc/omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_introspected.pysrc/omnibase_infra/nodes/node_registration_orchestrator/__init__.pysrc/omnibase_infra/nodes/node_registration_orchestrator/handlers/__init__.pytests/integration/registration/handlers/test_handler_node_heartbeat_integration.py
📚 Learning: 2025-12-06T22:21:32.649Z
Learnt from: CR
Repo: OmniNode-ai/omniagent PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T22:21:32.649Z
Learning: Applies to nodes/effect/**/*.py : Use handler envelopes from `omnibase_infra` for all I/O operations (HTTP, database, Kafka) instead of custom clients
Applied to files:
tests/integration/registration/handlers/conftest.pysrc/omnibase_infra/nodes/node_registration_orchestrator/__init__.pysrc/omnibase_infra/nodes/node_registration_orchestrator/handlers/__init__.pytests/integration/registration/handlers/test_handler_node_heartbeat_integration.py
📚 Learning: 2025-11-24T16:32:55.606Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T16:32:55.606Z
Learning: ORCHESTRATOR Nodes must inherit from `NodeOrchestrator` or use `NodeOrchestratorService` and must coordinate workflows, manage node interactions, and handle process/event orchestration
Applied to files:
tests/integration/registration/handlers/conftest.pysrc/omnibase_infra/nodes/node_registration_orchestrator/__init__.py
📚 Learning: 2025-12-26T13:16:11.773Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-26T13:16:11.773Z
Learning: Applies to **/*.py : Node Archetypes and Core Models (NodeEffect, NodeCompute, NodeReducer, NodeOrchestrator and their I/O models) must be imported from `omnibase_core.nodes`. Infrastructure extends base archetypes from core - never define new node archetypes in infra layer.
Applied to files:
tests/integration/registration/handlers/conftest.pysrc/omnibase_infra/nodes/node_registration_orchestrator/handlers/__init__.py
📚 Learning: 2025-11-30T21:55:10.298Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: Applies to src/omninode_bridge/nodes/**/*.py : All nodes in omninode_bridge MUST use omnibase_core standards (ModelServiceEffect, ModelServiceCompute for effect/compute nodes; NodeOrchestrator, NodeReducer with mixins for orchestrator/reducer nodes)
Applied to files:
tests/integration/registration/handlers/conftest.pysrc/omnibase_infra/nodes/node_registration_orchestrator/__init__.pytests/integration/registration/handlers/test_handler_node_heartbeat_integration.py
📚 Learning: 2025-12-26T13:16:11.773Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-26T13:16:11.773Z
Learning: Applies to **/*.py : All infrastructure adapters and services MUST use `MixinAsyncCircuitBreaker` for fault tolerance. Use `_init_circuit_breaker()` in __init__ with appropriate threshold and reset_timeout. Always hold `self._circuit_breaker_lock` when calling circuit breaker methods.
Applied to files:
src/omnibase_infra/mixins/mixin_async_circuit_breaker.py
📚 Learning: 2025-12-26T13:16:11.773Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-26T13:16:11.773Z
Learning: Applies to **/*.py : Dispatchers own their own resilience - use `MixinAsyncCircuitBreaker` for transport-specific failure handling. MessageDispatchEngine does NOT wrap dispatchers with circuit breakers. Each dispatcher knows its specific failure modes and recovery strategies.
Applied to files:
src/omnibase_infra/mixins/mixin_async_circuit_breaker.py
📚 Learning: 2025-12-06T22:21:32.649Z
Learnt from: CR
Repo: OmniNode-ai/omniagent PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T22:21:32.649Z
Learning: Applies to nodes/**/*.py : Use event bus mixins from `omnibase_core` for Kafka publishing instead of direct Kafka clients
Applied to files:
src/omnibase_infra/nodes/node_registration_orchestrator/__init__.pysrc/omnibase_infra/mixins/mixin_node_introspection.py
📚 Learning: 2025-11-30T21:55:10.298Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-30T21:55:10.298Z
Learning: Applies to src/omninode_bridge/nodes/**/*.py : Import mixins from omnibase_core.mixins.* and use Mixin* naming pattern (e.g., MixinHealthCheck, MixinMetrics, MixinEventBus) - never use local custom mixins unless experimental and documented
Applied to files:
src/omnibase_infra/nodes/node_registration_orchestrator/__init__.pysrc/omnibase_infra/mixins/mixin_node_introspection.py
📚 Learning: 2025-12-03T16:55:49.755Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T16:55:49.755Z
Learning: Applies to agents/**/*.py : Implement ONEX-compliant agent architecture with four node types: Effect (External I/O), Compute (Pure transforms), Reducer (State/persistence), and Orchestrator (Workflow coordination)
Applied to files:
src/omnibase_infra/nodes/node_registration_orchestrator/__init__.py
📚 Learning: 2025-11-24T16:32:55.606Z
Learnt from: CR
Repo: OmniNode-ai/omninode_bridge PR: 0
File: .cursor/rules/node_standards.mdc:0-0
Timestamp: 2025-11-24T16:32:55.606Z
Learning: Node communication must use event-driven patterns through `ModelEventEnvelope` from `omnibase_core.models.events.model_event_envelope`
Applied to files:
src/omnibase_infra/nodes/node_registration_orchestrator/__init__.py
📚 Learning: 2025-12-26T13:16:11.773Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-26T13:16:11.773Z
Learning: Applies to **/*.py : Node Introspection via `MixinNodeIntrospection`: Prefix internal/sensitive methods with `_` to exclude from introspection. Avoid exposing sensitive business logic in method names. Use generic parameter names instead of revealing implementation details.
Applied to files:
src/omnibase_infra/mixins/mixin_node_introspection.py
📚 Learning: 2025-12-26T13:16:11.773Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-26T13:16:11.773Z
Learning: Applies to **/*.py : Node Introspection cache is instance-level (not thread-safe without external synchronization). Designed for single-threaded asyncio usage. For multi-threaded access, external synchronization required. Background tasks (heartbeat, registry listener) run as asyncio tasks within event loop.
Applied to files:
src/omnibase_infra/mixins/mixin_node_introspection.py
📚 Learning: 2025-12-03T16:55:49.755Z
Learnt from: CR
Repo: OmniNode-ai/omniclaude PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T16:55:49.755Z
Learning: Applies to **/*.py : Publish intelligence requests to Kafka event bus using topics: dev.archon-intelligence.intelligence.code-analysis-{requested,completed,failed}.v1 for consistency and event-driven architecture
Applied to files:
src/omnibase_infra/mixins/mixin_node_introspection.py
📚 Learning: 2025-12-08T00:48:30.737Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_spi PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-08T00:48:30.737Z
Learning: Import `omnibase_core` models and types only for type hints and runtime usage - follow the SPI → Core dependency direction
Applied to files:
src/omnibase_infra/runtime/container_wiring.py
📚 Learning: 2025-12-07T17:50:13.678Z
Learnt from: CR
Repo: OmniNode-ai/omniintelligence PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-07T17:50:13.678Z
Learning: Applies to **/nodes/**/*compute*.py : Enforce ONEX node purity by preventing compute nodes from importing network/database clients (confluent_kafka, httpx, asyncpg, etc.), accessing environment variables (os.environ, os.getenv), or performing file system operations (open(), Path.read_text(), FileHandler)
Applied to files:
src/omnibase_infra/runtime/container_wiring.py
📚 Learning: 2025-12-26T13:16:11.773Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_infra PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-26T13:16:11.773Z
Learning: Applies to **/*.py : All services MUST use `ModelONEXContainer` for dependency injection via container initialization pattern `container = ModelONEXContainer()` followed by service resolution
Applied to files:
src/omnibase_infra/runtime/container_wiring.py
🧬 Code graph analysis (9)
tests/unit/nodes/node_registration_orchestrator/test_handler_node_introspected.py (5)
src/omnibase_infra/enums/enum_registration_state.py (1)
EnumRegistrationState(24-258)src/omnibase_infra/models/projection/model_registration_projection.py (1)
ModelRegistrationProjection(39-344)src/omnibase_infra/models/registration/events/model_node_registration_initiated.py (1)
ModelNodeRegistrationInitiated(29-104)src/omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_introspected.py (1)
handle(123-226)src/omnibase_infra/projectors/projection_reader_registration.py (1)
ProjectionReaderRegistration(49-660)
tests/unit/nodes/node_registration_orchestrator/test_handler_runtime_tick.py (2)
src/omnibase_infra/models/projection/model_registration_projection.py (1)
ModelRegistrationProjection(39-344)src/omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_runtime_tick.py (2)
HandlerRuntimeTick(59-309)handle(116-177)
src/omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_runtime_tick.py (2)
src/omnibase_infra/runtime/models/model_runtime_tick.py (1)
ModelRuntimeTick(61-190)src/omnibase_infra/models/projection/model_registration_projection.py (2)
needs_ack_timeout_event(302-322)needs_liveness_timeout_event(324-344)
tests/unit/runtime/test_container_wiring_registration.py (1)
src/omnibase_infra/runtime/container_wiring.py (4)
get_handler_node_introspected_from_container(892-928)get_handler_runtime_tick_from_container(931-967)get_projection_reader_from_container(845-889)wire_registration_handlers(670-842)
tests/unit/nodes/node_registration_orchestrator/test_handler_node_registration_acked.py (7)
src/omnibase_infra/enums/enum_registration_state.py (1)
EnumRegistrationState(24-258)src/omnibase_infra/models/projection/model_registration_projection.py (1)
ModelRegistrationProjection(39-344)src/omnibase_infra/models/registration/commands/model_node_registration_acked.py (1)
ModelNodeRegistrationAcked(29-105)src/omnibase_infra/models/registration/events/model_node_became_active.py (1)
ModelNodeBecameActive(25-100)src/omnibase_infra/models/registration/events/model_node_registration_ack_received.py (1)
ModelNodeRegistrationAckReceived(21-95)src/omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_registration_acked.py (3)
HandlerNodeRegistrationAcked(117-357)get_liveness_interval_seconds(74-114)handle(173-301)src/omnibase_infra/projectors/projection_reader_registration.py (1)
ProjectionReaderRegistration(49-660)
src/omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_registration_acked.py (6)
src/omnibase_infra/enums/enum_registration_state.py (1)
EnumRegistrationState(24-258)src/omnibase_infra/models/projection/model_registration_projection.py (1)
ModelRegistrationProjection(39-344)src/omnibase_infra/models/registration/commands/model_node_registration_acked.py (1)
ModelNodeRegistrationAcked(29-105)src/omnibase_infra/models/registration/events/model_node_registration_ack_received.py (1)
ModelNodeRegistrationAckReceived(21-95)src/omnibase_infra/projectors/projection_reader_registration.py (1)
ProjectionReaderRegistration(49-660)tests/helpers/deterministic.py (1)
now(143-154)
src/omnibase_infra/nodes/node_registration_orchestrator/handlers/__init__.py (4)
src/omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_heartbeat.py (2)
HandlerNodeHeartbeat(102-321)ModelHeartbeatHandlerResult(49-99)src/omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_introspected.py (1)
HandlerNodeIntrospected(77-226)src/omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_registration_acked.py (2)
HandlerNodeRegistrationAcked(117-357)get_liveness_interval_seconds(74-114)src/omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_runtime_tick.py (1)
HandlerRuntimeTick(59-309)
src/omnibase_infra/mixins/mixin_node_introspection.py (3)
src/omnibase_infra/event_bus/inmemory_event_bus.py (2)
publish_envelope(353-395)publish(244-351)src/omnibase_infra/event_bus/kafka_event_bus.py (2)
publish_envelope(1024-1058)publish(821-879)src/omnibase_infra/protocols/protocol_event_bus_like.py (2)
publish_envelope(74-89)publish(91-108)
src/omnibase_infra/runtime/container_wiring.py (4)
src/omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_introspected.py (1)
HandlerNodeIntrospected(77-226)src/omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_registration_acked.py (2)
HandlerNodeRegistrationAcked(117-357)get_liveness_interval_seconds(74-114)src/omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_runtime_tick.py (1)
HandlerRuntimeTick(59-309)src/omnibase_infra/projectors/projection_reader_registration.py (1)
ProjectionReaderRegistration(49-660)
🔇 Additional comments (38)
src/omnibase_infra/runtime/registry/model_message_type_entry.py (1)
23-23: LGTM!The
datetimeimport is correctly added to support the requiredregistered_atfield.src/omnibase_infra/mixins/mixin_async_circuit_breaker.py (1)
3-24: Coroutine-safety docs now accurately describe actual behaviorThe updated module and class docstrings correctly clarify that the mixin is coroutine-safe (asyncio.Lock) rather than thread-safe, and the per-method “REQUIRES: self._circuit_breaker_lock must be held by caller.” notes are consistent with the implementation and infra guidelines. No behavioral changes; just clearer, more accurate documentation.
Also applies to: 66-74, 145-172, 218-272, 326-537
src/omnibase_infra/mixins/mixin_node_introspection.py (2)
173-176: Introspection timestamp + metrics extensions are coherentThe additions in
IntrospectionCacheDict(timestamp), the cache-hit path, and the fresh-build path inget_introspection_data()are consistent:
- Cache path reconstructs
ModelNodeIntrospectionEventfrom the JSON-serialized dict, letting Pydantic parse the ISOtimestampstring back todatetime.- Fresh path records
discover_capabilities_msseparately fromget_capabilities_mswhile still driving capability discovery throughget_capabilities().- The new
timestamp=datetime.now(UTC)field onModelNodeIntrospectionEventis carried into the cache and reused on cache hits, which matches the comment that timestamp reflects cache population time rather than “time of call”.This all hangs together cleanly with the existing performance metrics machinery.
Also applies to: 219-276, 1056-1074, 1076-1271
1272-1373: Heartbeat timestamp + registry-listener correlation IDs follow ONEX patterns
_publish_heartbeat()now:
- Captures
now = datetime.now(UTC)and passes it as the requiredtimestampintoModelNodeHeartbeatEvent.- Continues to generate a fresh UUID
correlation_idper heartbeat.The publish logic’s use of a narrowed
event_busvariable is mypy-friendly and mirrors thepublish_introspection()pattern.In
_registry_listener_loop.on_request, both the “no value” branch and the parsed request branch now ensure a UUID correlation_id is used when callingpublish_introspection()(viauuid4()or_parse_correlation_id), which aligns with the correlation-id guidance and avoidsNoneleaking into downstream tracing. Overall the behavioral changes look correct.Also applies to: 1374-1477, 1645-1679
src/omnibase_infra/nodes/node_registration_orchestrator/__init__.py (1)
19-35: Package doc now correctly points to co-located handlersThe updated module docstring reflecting
HandlerNodeIntrospected,HandlerNodeRegistrationAcked,HandlerRuntimeTick, andHandlerNodeHeartbeatin thehandlerssubpackage—plus the example import block—accurately matches the new structure. Keeping handlers accessed via thehandlerssubmodule while leaving__all__focused on the orchestrator and its models is a reasonable separation.tests/integration/registration/handlers/test_handler_node_heartbeat_integration.py (1)
37-51: Import relocation for heartbeat handler is consistent with new package layoutThe integration tests now import
HandlerNodeHeartbeat,DEFAULT_LIVENESS_WINDOW_SECONDS, andModelHeartbeatHandlerResultfromomnibase_infra.nodes.node_registration_orchestrator.handlers, including the late import inside the precision test. This matches the new handler location and keeps the rest of the test logic intact.Also applies to: 1013-1016
tests/integration/registration/handlers/conftest.py (1)
33-36: Handler fixtures correctly updated to the new handlers namespaceThe heartbeat fixtures now import
HandlerNodeHeartbeatandDEFAULT_LIVENESS_WINDOW_SECONDSfromomnibase_infra.nodes.node_registration_orchestrator.handlersin all three places (top-level constant, TYPE_CHECKING, and inside fixtures). The constructed handlers still use the intended default and 5-second liveness windows, so downstream tests remain valid.Also applies to: 49-56, 73-99, 101-126
tests/unit/nodes/node_registration_orchestrator/test_handler_runtime_tick.py (2)
45-93: RuntimeTick timeout behavior is well covered (ack + liveness + dedup)The test suite around
HandlerRuntimeTickdoes a good job of pinning down behavior:
- Ack timeouts are validated for both
AWAITING_ACKandACCEPTEDstates, with full checks onentity_id/node_id,causation_id,correlation_id,emitted_at, anddeadline_at.- Deduplication is exercised via projections where the relevant
*_timeout_emitted_atfield is set, confirming no events are emitted whenneeds_*_timeout_event()would return False.- Liveness expiry tests verify that
ModelNodeLivenessExpiredis produced only for ACTIVE projections with overdue deadlines and thatlast_heartbeat_atremainsNonewhen there has never been a heartbeat.- Multi-entity and mixed ack+liveness scenarios assert both cardinality and ordering (ack timeout first, then liveness expired), matching the handler’s documented sequencing.
These tests should catch most regressions in the C2 timeout detection logic.
Also applies to: 96-232, 261-329, 331-365
430-512: Injectednowand timezone-awareness are enforced correctly in testsThe
TestHandlerRuntimeTickInjectedNowandTestHandlerRuntimeTickTimezoneValidationclasses validate two important contracts:
- Both projection-reader queries (
get_overdue_ack_registrationsandget_overdue_liveness_registrations) are asserted to receive the injectednowandcorrelation_id, so the handler can’t silently fall back todatetime.now().- Timeout events’
emitted_atfields are checked against the injectednow, guarding against latent use of system time.- Naive datetimes for
noware confirmed to raiseValueError, while timezone-aware datetimes pass and yield an empty event list.This aligns tightly with the handler’s implementation and the broader “injected time, tz-aware only” pattern.
Also applies to: 514-563
tests/unit/nodes/node_registration_orchestrator/test_handler_node_registration_acked.py (2)
49-93: Ack handler tests thoroughly exercise activation, idempotency, and capabilitiesThe
HandlerNodeRegistrationAckedtests cover the critical behavioral matrix:
- For
AWAITING_ACKandACCEPTED, the handler emits exactly two events (ModelNodeRegistrationAckReceivedthenModelNodeBecameActive), with assertions on node/entity IDs, correlation IDs,causation_id == command_id,emitted_at == now, and capabilities snapshot equality.- Duplicate/idempotent cases (ACTIVE, ACK_RECEIVED, PENDING_REGISTRATION, and the terminal states including ACK_TIMED_OUT/REJECTED/LIVENESS_EXPIRED) all assert an empty event list, matching the FSM semantics for late or redundant acks.
- Unknown-node handling is explicitly tested as a no-op.
- Causation linkage is validated across both emitted events to ensure proper traceability.
These tests closely track the handler’s contract and should prevent accidental drift in the registration-ack flow.
Also applies to: 95-185, 186-351, 353-461, 463-493
353-418: Liveness interval resolution and timezone validation are well specifiedThe remaining tests pin down the configuration and time-handling details:
test_liveness_deadline_uses_injected_nowandtest_custom_liveness_intervalassert thatliveness_deadlineis always computed from the injectednowplus the effective interval, whether from the default constant or a per-handler override.TestGetLivenessIntervalSecondsverifies precedence rules forget_liveness_interval_seconds: explicit value > env var > default, plus correct handling of explicitNoneand invalid env values (raisingValueErrorwith clear messaging).test_handler_uses_get_liveness_interval_internallyconfirms that a handler constructed without an explicit interval picks up the env-configured value.- The timezone-validation tests mirror the RuntimeTick handler: naive
nowraisesValueError, while tz-aware datetimes succeed, even when no projection is found.Overall this gives strong coverage for config-driven liveness behavior and reinforces the “tz-aware injected time” requirement.
Also applies to: 494-595, 597-644
src/omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_introspected.py (4)
1-54: LGTM: Imports and module structure are clean.The module is well-documented with clear decision logic explanation, proper license headers, and appropriate imports. The TYPE_CHECKING guard for BaseModel is correctly used for type hints only.
56-75: LGTM: State groups are well-defined and exhaustive.The
_RETRIABLE_STATESand_BLOCKING_STATESfrozen sets correctly partition the registration states per the documented decision matrix. Usingfrozensetensures immutability.
148-163: LGTM: Timezone validation and projection query are correct.The handler properly validates timezone-awareness before any operations and uses the projection reader with correct parameters (entity_id, domain, correlation_id).
164-205: LGTM: Decision logic is comprehensive and well-structured.The state decision logic correctly handles:
- New nodes (projection is None)
- Retriable states (LIVENESS_EXPIRED, REJECTED, ACK_TIMED_OUT)
- Blocking states (PENDING_REGISTRATION, ACCEPTED, AWAITING_ACK, ACK_RECEIVED, ACTIVE)
Logging at appropriate levels (info for actions, debug for no-ops).
tests/unit/nodes/node_registration_orchestrator/test_handler_node_introspected.py (6)
42-51: LGTM: Test fixtures are well-designed.The
TEST_NOWconstant ensures deterministic testing, and the mock factory properly specs againstProjectionReaderRegistrationto catch interface mismatches.
53-83: LGTM: Helper functions provide clean test data creation.Both
create_projectionandcreate_introspection_eventprovide sensible defaults while allowing customization. The projection helper correctly usesTEST_NOWfor timestamp offsets.
85-143: LGTM: Core emission tests are thorough.The tests correctly verify:
- Event type (ModelNodeRegistrationInitiated)
- Field propagation (node_id, entity_id, correlation_id)
- Causation linkage to triggering event's correlation_id
- Time injection (emitted_at == TEST_NOW)
- Registration attempt ID generation
176-209: LGTM: Parametrized blocking state test provides comprehensive coverage.All five blocking states are tested with a single parametrized test, reducing code duplication while ensuring full coverage.
318-397: LGTM: Event field tests validate critical invariants.The tests correctly verify:
- Unique registration_attempt_id per invocation
- Causation ID linkage to introspection event
- Entity ID equals node ID (registration domain invariant)
427-473: LGTM: Timezone validation tests ensure time injection safety.Both positive (aware datetime accepted) and negative (naive datetime rejected) cases are covered with appropriate assertion of error message content.
src/omnibase_infra/nodes/node_registration_orchestrator/handlers/__init__.py (1)
1-57: LGTM: Module exports are comprehensive and well-documented.The
__init__.pycorrectly:
- Documents handler architecture and patterns
- Re-exports all handler classes and utility functions
- Uses typed
__all__: list[str]per coding guidelines- Groups related exports logically
src/omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_runtime_tick.py (3)
141-147: LGTM: Timezone validation is correctly implemented.The handler validates timezone-awareness at the entry point of
handle(), preventing subtle bugs in deadline comparisons downstream. This addresses the past review comment.
278-294: LGTM: Liveness expiry detection correctly handles None heartbeat.The
last_heartbeat_atfield is correctly passed through as-is (may be None if no heartbeats were ever received), with good inline documentation explaining the semantic difference fromregistered_at.
166-177: LGTM: Timeout event aggregation and logging are appropriate.The handler correctly:
- Aggregates events from both timeout checks
- Logs summary with counts only when events are emitted
- Returns combined event list
src/omnibase_infra/runtime/container_wiring.py (6)
61-71: LGTM: TYPE_CHECKING imports correctly structured.The imports are properly guarded under
TYPE_CHECKINGfor type hints only, avoiding runtime import of handler classes which would create circular dependencies.
670-724: LGTM: wire_registration_handlers() has comprehensive docstring and proper resolution.The function:
- Documents all registered services
- Uses
get_liveness_interval_seconds()for configuration resolution- Follows the established wiring pattern
727-798: LGTM: Service registration follows established patterns.The registration sequence correctly:
- Registers ProjectionReaderRegistration first (dependency)
- Registers handlers in order, each receiving the shared projection_reader
- Includes appropriate metadata including liveness_interval_seconds for ack handler
800-842: LGTM: Error handling is consistent with existing wiring functions.The AttributeError and generic Exception handling mirrors the pattern in
wire_infrastructure_services(), providing clear hints for common issues.
845-928: LGTM: Getter functions follow consistent patterns.All four getter functions (
get_projection_reader_from_container,get_handler_node_introspected_from_container, etc.):
- Use lazy imports inside functions
- Follow established error handling patterns
- Provide clear error messages with fix suggestions
1011-1024: LGTM: all exports are complete and organized.The new exports are grouped under a comment for organization, and all five new functions are included.
src/omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_registration_acked.py (7)
64-114: LGTM: Liveness interval configuration is well-designed.The
get_liveness_interval_seconds()function correctly implements the resolution order (explicit → env → default) with proper error handling for invalid env values.
155-172: LGTM: Handler initialization resolves liveness interval correctly.The constructor uses
get_liveness_interval_seconds()to resolve the interval, allowing flexible configuration via constructor, environment, or default.
197-211: LGTM: Timezone validation and projection query are correct.The handler validates timezone-awareness before operations and uses the projection reader with correct parameters.
213-238: LGTM: Valid ack states correctly trigger activation events.The handler correctly identifies ACCEPTED and AWAITING_ACK as states where an ack is valid and should trigger activation events.
240-301: LGTM: All non-valid ack states are handled with appropriate logging.The decision logic correctly handles:
- ACK_RECEIVED/ACTIVE: Duplicate ack (debug log)
- PENDING_REGISTRATION: Ack too early (warning)
- ACK_TIMED_OUT: Ack too late (warning)
- Terminal states: Ack meaningless (warning)
- Unexpected states: Fallback warning
All paths return empty list for no-ops.
303-357: LGTM: Activation events use injected time consistently.Both
ModelNodeRegistrationAckReceivedandModelNodeBecameActivecorrectly use:
emitted_at=nowfor time injectioncausation_id=command.command_idfor causal tracingliveness_deadlinecomputed fromnow + intervalThis addresses the past review comment about time injection consistency.
360-365: LGTM: all exports are complete.All public symbols (constants, function, class) are correctly exported.
- Use DLQ_REPLAY_RUNBOOK.md filename (follows naming convention from main) - Keep EVENT_BUS_OPERATIONS_RUNBOOK.md entry from feature branch
Code Review: Registration Orchestrator Implementation [C1]✅ Overall AssessmentThis is an excellent implementation of the first orchestrator node in omnibase_infra. The PR successfully establishes the declarative orchestrator pattern and demonstrates strong adherence to ONEX architectural principles. The code quality is high, with comprehensive test coverage and thorough documentation. 🎯 Strengths1. Exemplary Declarative Pattern ⭐The orchestrator implementation perfectly demonstrates the ONEX declarative philosophy: class NodeRegistrationOrchestrator(NodeOrchestrator):
"""Declarative orchestrator - all behavior defined in contract.yaml."""
pass # No custom code - driven entirely by contract
2. Strong Type Safety ✅
Example from # CORRECT - No default_factory, explicit time injection
emitted_at: datetime = Field(
...,
description="Timestamp when the orchestrator emitted this event (UTC)",
)3. Excellent Error Handling 🛡️
4. Comprehensive Test Coverage 🧪
Example test structure from TEST_NOW = datetime(2025, 1, 15, 12, 0, 0, tzinfo=UTC)
async def test_handler_node_introspected_emits_initiated(self) -> None:
# Arrange - Create mock projection reader
mock_reader.get_entity_state.return_value = None # New node
# Act - Process event with injected time
events = await handler.handle(event, now=TEST_NOW, correlation_id=uuid4())
# Assert - Verify emitted event
assert isinstance(events[0], ModelNodeRegistrationInitiated)
assert events[0].emitted_at == TEST_NOW # Uses injected time5. Excellent Documentation 📚
🔍 Issues Found🟡 Minor Issues (Nitpicks)1. Contract Complexity (Line count)
Current structure: # contract.yaml (460 lines)
workflow_coordination: ...
handler_routing: (246 lines)
consumed_events: ...
published_events: ...
error_handling: ...Recommended refactoring (per contract comments): # contract.yaml (main)
routing_subcontract: \!include subcontracts/routing.yaml
event_subcontract: \!include subcontracts/events.yaml
state_subcontract: \!include subcontracts/coordination.yamlRationale:
Recommendation: File follow-up ticket for subcontract extraction (not blocking for this PR). 2. Concurrency Documentation ClarityThe orchestrator docstring mentions "not coroutine-safe" but this needs clarification: # node.py:88-90
Coroutine Safety:
This orchestrator is NOT coroutine-safe. Each instance should handle one
workflow at a time. For concurrent workflows, create multiple instances.Issue: This is potentially misleading. The orchestrator is coroutine-safe for handling different events (different node_ids), but not for concurrent processing of the same workflow instance. Recommended clarification: Coroutine Safety:
This orchestrator is coroutine-safe for handling different workflow instances
(different node_ids) concurrently. However, do NOT process the same workflow
instance (same node_id) concurrently, as this may cause race conditions in
projection reads and event emissions.3. Handler State Decision DuplicationThe state decision matrix appears in three locations:
Consideration: This duplication is acceptable for documentation purposes, but ensure they stay synchronized. Consider adding a validation test that verifies the handler's actual behavior matches the contract's state_decision_matrix. 🚀 Performance Considerations✅ Excellent Parallel Execution DesignThe workflow uses parallel mode effectively: # contract.yaml:192-200
coordination_rules:
execution_mode: parallel
parallel_execution_allowed: true
max_parallel_branches: 2Benefits:
🟢 Circuit Breaker ConfigurationThe Strengths:
Validation: Ensure circuit breaker thresholds are tuned appropriately:
🔒 Security Considerations✅ Proper Error SanitizationThe implementation correctly sanitizes errors: # GOOD - No credentials exposed
raise InfraConnectionError(
"Failed to connect to database",
context=context,
host="db.example.com", # Safe
port=5432, # Safe
retry_count=3, # Safe
)
# Never includes passwords, connection strings, or PII✅ Correlation ID PropagationProper distributed tracing support:
📋 Test Coverage Analysis✅ Comprehensive CoverageThe test suite covers all critical paths: Unit tests (
Integration tests (
Recommendation: All tests use deterministic time injection (no 🎯 ONEX Compliance✅ Full Compliance with ONEX Principles
✅ Architectural Constraints (Per CLAUDE.md)Orchestrator constraints from
🎓 RecommendationsFor This PR:
For Future PRs:
📊 Metrics
✅ Final VerdictStatus: APPROVED ✅ This PR represents excellent work and successfully establishes the declarative orchestrator pattern for omnibase_infra. The implementation is:
The minor issues identified are all nitpicks that can be addressed in follow-up PRs. None are blocking for merge. Recommendation: Merge immediately. 🚀 Review completed with ONEX architecture compliance validation |
Summary
Implements C1: Registration Orchestrator (Event-Driven) per ONEX_RUNTIME_REGISTRATION_TICKET_PLAN.md.
This is the first orchestrator node in omnibase_infra, establishing the pattern for all future orchestrators.
Changes
Orchestrator Node
NodeRegistrationOrchestrator: Routes events to handlers, returns events onlyHandlers
HandlerNodeIntrospected: Canonical trigger, emitsNodeRegistrationInitiatedHandlerRuntimeTick: Timeout detection for ack/liveness deadlinesHandlerNodeRegistrationAcked: Processes ack commands, emits activation eventsEvent Models (7 decision events)
ModelNodeRegistrationInitiatedModelNodeRegistrationAcceptedModelNodeRegistrationRejectedModelNodeRegistrationAckTimedOutModelNodeRegistrationAckReceivedModelNodeBecameActiveModelNodeLivenessExpiredSupporting Models
ModelNodeRegistrationAcked: Node acknowledgment commandModelOrchestratorContext: Time injection withnow: datetimeTests
Architectural Compliance
Per ONEX_RUNTIME_REGISTRATION_TICKET_PLAN.md Global Constraints:
nowfor all time decisionsTest Plan
Dependencies
Unblocks
Summary by CodeRabbit
New Features
Documentation
Refactor
✏️ Tip: You can customize this high-level summary in your review settings.