Skip to content

feat(compute): implement contract-driven NodeCompute v1.0 [OMN-465] - #115

Merged
jonahgabriel merged 18 commits into
mainfrom
feat/OMN-465-nodecompute-contract-design
Dec 7, 2025
Merged

jonahgabriel merged 18 commits into
mainfrom
feat/OMN-465-nodecompute-contract-design

Conversation

@jonahgabriel

@jonahgabriel jonahgabriel commented Dec 7, 2025 •

Copy link
Copy Markdown
Contributor

Summary

Implement the v1.0 contract-driven NodeCompute specification with sequential pipelines, abort-on-first-failure semantics, and 6 built-in transformation types.

This is a minimal, stable foundation that can be shipped safely and extended incrementally.

v1.0 Scope

IN OUT (deferred)
Sequential pipelines Caching (v1.1)
3 step types: VALIDATION, TRANSFORMATION, MAPPING Parallelism (v1.2)
6 transformations: IDENTITY, REGEX, CASE_CONVERSION, TRIM, NORMALIZE_UNICODE, JSON_PATH Conditionals (v1.2)
Abort-on-first-failure Full expression language (v1.2)
Simple $.input / $.steps.<name>.output paths Per-step timeouts (v1.1)

Files Added

Enums (6)

  • EnumComputeStepType - VALIDATION, TRANSFORMATION, MAPPING
  • EnumTransformationType - 6 transformation types
  • EnumCaseMode, EnumRegexFlag, EnumTrimMode, EnumUnicodeForm

Models (16)

  • ModelComputeExecutionContext - Typed execution context
  • ModelComputeStepMetadata/Result - Step-level execution tracking
  • ModelComputePipelineResult - Pipeline result with abort semantics
  • ModelComputePipelineStep - Pipeline step with model validator
  • ModelComputeSubcontract - v1.0 contract definition
  • 7 transformation config models with discriminated union (ModelTransformationConfig)

Execution (3)

  • compute_transformations.py - 6 pure transformation functions
  • compute_executor.py - Pipeline executor with path resolution
  • MixinComputeExecution - Integration mixin for NodeCompute

Documentation (3)

  • CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md - v1.0 specification
  • NODECOMPUTE_VERSIONING_ROADMAP.md - Version roadmap
  • NODECOMPUTE_FULL_DESIGN_V1X_TARGET.md - Full vision document

Key Design Decisions

  1. VALIDATION is a step type, not a transformation - Semantic clarity
  2. IDENTITY transformation has no config - Must be null/omitted
  3. Schema refs resolved at load time - Fail fast if invalid
  4. String-only error types in v1.0 - Enums deferred to v1.1
  5. All results immutable - frozen=True for future parallel support

Test plan

  • mypy --strict passes (0 errors in 25 source files)
  • 95 unit tests pass covering all components
  • CI pipeline passes
  • Manual verification of example pipeline

Linear Issue

OMN-465

Summary by CodeRabbit

  • New Features

    • NodeCompute v1.0: contract-driven sequential pipelines with validation, transformations (identity, regex, case, trim, unicode, JSONPath), mapping steps, execution context, per-step metadata, timing, and abort-on-first-failure semantics.
    • Path resolution for referencing input and prior step outputs.
  • Documentation

    • Added authoritative v1.0 specification and a versioning roadmap (v1.1–v1.3 plans).
  • Tests

    • Extensive unit and integration test coverage for pipelines, transforms, error handling, and edge cases.

✏️ Tip: You can customize this high-level summary in your review settings.

Implement the v1.0 contract-driven NodeCompute specification with sequential
pipelines, abort-on-first-failure semantics, and 6 built-in transformation types.

## Core Components

### Enums (6 new)
- EnumComputeStepType: VALIDATION, TRANSFORMATION, MAPPING
- EnumTransformationType: IDENTITY, REGEX, CASE_CONVERSION, TRIM, NORMALIZE_UNICODE, JSON_PATH
- EnumCaseMode, EnumRegexFlag, EnumTrimMode, EnumUnicodeForm

### Models
- ModelComputeExecutionContext: Typed execution context with operation/correlation IDs
- ModelComputeStepMetadata/Result: Step-level execution tracking
- ModelComputePipelineResult: Pipeline result with abort-on-first-failure
- ModelComputePipelineStep: Pipeline step with model validator
- ModelComputeSubcontract: v1.0 contract definition
- 7 transformation config models with discriminated union

### Execution
- compute_transformations.py: 6 pure transformation functions
- compute_executor.py: Pipeline executor with path resolution
- MixinComputeExecution: Integration mixin for NodeCompute

## Key Features
- Sequential-only pipelines (parallel deferred to v1.2)
- Abort-on-first-failure semantics
- Simple path expressions: $.input, $.steps.<name>.output
- Immutable results (frozen=True)
- IDENTITY transformation requires no config

## Testing
- 95 unit tests covering all components
- mypy strict: 0 errors in 25 source files
@coderabbitai

coderabbitai Bot commented Dec 7, 2025 •

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@jonahgabriel has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 9 minutes and 46 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between ee13578 and 85b7def.

📒 Files selected for processing (1)
  • tests/unit/enums/test_enum_node_type_kind_mapping.py (1 hunks)

Walkthrough

Adds a v1.0 contract-driven NodeCompute spec plus implementation: new enums, immutable compute and transformation models, mapping/validation configs, a stateless executor, path resolver, mixin for execution, ComputePipelineError, example contract, and extensive unit/integration tests for sequential, abort-on-first-failure pipelines.

Changes

Cohort / File(s) Summary
Architecture & Specification
docs/architecture/CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md, docs/architecture/NODECOMPUTE_VERSIONING_ROADMAP.md
New NodeCompute v1.0 specification and versioning roadmap documents.
Enums: core & modes
src/omnibase_core/enums/__init__.py, src/omnibase_core/enums/enum_compute_step_type.py, src/omnibase_core/enums/enum_transformation_type.py, src/omnibase_core/enums/enum_case_mode.py, src/omnibase_core/enums/enum_regex_flag.py, src/omnibase_core/enums/enum_trim_mode.py, src/omnibase_core/enums/enum_unicode_form.py
Added compute-step and transformation enums and related mode/flag enums; exported via enums package.
Compute models
src/omnibase_core/models/compute/*
New immutable models: ModelComputeExecutionContext, ModelComputeStepMetadata, ModelComputeStepResult, ModelComputePipelineResult and package init exports.
Transformation configs & types
src/omnibase_core/models/transformations/*
New discriminated transformation config models (regex, case, trim, unicode, json_path), mapping and validation configs, and ModelTransformationConfig union; package re-exports.
Contract/subcontract models
src/omnibase_core/models/contracts/subcontracts/*
New ModelComputePipelineStep with per-type config validation and ModelComputeSubcontract with pipeline, timeout bounds, and unique-step-name validation; updated exports.
Execution utilities
src/omnibase_core/utils/compute_executor.py, src/omnibase_core/utils/compute_transformations.py, src/omnibase_core/utils/compute_path_resolver.py
Stateless executor (execute_compute_pipeline), transformation handlers (six types) with registry and dispatcher, and unified path-resolution utilities with PathResolutionError.
Mixin for execution
src/omnibase_core/mixins/mixin_compute_execution.py, src/omnibase_core/mixins/__init__.py
MixinComputeExecution added with async execute_contract_pipeline wrapper and contract validation helpers; exported via mixins package.
Errors
src/omnibase_core/errors/exception_compute_pipeline_error.py, src/omnibase_core/errors/__init__.py
ComputePipelineError exception added and exposed via errors package lazy import.
Model field validations & others
Multiple model files (model_compute_input.py, model_compute_output.py, various model_* files under models/)
Added ge=0 non-negativity constraints and other tightened validations; ModelComputeOutput frozen and stricter Field validations.
Node/logging handling
src/omnibase_core/infrastructure/node_base.py, src/omnibase_core/mixins/mixin_event_handler.py, src/omnibase_core/mixins/mixin_introspection_publisher.py
Safer node_id handling in logs and events using "" sentinel and guarded UUID conversion.
Tests & fixtures
tests/unit/**, tests/integration/**, tests/unit/models/compute/conftest.py, tests/integration/conftest.py
Extensive unit and integration tests for enums, models, transform configs, executor, path resolver, subcontract validation; added fixtures and test markers/timeout adjustments.
Example contract
examples/contracts/compute/user_profile_normalizer.yaml
v1.0 example YAML contract showing multi-step normalization pipeline.
Docs formatting
docs/*
Various documentation formatting updates (code fence languages, examples).

Sequence Diagram(s)

sequenceDiagram
    actor Client
    participant Mixin as MixinComputeExecution
    participant Executor as execute_compute_pipeline
    participant Dispatcher as execute_pipeline_step
    participant Transformer as compute_transformations
    participant Resolver as compute_path_resolver
    participant Result as ModelComputePipelineResult

    Client->>Mixin: execute_contract_pipeline(contract, input)
    Mixin->>Mixin: validate_compute_contract(contract)
    Mixin->>Executor: execute_compute_pipeline(contract, input, context)

    loop for each step
        Executor->>Dispatcher: execute_pipeline_step(step, current_data, input, step_results)
        alt step.type == TRANSFORMATION
            Dispatcher->>Transformer: execute_transformation(data, transformation_type, config)
            Transformer-->>Dispatcher: transformed_value
        else step.type == MAPPING
            Dispatcher->>Resolver: resolve_mapping_path(path, input, step_results)
            Resolver-->>Dispatcher: resolved_value
        else step.type == VALIDATION
            Dispatcher-->>Dispatcher: passthrough/validate
        end
        Dispatcher-->>Executor: ModelComputeStepResult (with timing, success/error)
        Note over Executor: record step_results, stop on first failure
    end

    Executor-->>Mixin: ModelComputePipelineResult
    Mixin-->>Client: ModelComputePipelineResult
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Areas to focus review on:

  • src/omnibase_core/utils/compute_executor.py: orchestration, error propagation, timing and step/result wiring.
  • src/omnibase_core/utils/compute_transformations.py: handler correctness, regex/flags handling, json_path traversal and error semantics.
  • src/omnibase_core/utils/compute_path_resolver.py: path parsing/traversal, private attribute protections, and PathResolutionError content.
  • src/omnibase_core/models/contracts/subcontracts/*: per-step validation logic and unique-name validator messaging.
  • src/omnibase_core/mixins/mixin_compute_execution.py: contract validation (forward refs) and context population.

Possibly related PRs

  • omnibase_core PR 109 — overlaps on enums/mixins and import/export surface changes; likely touches same packages and export behavior.
  • omnibase_core PR 58 — modifies contracts/subcontracts exports and models; directly related to subcontract model additions here.
  • omnibase_core PR 32 — enum package changes; potentially conflicts with newly added enum exports.

Poem

🐰 I hopped through specs and tests today,

Six transforms helping data sway,
Paths resolved and steps ran true,
Abort on fail — we skip askew,
A rabbit cheers: pipelines, hooray!

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and concisely describes the main implementation: introducing contract-driven NodeCompute v1.0 with sequential pipelines and essential transformations.
Docstring Coverage ✅ Passed Docstring coverage is 98.47% which is sufficient. The required threshold is 80.00%.

Comment @coderabbitai help to get the list of available commands and usage tips.

@claude

claude Bot commented Dec 7, 2025

Copy link
Copy Markdown

Code Review: Contract-Driven NodeCompute v1.0 Implementation

Summary

This PR implements a well-architected, contract-driven transformation pipeline for NodeCompute with sequential execution and abort-on-first-failure semantics. The implementation follows ONEX patterns established by NodeReducer and NodeOrchestrator, with strong type safety and comprehensive documentation.

Overall Assessment: ✅ APPROVE with minor suggestions for improvement


Strengths 🎉

1. Excellent Architecture & Design

  • ✅ Clear separation of concerns: enums, models, transformations, executor, and mixin
  • ✅ Pure functional transformations ((data, config) → result) enable easy testing
  • ✅ Follows established ONEX patterns (FSM-driven Reducer, workflow-driven Orchestrator)
  • ✅ Minimal v1.0 scope reduces risk and complexity
  • ✅ Well-documented roadmap for future versions (v1.1, v1.2)

2. Strong Type Safety

  • ✅ 100% Pydantic models with proper discriminated unions (ModelTransformationConfig)
  • ✅ ConfigDict(extra="forbid", frozen=True) enforces immutability and prevents field typos
  • ✅ Proper use of ModelOnexError instead of generic exceptions
  • ✅ Type annotations throughout (should pass mypy --strict)

3. Comprehensive Testing

  • ✅ 95 unit tests covering all transformation types
  • ✅ Test organization mirrors source structure
  • ✅ Good coverage of edge cases (invalid inputs, error conditions)

4. Excellent Documentation

  • ✅ Three detailed specification documents with clear scope definitions
  • ✅ Comprehensive inline docstrings
  • ✅ Example contracts demonstrating usage
  • ✅ Versioning roadmap with feature deferral rationale

Issues & Concerns 🔴

CRITICAL - Must Fix Before Merge

1. Missing CI Verification ❌

From the PR description:

  • CI pipeline passes

Issue: Cannot verify if this passes the project's strict quality gates:

  • mypy --strict (0 errors required)
  • 60%+ coverage requirement
  • 12,000+ existing tests still pass

Action Required: Run full CI pipeline and verify all checks pass.


Potential Issues ⚠️

1. Error Type Inconsistency

Location: compute_executor.py:278-279, 310, 322

error_type=_get_error_type(e),
error_message=e.message,

Issue: e.message may not exist on ModelOnexError. The standard Pydantic error attribute is different.

Recommendation: Verify ModelOnexError.message exists, or use proper attribute access pattern.


2. Thread Safety Not Addressed

Location: All transformation and executor functions

Observation: Per CLAUDE.md, most ONEX components are NOT thread-safe by default. While v1.0 uses sequential execution, the functions appear stateless (good!), but this should be documented.

Recommendation: Add explicit thread-safety guarantee to docstrings:

"""
Execute a transformation pipeline.

Thread Safety: All functions are pure and stateless - safe for concurrent use.
"""

3. Validation Step Is Stubbed

Location: compute_executor.py:153-172

def execute_validation_step(...):
    # v1.0: Pass through data (schema validation deferred)
    return data

Issue: This makes the VALIDATION step type somewhat misleading in v1.0 - it doesn't actually validate.

Recommendations:

  1. Document this limitation prominently in the v1.0 spec and contract examples
  2. Consider logging a warning when validation steps are used in v1.0
  3. Add a TODO comment with target version for real implementation

4. Potential Performance Issue: Step Result Storage

Location: compute_executor.py:259

step_results[step.step_name] = step_result

Issue: Every step's output is stored in memory. For pipelines processing large data (images, documents), this could cause memory issues.

Impact: Low for v1.0 (doc says text processing focus), but worth documenting limits.

Recommendation: Add memory considerations to documentation or configuration.


5. Missing Timeout Enforcement

Location: compute_executor.py:210-335

Issue: pipeline_timeout_ms is accepted in the contract but never enforced in execute_compute_pipeline().

Impact: Pipelines can run indefinitely despite timeout configuration.

Recommendation: Add timeout enforcement:

if contract.pipeline_timeout_ms:
    start_time = time.perf_counter()
    # ... in loop ...
    elapsed_ms = (time.perf_counter() - start_time) * 1000
    if elapsed_ms > contract.pipeline_timeout_ms:
        raise ModelOnexError(
            error_code=EnumCoreErrorCode.OPERATION_TIMEOUT,
            message=f"Pipeline exceeded timeout of {contract.pipeline_timeout_ms}ms"
        )

6. Path Resolution Security

Location: compute_executor.py:44-131 (resolve_mapping_path)

Potential Issue: Path expressions access arbitrary object attributes via getattr():

elif hasattr(current, part):
    current = getattr(current, part)

Security Consideration: This could potentially access private attributes or methods. Consider restricting to public attributes only.

Recommendation: Add safeguard:

if part.startswith('_'):
    raise ModelOnexError(message=f"Cannot access private attribute: {part}")

Code Quality Suggestions 💡

1. Type Hints Could Be More Specific

Location: Multiple files using Any

Current:

def resolve_mapping_path(path: str, input_data: Any, ...) -> Any:

Better (if feasible):

from typing import Dict, List, Union
JsonType = Union[Dict[str, 'JsonType'], List['JsonType'], str, int, float, bool, None]

def resolve_mapping_path(path: str, input_data: JsonType, ...) -> JsonType:

Trade-off: More verbose but better type safety. May not be worth it for v1.0.


2. Consider Custom Exception for Transformation Errors

Current: All errors use ModelOnexError with different error codes

Suggestion: For better error handling:

class TransformationError(ModelOnexError):
    def __init__(self, transformation_type: str, message: str):
        super().__init__(
            error_code=EnumCoreErrorCode.TRANSFORMATION_ERROR,
            message=f"{transformation_type}: {message}"
        )

Benefit: Easier to catch transformation-specific errors vs. other operation failures.


3. Add Input Validation to IDENTITY Transform

Location: compute_transformations.py:37-39

Current: IDENTITY silently accepts any data
Observation: The validator in ModelComputePipelineStep checks for config presence, but runtime could be safer.

Low Priority: Current implementation is fine, but explicit validation could catch contract bugs earlier.


Testing Recommendations 🧪

1. Missing Integration Tests

From PR description, only unit tests are mentioned. Consider adding:

  • ✅ Full pipeline execution test (multiple steps)
  • ✅ Error propagation test (failure in middle of pipeline)
  • ✅ Mapping referencing multiple prior steps
  • ✅ Large data handling (performance baseline)

2. Missing Edge Cases

Consider testing:

  • Empty pipeline (zero steps)
  • Pipeline with all disabled steps
  • Circular references in mapping (though probably impossible with sequential execution)
  • Very deep nested path resolution

Documentation Suggestions 📚

1. Add Migration Guide

The spec mentions migration from code-driven NodeCompute, but no guide exists yet.

Recommendation: Add docs/guides/MIGRATING_TO_CONTRACT_DRIVEN_NODECOMPUTE.md showing before/after examples.

2. Add Troubleshooting Section

Common issues:

  • Path resolution errors
  • Type mismatches in transformations
  • Timeout not working (if not fixed)

Performance Considerations ⚡

Positive

  • ✅ Sequential execution is predictable and debuggable
  • ✅ Pure functions enable future caching/memoization
  • ✅ Step-level timing metadata helps identify bottlenecks

Potential Optimizations (Future)

  • Consider lazy evaluation for mapping steps (only resolve used paths)
  • Consider streaming for large data (v1.2+)
  • Consider step result pruning (only keep what's referenced)

Security Review 🔒

Low Risk

  • ✅ No dynamic code execution
  • ✅ No file system access
  • ✅ No network calls
  • ✅ Pure data transformations

Minor Concerns

  • ⚠️ getattr() usage in path resolution (addressed above)
  • ⚠️ Regex patterns from untrusted contracts could cause ReDoS

Recommendation: Document that contracts should be treated as trusted code.


Alignment with CLAUDE.md ✅

Excellent Adherence

  • ✅ Uses ModelOnexError consistently
  • ✅ All models use ConfigDict(extra="forbid", frozen=True)
  • ✅ Proper discriminated unions
  • ✅ Pure functional design
  • ✅ Comprehensive docstrings
  • ✅ Follows ONEX four-node architecture

Minor Gaps

  • ⚠️ Thread safety not explicitly documented (but appears safe)
  • ⚠️ No explicit Poetry usage in CI instructions

Final Recommendations

Must Fix Before Merge (P0)

  1. ❌ Run and pass full CI pipeline (mypy, tests, coverage)
  2. ⚠️ Implement timeout enforcement or remove from contract
  3. ⚠️ Verify ModelOnexError.message attribute access

Should Fix (P1)

  1. 💡 Add path resolution security (block private attributes)
  2. 💡 Document validation step limitation prominently
  3. 💡 Add thread-safety documentation

Nice to Have (P2)

  1. 📚 Add migration guide
  2. 🧪 Add integration tests
  3. ⚡ Add memory usage documentation

Conclusion

This is high-quality work that follows ONEX patterns excellently. The architecture is sound, the type safety is strong, and the documentation is comprehensive.

The main blocker is CI verification. Once CI passes and the timeout enforcement is addressed, this is ready to merge.

Estimated Effort to Address Critical Issues: 1-2 hours

Great job on this implementation! 🚀


Reviewed By: Claude Code (Sonnet 4.5)
Review Date: 2025-12-07

Security:
- Block private attribute access in path resolution (getattr security)

Quality:
- Add comprehensive Google-style docstrings with thread safety notes
- Add type aliases (JsonType, TransformationHandler) for better type safety
- Add type comments explaining intentional Any usage

Features:
- Add validation step warning logging for v1.0 pass-through mode
- Add TODO(v1.1) comments for future schema validation
- Add 19 integration tests for compute pipeline

Files modified:
- compute_executor.py: Security fix, docstrings, logging
- compute_transformations.py: Security fix, docstrings, type aliases
- mixin_compute_execution.py: Comprehensive docstrings
- model_compute_execution_context.py: Enhanced docstrings
- model_compute_pipeline_result.py: Enhanced docstrings

Files added:
- tests/integration/test_compute_pipeline_integration.py
@claude

claude Bot commented Dec 7, 2025

Copy link
Copy Markdown

PR Review: Contract-Driven NodeCompute v1.0 Implementation

Summary

This PR implements contract-driven NodeCompute with sequential pipelines and 6 built-in transformation types. The implementation follows established patterns from NodeReducer and NodeOrchestrator, achieving the goal of zero custom Python code for compute node implementations.

Overall Assessment: ✅ APPROVE with minor recommendations

This is an excellent foundation for v1.0. The code quality is high, testing is comprehensive, and the architecture follows ONEX principles consistently.


✅ Strengths

1. Architectural Excellence

  • Zero boilerplate goal achieved: Users can create compute nodes by inheriting from NodeCompute and providing a YAML contract
  • Consistent with ONEX patterns: Follows the FSM/workflow-driven approach established by NodeReducer/NodeOrchestrator
  • Clean separation of concerns: Pure transformation functions separated from pipeline orchestration
  • Immutability guarantees: All results use frozen=True, setting up v1.2 replay/observability cleanly

2. Type Safety & Code Quality

  • ✅ Excellent use of Pydantic models with discriminated unions (ModelTransformationConfig)
  • ✅ Proper frozen=True on all result models for immutability
  • ✅ Comprehensive docstrings with thread safety notes, examples, and parameter documentation
  • ✅ Security conscious: Private attribute access blocked (part.startswith('_'))

3. Testing

  • Comprehensive coverage: 95 unit tests + integration tests covering all components
  • Well-structured: Clear test organization with descriptive names and docstrings
  • Edge cases covered: Tests include error conditions, security boundaries, type validation

4. Documentation

  • Exceptional documentation: Three comprehensive markdown docs totaling 4,412 lines
  • Clear versioning roadmap: Explicit v1.0 scope with deferred features documented
  • Migration guidance: Forward-looking with upgrade paths to v1.1/v1.2

5. Error Handling

  • ✅ Consistent use of ModelOnexError (not generic Exception)
  • ✅ Proper error codes from EnumCoreErrorCode
  • ✅ Abort-on-first-failure semantics with full error context preserved

💡 Recommendations (Minor - Non-Blocking)

1. Pipeline Timeout (Minor)

Issue: pipeline_timeout_ms is defined in the contract but not enforced in v1.0.

Recommendation: Add a TODO comment or implement basic timeout checking.

Rationale: Without timeout enforcement, long-running pipelines could block indefinitely.

2. Validation Step Warning Frequency (Minor)

Issue: Validation step logs a warning every execution (compute_executor.py:307-311).

Recommendation: Consider using logger.info or logging once at contract load time to reduce log noise in production.

3. Missing Example Contract (Minor)

Issue: No working example YAML contract in examples/contracts/compute/.

Recommendation: Add the text_processor_v1.yaml example from the spec for reference.


🔒 Security Assessment

✅ No security vulnerabilities identified

  • Private attribute access properly blocked (compute_executor.py:167-171)
  • Input validation via Pydantic models with extra='forbid'
  • Regex patterns use re.sub with proper error handling

Note: Users can create slow pipelines with catastrophic backtracking regex patterns. Consider adding regex complexity analysis in v1.1.


🎯 Acceptance Criteria Check

Functional Requirements

  • ✅ ModelComputeSubcontract validates with extra='forbid'
  • ✅ All 6 transformation types implemented (IDENTITY, REGEX, CASE_CONVERSION, TRIM, NORMALIZE_UNICODE, JSON_PATH)
  • ✅ VALIDATION step type uses separate ModelValidationConfig
  • ✅ Pipeline executes steps sequentially
  • ✅ Pipeline aborts on first failure
  • ✅ Mapping resolves $.input and $.steps..output paths
  • ⚠️ Pipeline timeout defined but not enforced (see recommendation Complete SPI Migration and Core Stabilization: LogLevel Standardization + ONEX Architecture #1)

Type Safety Requirements

  • ✅ All config models have config_type discriminator
  • ✅ All models use ConfigDict(extra='forbid', frozen=True)
  • ✅ ModelTransformationConfig is proper discriminated union
  • ⏳ mypy --strict passes (will be verified in CI)

Testing Requirements

  • ✅ Unit tests for each enum
  • ✅ Unit tests for each model
  • ✅ Unit tests for each transformation type
  • ✅ Integration test with example contract
  • ⏳ 90%+ code coverage (should verify with coverage report)

📝 Adherence to CLAUDE.md

✅ Excellent adherence to project guidelines:

  1. ✅ Always use ModelOnexError (not Exception)
  2. ✅ Protocol-driven DI (mixin doesn't directly import concrete classes)
  3. ✅ Immutability guarantees (all results frozen=True)
  4. ✅ Thread safety documentation (explicitly documented in all modules)
  5. ✅ Pure functions (all transformations are pure, side-effect-free)
  6. ✅ Comprehensive docstrings (Google-style with examples and thread safety notes)

🎉 Final Verdict

Status: ✅ APPROVE

This is a well-crafted, production-ready v1.0 implementation that:

  • Achieves the zero-boilerplate goal for compute nodes
  • Follows ONEX architectural patterns consistently
  • Provides a solid foundation for incremental feature addition (v1.1+)
  • Maintains high code quality and comprehensive testing
  • Documents limitations and future work clearly

The recommendations above are minor enhancements that can be addressed in follow-up PRs or v1.1. None are blocking for merge.

Great work! This sets a strong precedent for contract-driven node implementations.


Reviewer: Claude Code
Review Date: 2025-12-07
Files Changed: 36 files (+8,398 additions)
Test Coverage: 95 unit tests + integration tests

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (22)
src/omnibase_core/enums/enum_unicode_form.py (1)

7-24: Well-structured enum with correct Unicode normalization forms.

The enum correctly defines the four standard Unicode normalization forms (NFC, NFD, NFKC, NFKD) that align with Python's unicodedata.normalize() function. The (str, Enum) base classes ensure JSON serialization compatibility.

Consider adding __all__ for explicit public API declaration, consistent with other modules like model_compute_execution_context.py:

 from enum import Enum
 
+__all__ = [
+    "EnumUnicodeForm",
+]
+
 
 class EnumUnicodeForm(str, Enum):
src/omnibase_core/models/compute/model_compute_execution_context.py (1)

91-95: Clean, immutable execution context model.

The model is well-designed with proper type annotations and immutability via frozen=True. The documentation is thorough.

For consistency with other v1.0 models like ModelTransformCaseConfig which use ConfigDict(extra="forbid", frozen=True), consider adding extra="forbid" to reject unexpected fields:

-    model_config = ConfigDict(frozen=True)
+    model_config = ConfigDict(extra="forbid", frozen=True)

This provides stricter schema validation and guards against typos in field names during instantiation.

src/omnibase_core/models/transformations/model_transform_case_config.py (1)

15-27: Well-structured discriminated union config model.

The model correctly implements the discriminated union pattern with config_type as the discriminator. Using ConfigDict(extra="forbid", frozen=True) ensures strict validation and immutability, aligning with the coding guidelines.

Consider adding __all__ for explicit public API declaration:

 from omnibase_core.enums.enum_case_mode import EnumCaseMode
 
+__all__ = [
+    "ModelTransformCaseConfig",
+]
+

 class ModelTransformCaseConfig(BaseModel):
tests/unit/enums/test_compute_enums.py (1)

53-66: Consider adding member count tests for remaining enums.

TestEnumComputeStepType and TestEnumTransformationType include test_member_count to validate v1.0 contract boundaries. For consistency and to guard against accidental additions, consider adding similar tests for the remaining enums:

def test_member_count(self) -> None:
    """Test v1.0 member count."""
    assert len(EnumCaseMode) == 3

# Similarly for:
# EnumRegexFlag: 3 members
# EnumUnicodeForm: 4 members  
# EnumTrimMode: 3 members
tests/unit/models/transformations/test_transformation_configs.py (1)

1-24: Solid config coverage; add pytest markers/timeout for consistency

The tests exercise creation, defaults, extra-field rejection, and immutability across all config models — this looks good. To align with the repo’s test conventions, consider adding module-level markers and a timeout:

 import pytest
 from pydantic import ValidationError
 
+pytestmark = [pytest.mark.unit, pytest.mark.timeout(5)]
+

This keeps the file concise while satisfying the requirement for @pytest.mark.unit and @pytest.mark.timeout() on tests. As per coding guidelines, tests should consistently use these markers.

src/omnibase_core/models/compute/model_compute_step_metadata.py (1)

14-26: Consider constraining duration_ms to non-negative values

The model is clean and immutable, matching the compute models pattern. If you want to guard against accidental negative durations, you could add a ge=0 constraint via Field or similar. Not required for correctness, but it would make the timing metadata stricter and self-validating.

src/omnibase_core/models/transformations/model_transform_json_path_config.py (1)

13-25: Optional: add lightweight validation for JSONPath strings

The config model is minimal, immutable, and uses a clear discriminator, which fits the transformation-union pattern well. If you want slightly stronger contracts, consider a small validator (e.g., ensuring path is non-empty and maybe starts with "$"), while still keeping parsing to the execution layer. Based on learnings, this stays aligned with the “immutable Pydantic models” guideline.

docs/architecture/NODECOMPUTE_VERSIONING_ROADMAP.md (3)

106-112: Add language identifier to fenced code block.

The code block should specify a language for syntax highlighting and better markdown compliance.

Apply this diff:

-```
+```text
 1.x.y
 | | |
 | | +-- Patch: Bug fixes, performance improvements (no API changes)
 | +---- Minor: New features, new transformations (backward compatible)
 +------ Major: Breaking changes (new replay epoch)

---

`132-138`: **Add language identifier to fenced code block.**

Specify a language (e.g., `text` or `plaintext`) for the timeline code block.



Apply this diff:

```diff
-```
+```text
 Q1 2025: v1.0 Implementation and Production Validation
 Q2 2025: v1.1 Design and Implementation (if warranted)
 Q3 2025: v1.2 Design and Implementation (if warranted)
 Q4 2025: v1.3 Design and Implementation (if warranted)

---

`927-931`: **Add language identifier to fenced code block.**

Specify a language (e.g., `text`) for the compatibility promise code block.



Apply this diff:

```diff
-```
+```text
 Any contract valid in v1.0 MUST be valid in v1.3
 Any contract valid in v1.0 MUST produce identical output in v1.3
 Any ledger entry from v1.0 MUST be replayable in v1.3

</blockquote></details>
<details>
<summary>src/omnibase_core/models/contracts/subcontracts/model_compute_subcontract.py (1)</summary><blockquote>

`45-49`: **Consider adding validation for `pipeline_timeout_ms` and `pipeline`.**

The `pipeline_timeout_ms` field accepts any integer including zero or negative values, which would be invalid. Similarly, an empty pipeline list may be semantically invalid.



Consider adding a `model_validator` or `field_validator`:

```diff
+from pydantic import BaseModel, ConfigDict, field_validator
+
 class ModelComputeSubcontract(BaseModel):
     ...
+
+    @field_validator("pipeline_timeout_ms")
+    @classmethod
+    def validate_timeout(cls, v: int | None) -> int | None:
+        if v is not None and v <= 0:
+            raise ValueError("pipeline_timeout_ms must be positive")
+        return v
src/omnibase_core/models/transformations/model_mapping_config.py (1)

26-28: Consider validating field_mappings is non-empty.

An empty field_mappings dictionary would produce a no-op mapping step, which may not be the intended behavior.

+from pydantic import BaseModel, ConfigDict, field_validator
+
 class ModelMappingConfig(BaseModel):
     ...
+
+    @field_validator("field_mappings")
+    @classmethod
+    def validate_field_mappings(cls, v: dict[str, str]) -> dict[str, str]:
+        if not v:
+            raise ValueError("field_mappings must not be empty")
+        return v

Alternatively, if empty mappings are valid for passthrough semantics, this can be ignored.

docs/architecture/CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md (1)

482-486: Add language specifier to fenced code blocks.

The ASCII diagrams should have a language specifier for markdown linting compliance.

Apply this pattern to the diagram code blocks:

-```
+```text
 Step 1 → Step 2 → Step 3 → ... → Step N → Output

This applies to the diagrams at lines 482-486, 503-510, and 677-691.

Also applies to: 503-510, 677-691

tests/unit/models/compute/test_compute_models.py (2)

1-9: Missing pytest marker for unit tests.

Per coding guidelines, test files should use pytest markers. Add @pytest.mark.unit to the test classes or configure it at the module level.

 """Unit tests for Contract-Driven NodeCompute v1.0 compute models."""
+
 import pytest
 from uuid import uuid4
+
+pytestmark = pytest.mark.unit
 
 from omnibase_core.models.compute.model_compute_execution_context import ModelComputeExecutionContext

35-39: Use specific exception type for frozen model tests.

pytest.raises(Exception) is too broad. Pydantic frozen models raise pydantic.ValidationError when mutation is attempted. Using the specific exception type improves test reliability.

+from pydantic import ValidationError
+
 # In each test_is_frozen method:
-    with pytest.raises(Exception):  # ValidationError for frozen model
+    with pytest.raises(ValidationError):

Apply this pattern to all four test_is_frozen methods (lines 38, 63, 108, 173).

src/omnibase_core/mixins/mixin_compute_execution.py (1)

37-47: Inconsistent UUID import pattern.

uuid4 is imported at runtime while UUID is only imported under TYPE_CHECKING. Since UUID is used in the runtime type hint for node_id (line 85), this should work but is inconsistent. Consider importing UUID at runtime for clarity.

-from typing import Any, TYPE_CHECKING
+from typing import Any
-from uuid import uuid4
+from uuid import UUID, uuid4
 
 from omnibase_core.models.compute.model_compute_execution_context import ModelComputeExecutionContext
 from omnibase_core.models.compute.model_compute_pipeline_result import ModelComputePipelineResult
 from omnibase_core.models.contracts.subcontracts.model_compute_subcontract import ModelComputeSubcontract
 from omnibase_core.utils.compute_executor import execute_compute_pipeline
 
-if TYPE_CHECKING:
-    from uuid import UUID
-
tests/integration/test_compute_pipeline_integration.py (3)

1-17: Missing pytest marker for integration tests.

Per coding guidelines, add @pytest.mark.integration marker for integration tests. Also consider extracting the duplicate _create_context helper.

 """
 Integration tests for contract-driven NodeCompute pipeline execution.
 ...
 """
 
 from uuid import uuid4
 
 import pytest
 
+pytestmark = pytest.mark.integration
+
 from omnibase_core.enums.enum_case_mode import EnumCaseMode

476-478: Simplify regex test assertion.

The compound assertion is confusing and potentially fragile. Since the regex with IGNORECASE should replace all variations of "hello", assert the exact expected output directly.

         assert result.success is True
-        # All variations of "hello" should be replaced
-        assert "hello" not in result.output.lower() or result.output == "hi World, hi friend, hi there"
+        # All variations of "hello" should be replaced (case-insensitive)
+        assert result.output == "hi World, hi friend, hi there"

55-60: Consider extracting duplicate helper to fixture.

The _create_context method is duplicated in TestComputePipelineErrorScenarios (line 615). Consider using a module-level pytest fixture for DRY.

+@pytest.fixture
+def execution_context() -> ModelComputeExecutionContext:
+    """Create a test execution context."""
+    return ModelComputeExecutionContext(
+        operation_id=uuid4(),
+        correlation_id=uuid4(),
+    )
+
+
 class TestComputePipelineIntegration:
     """Integration tests for complete pipeline scenarios."""
-
-    def _create_context(self) -> ModelComputeExecutionContext:
-        """Create a test execution context."""
-        return ModelComputeExecutionContext(
-            operation_id=uuid4(),
-            correlation_id=uuid4(),
-        )

Then use execution_context fixture parameter in test methods instead of self._create_context().

src/omnibase_core/utils/compute_executor.py (1)

317-377: Step dispatcher is correct; minor redundancy only

Dispatching on EnumComputeStepType with dedicated handlers for TRANSFORMATION, MAPPING, and VALIDATION is clean, and missing configuration cases correctly raise ModelOnexError. The extra if not step.enabled here is redundant because disabled steps are already skipped in the main loop, but it’s harmless; you could drop it later to reduce duplication.

docs/architecture/NODECOMPUTE_FULL_DESIGN_V1X_TARGET.md (1)

1-2473: Tidy up markdownlint issues (fence languages, emphasis headings, duplicate heading)

markdownlint flags a few mechanical issues in this doc:

  • Fenced code blocks without a language (e.g., generic triple‑backticks) – add text, yaml, or python as appropriate.
  • Lines using emphasis as a pseudo‑heading (e.g., **Phase 1: Load**) – convert these to proper ###/#### headings.
  • Duplicate heading text (another “Transformation Registry” section later in the file) – rename or merge to avoid MD024.

These are minor, but fixing them will keep docs lint‑clean while preserving the existing v1.x design content.

src/omnibase_core/utils/compute_transformations.py (1)

76-99: Align transform_identity signature with other handlers for safer registry use

Right now transform_identity only accepts data, but TRANSFORMATION_REGISTRY is documented as a generic handler registry and execute_transformation calls other handlers as (data, config). If any caller ever uses the registry directly and assumes a uniform (data, config) signature, IDENTITY will raise a TypeError.

To future‑proof the API, consider letting transform_identity accept an optional (ignored) config:

-def transform_identity(
-    data: Any,  # Any: intentionally polymorphic - accepts any input type unchanged
-) -> Any:  # Any: output type mirrors input type
+def transform_identity(
+    data: Any,  # Any: intentionally polymorphic - accepts any input type unchanged
+    config: ModelTransformationConfig | None = None,
+) -> Any:  # Any: output type mirrors input type

execute_transformation can keep calling it as it does now, and registry lookups remain safe for uniform (data, config) calls.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 00e26d9 and 8132d58.

📒 Files selected for processing (36)
  • docs/architecture/CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md (1 hunks)
  • docs/architecture/NODECOMPUTE_FULL_DESIGN_V1X_TARGET.md (1 hunks)
  • docs/architecture/NODECOMPUTE_VERSIONING_ROADMAP.md (1 hunks)
  • src/omnibase_core/enums/__init__.py (5 hunks)
  • src/omnibase_core/enums/enum_case_mode.py (1 hunks)
  • src/omnibase_core/enums/enum_compute_step_type.py (1 hunks)
  • src/omnibase_core/enums/enum_regex_flag.py (1 hunks)
  • src/omnibase_core/enums/enum_transformation_type.py (1 hunks)
  • src/omnibase_core/enums/enum_trim_mode.py (1 hunks)
  • src/omnibase_core/enums/enum_unicode_form.py (1 hunks)
  • src/omnibase_core/mixins/__init__.py (2 hunks)
  • src/omnibase_core/mixins/mixin_compute_execution.py (1 hunks)
  • src/omnibase_core/models/compute/__init__.py (1 hunks)
  • src/omnibase_core/models/compute/model_compute_execution_context.py (1 hunks)
  • src/omnibase_core/models/compute/model_compute_pipeline_result.py (1 hunks)
  • src/omnibase_core/models/compute/model_compute_step_metadata.py (1 hunks)
  • src/omnibase_core/models/compute/model_compute_step_result.py (1 hunks)
  • src/omnibase_core/models/contracts/subcontracts/__init__.py (2 hunks)
  • src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py (1 hunks)
  • src/omnibase_core/models/contracts/subcontracts/model_compute_subcontract.py (1 hunks)
  • src/omnibase_core/models/transformations/__init__.py (1 hunks)
  • src/omnibase_core/models/transformations/model_mapping_config.py (1 hunks)
  • src/omnibase_core/models/transformations/model_transform_case_config.py (1 hunks)
  • src/omnibase_core/models/transformations/model_transform_json_path_config.py (1 hunks)
  • src/omnibase_core/models/transformations/model_transform_regex_config.py (1 hunks)
  • src/omnibase_core/models/transformations/model_transform_trim_config.py (1 hunks)
  • src/omnibase_core/models/transformations/model_transform_unicode_config.py (1 hunks)
  • src/omnibase_core/models/transformations/model_validation_step_config.py (1 hunks)
  • src/omnibase_core/models/transformations/types.py (1 hunks)
  • src/omnibase_core/utils/compute_executor.py (1 hunks)
  • src/omnibase_core/utils/compute_transformations.py (1 hunks)
  • tests/integration/test_compute_pipeline_integration.py (1 hunks)
  • tests/unit/enums/test_compute_enums.py (1 hunks)
  • tests/unit/models/compute/test_compute_models.py (1 hunks)
  • tests/unit/models/transformations/test_transformation_configs.py (1 hunks)
  • tests/unit/utils/test_compute_pipeline.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Always use Poetry for Python package management and task execution. Use poetry run for pytest, mypy, black, isort, and other tools. Never use pip directly or execute python commands without the poetry run prefix.
Enforce 100% strict mypy compliance. All functions must have complete type annotations. Use poetry run mypy src/omnibase_core/ to verify strict mode compliance with no errors.
Format code with black, sort imports with isort, and lint with ruff. Run poetry run black src/ tests/, poetry run isort src/ tests/, and poetry run ruff check --fix src/ tests/

Files:

  • src/omnibase_core/models/transformations/model_transform_json_path_config.py
  • src/omnibase_core/models/compute/model_compute_execution_context.py
  • src/omnibase_core/models/transformations/model_transform_case_config.py
  • src/omnibase_core/models/compute/__init__.py
  • src/omnibase_core/enums/enum_compute_step_type.py
  • tests/unit/models/compute/test_compute_models.py
  • src/omnibase_core/enums/enum_regex_flag.py
  • src/omnibase_core/enums/enum_transformation_type.py
  • src/omnibase_core/models/transformations/model_validation_step_config.py
  • src/omnibase_core/models/transformations/types.py
  • src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py
  • tests/unit/enums/test_compute_enums.py
  • src/omnibase_core/models/transformations/model_transform_unicode_config.py
  • src/omnibase_core/models/contracts/subcontracts/model_compute_subcontract.py
  • src/omnibase_core/models/transformations/model_transform_regex_config.py
  • src/omnibase_core/utils/compute_executor.py
  • src/omnibase_core/models/compute/model_compute_step_metadata.py
  • src/omnibase_core/enums/enum_trim_mode.py
  • tests/unit/models/transformations/test_transformation_configs.py
  • tests/unit/utils/test_compute_pipeline.py
  • src/omnibase_core/enums/__init__.py
  • src/omnibase_core/models/compute/model_compute_step_result.py
  • src/omnibase_core/enums/enum_case_mode.py
  • src/omnibase_core/mixins/mixin_compute_execution.py
  • tests/integration/test_compute_pipeline_integration.py
  • src/omnibase_core/enums/enum_unicode_form.py
  • src/omnibase_core/models/transformations/model_transform_trim_config.py
  • src/omnibase_core/models/contracts/subcontracts/__init__.py
  • src/omnibase_core/mixins/__init__.py
  • src/omnibase_core/models/compute/model_compute_pipeline_result.py
  • src/omnibase_core/utils/compute_transformations.py
  • src/omnibase_core/models/transformations/__init__.py
  • src/omnibase_core/models/transformations/model_mapping_config.py
src/omnibase_core/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/omnibase_core/**/*.py: Use protocol names with container.get_service() for dependency injection, never resolve services by concrete class names. Example: container.get_service('ProtocolEventBus') instead of container.get_service('EventBusService')
Always use ModelONEXContainer for dependency injection in node constructors and service resolution. Never confuse it with ModelContainer[T], which is a generic value wrapper, not a DI container.
Use structured error handling with ModelOnexError and EnumCoreErrorCode, never raise generic Exception. Always chain exceptions with from e when catching and re-raising.
Use the @standard_error_handling decorator on methods to eliminate 6+ lines of try/catch boilerplate. Example: @standard_error_handling above async methods.
Respect thread safety constraints: Do NOT share node instances (NodeCompute, NodeEffect), cache, or circuit breaker instances across threads without synchronization. Use thread-local instances or locks.
Use duck typing with protocols. Do not use isinstance checks with protocol types. Rely on the protocol interface directly.
Use EnumNodeKind for high-level architectural classification (EFFECT, COMPUTE, REDUCER, ORCHESTRATOR) when routing data through the ONEX pipeline. Use EnumNodeType for specific implementation discovery and capability matching.
Use ModelEventEnvelope for inter-service event-driven communication. Process events through the envelope pattern for consistent event handling.

Files:

  • src/omnibase_core/models/transformations/model_transform_json_path_config.py
  • src/omnibase_core/models/compute/model_compute_execution_context.py
  • src/omnibase_core/models/transformations/model_transform_case_config.py
  • src/omnibase_core/models/compute/__init__.py
  • src/omnibase_core/enums/enum_compute_step_type.py
  • src/omnibase_core/enums/enum_regex_flag.py
  • src/omnibase_core/enums/enum_transformation_type.py
  • src/omnibase_core/models/transformations/model_validation_step_config.py
  • src/omnibase_core/models/transformations/types.py
  • src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py
  • src/omnibase_core/models/transformations/model_transform_unicode_config.py
  • src/omnibase_core/models/contracts/subcontracts/model_compute_subcontract.py
  • src/omnibase_core/models/transformations/model_transform_regex_config.py
  • src/omnibase_core/utils/compute_executor.py
  • src/omnibase_core/models/compute/model_compute_step_metadata.py
  • src/omnibase_core/enums/enum_trim_mode.py
  • src/omnibase_core/enums/__init__.py
  • src/omnibase_core/models/compute/model_compute_step_result.py
  • src/omnibase_core/enums/enum_case_mode.py
  • src/omnibase_core/mixins/mixin_compute_execution.py
  • src/omnibase_core/enums/enum_unicode_form.py
  • src/omnibase_core/models/transformations/model_transform_trim_config.py
  • src/omnibase_core/models/contracts/subcontracts/__init__.py
  • src/omnibase_core/mixins/__init__.py
  • src/omnibase_core/models/compute/model_compute_pipeline_result.py
  • src/omnibase_core/utils/compute_transformations.py
  • src/omnibase_core/models/transformations/__init__.py
  • src/omnibase_core/models/transformations/model_mapping_config.py
src/omnibase_core/models/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Use Pydantic 2.11+ models for all data validation and serialization. Ensure models are immutable after creation for thread safety.

Files:

  • src/omnibase_core/models/transformations/model_transform_json_path_config.py
  • src/omnibase_core/models/compute/model_compute_execution_context.py
  • src/omnibase_core/models/transformations/model_transform_case_config.py
  • src/omnibase_core/models/compute/__init__.py
  • src/omnibase_core/models/transformations/model_validation_step_config.py
  • src/omnibase_core/models/transformations/types.py
  • src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py
  • src/omnibase_core/models/transformations/model_transform_unicode_config.py
  • src/omnibase_core/models/contracts/subcontracts/model_compute_subcontract.py
  • src/omnibase_core/models/transformations/model_transform_regex_config.py
  • src/omnibase_core/models/compute/model_compute_step_metadata.py
  • src/omnibase_core/models/compute/model_compute_step_result.py
  • src/omnibase_core/models/transformations/model_transform_trim_config.py
  • src/omnibase_core/models/contracts/subcontracts/__init__.py
  • src/omnibase_core/models/compute/model_compute_pipeline_result.py
  • src/omnibase_core/models/transformations/__init__.py
  • src/omnibase_core/models/transformations/model_mapping_config.py
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Write tests using pytest with async support via pytest-asyncio. Maintain minimum 60% code coverage. Use pytest markers: @pytest.mark.unit, @pytest.mark.integration, @pytest.mark.slow
Add @pytest.mark.timeout() to prevent test hangs. Run tests with poetry run pytest tests/ --timeout=60 for 60-second timeout protection.

Files:

  • tests/unit/models/compute/test_compute_models.py
  • tests/unit/enums/test_compute_enums.py
  • tests/unit/models/transformations/test_transformation_configs.py
  • tests/unit/utils/test_compute_pipeline.py
  • tests/integration/test_compute_pipeline_integration.py
src/omnibase_core/mixins/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Mixin classes should be composed into node classes for specific capabilities. Available mixins include: MixinDiscoveryResponder, MixinEventHandler, MixinEventListener, MixinNodeExecutor, MixinNodeLifecycle, MixinRequestResponseIntrospection, MixinWorkflowSupport.

Files:

  • src/omnibase_core/mixins/mixin_compute_execution.py
  • src/omnibase_core/mixins/__init__.py
🧠 Learnings (8)
📓 Common learnings
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/nodes/node_compute.py : NodeCompute is for data processing and transformation. Inherit from NodeCompute for COMPUTE nodes that perform calculations, validations, and data mapping.
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/models/**/*.py : Use Pydantic 2.11+ models for all data validation and serialization. Ensure models are immutable after creation for thread safety.

Applied to files:

  • src/omnibase_core/models/transformations/model_transform_json_path_config.py
  • src/omnibase_core/models/transformations/model_validation_step_config.py
  • src/omnibase_core/models/transformations/types.py
  • src/omnibase_core/models/transformations/model_transform_unicode_config.py
  • src/omnibase_core/models/transformations/model_mapping_config.py
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/nodes/node_compute.py : NodeCompute is for data processing and transformation. Inherit from NodeCompute for COMPUTE nodes that perform calculations, validations, and data mapping.

Applied to files:

  • src/omnibase_core/models/compute/__init__.py
  • tests/unit/models/compute/test_compute_models.py
  • src/omnibase_core/enums/__init__.py
  • src/omnibase_core/mixins/mixin_compute_execution.py
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to docs/guides/node-building/**/*.md : Node building guide is the critical starting point for developers and AI agents. Follow the sequence: What is a Node → Node Types → COMPUTE Tutorial → EFFECT Tutorial → REDUCER Tutorial → ORCHESTRATOR Tutorial.

Applied to files:

  • docs/architecture/NODECOMPUTE_VERSIONING_ROADMAP.md
  • docs/architecture/NODECOMPUTE_FULL_DESIGN_V1X_TARGET.md
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/**/*.py : Use EnumNodeKind for high-level architectural classification (EFFECT, COMPUTE, REDUCER, ORCHESTRATOR) when routing data through the ONEX pipeline. Use EnumNodeType for specific implementation discovery and capability matching.

Applied to files:

  • src/omnibase_core/enums/enum_compute_step_type.py
  • src/omnibase_core/enums/enum_transformation_type.py
  • src/omnibase_core/enums/__init__.py
  • src/omnibase_core/enums/enum_case_mode.py
📚 Learning: 2025-09-23T22:28:00.333Z
Learnt from: jonahgabriel
Repo: OmniNode-ai/omnibase_core PR: 32
File: examples/practical_migration_example.py:125-134
Timestamp: 2025-09-23T22:28:00.333Z
Learning: The omnibase_core codebase extensively uses constrained TypeVars for primitive types with the pattern `T = TypeVar("T", str, int, float, bool)` across multiple models including ModelTypedMetrics, ModelGenericMetadata, and ModelExecutionResult. This is the preferred approach over hardcoded union types like `str | int | bool | float | None`.

Applied to files:

  • src/omnibase_core/models/transformations/types.py
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/mixins/**/*.py : Mixin classes should be composed into node classes for specific capabilities. Available mixins include: MixinDiscoveryResponder, MixinEventHandler, MixinEventListener, MixinNodeExecutor, MixinNodeLifecycle, MixinRequestResponseIntrospection, MixinWorkflowSupport.

Applied to files:

  • src/omnibase_core/mixins/mixin_compute_execution.py
  • src/omnibase_core/mixins/__init__.py
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Respect the ONEX Four-Node Architecture: data flows unidirectionally from EFFECT → COMPUTE → REDUCER → ORCHESTRATOR with no backwards dependencies. This is an architectural principle, not tied to specific files.

Applied to files:

  • docs/architecture/NODECOMPUTE_FULL_DESIGN_V1X_TARGET.md
🧬 Code graph analysis (21)
src/omnibase_core/models/compute/model_compute_execution_context.py (1)
src/omnibase_core/models/metadata/model_metadata_field_info.py (1)
  • uuid (162-181)
src/omnibase_core/models/transformations/model_transform_case_config.py (1)
src/omnibase_core/enums/enum_case_mode.py (1)
  • EnumCaseMode (10-22)
src/omnibase_core/models/compute/__init__.py (4)
src/omnibase_core/models/compute/model_compute_execution_context.py (1)
  • ModelComputeExecutionContext (44-95)
src/omnibase_core/models/compute/model_compute_pipeline_result.py (1)
  • ModelComputePipelineResult (53-122)
src/omnibase_core/models/compute/model_compute_step_metadata.py (1)
  • ModelComputeStepMetadata (14-26)
src/omnibase_core/models/compute/model_compute_step_result.py (1)
  • ModelComputeStepResult (23-43)
tests/unit/models/compute/test_compute_models.py (4)
src/omnibase_core/models/compute/model_compute_execution_context.py (1)
  • ModelComputeExecutionContext (44-95)
src/omnibase_core/models/compute/model_compute_step_metadata.py (1)
  • ModelComputeStepMetadata (14-26)
src/omnibase_core/models/compute/model_compute_step_result.py (1)
  • ModelComputeStepResult (23-43)
src/omnibase_core/models/compute/model_compute_pipeline_result.py (1)
  • ModelComputePipelineResult (53-122)
src/omnibase_core/models/transformations/types.py (5)
src/omnibase_core/models/transformations/model_transform_case_config.py (1)
  • ModelTransformCaseConfig (15-27)
src/omnibase_core/models/transformations/model_transform_json_path_config.py (1)
  • ModelTransformJsonPathConfig (13-25)
src/omnibase_core/models/transformations/model_transform_regex_config.py (1)
  • ModelTransformRegexConfig (15-31)
src/omnibase_core/models/transformations/model_transform_trim_config.py (1)
  • ModelTransformTrimConfig (15-27)
src/omnibase_core/models/transformations/model_transform_unicode_config.py (1)
  • ModelTransformUnicodeConfig (15-27)
src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py (4)
src/omnibase_core/enums/enum_compute_step_type.py (1)
  • EnumComputeStepType (11-27)
src/omnibase_core/enums/enum_transformation_type.py (1)
  • EnumTransformationType (11-34)
src/omnibase_core/models/transformations/model_mapping_config.py (1)
  • ModelMappingConfig (13-29)
src/omnibase_core/models/transformations/model_validation_step_config.py (1)
  • ModelValidationStepConfig (13-30)
tests/unit/enums/test_compute_enums.py (6)
src/omnibase_core/enums/enum_compute_step_type.py (1)
  • EnumComputeStepType (11-27)
src/omnibase_core/enums/enum_transformation_type.py (1)
  • EnumTransformationType (11-34)
src/omnibase_core/enums/enum_case_mode.py (1)
  • EnumCaseMode (10-22)
src/omnibase_core/enums/enum_regex_flag.py (1)
  • EnumRegexFlag (10-22)
src/omnibase_core/enums/enum_unicode_form.py (1)
  • EnumUnicodeForm (10-24)
src/omnibase_core/enums/enum_trim_mode.py (1)
  • EnumTrimMode (10-22)
src/omnibase_core/models/transformations/model_transform_unicode_config.py (1)
src/omnibase_core/enums/enum_unicode_form.py (1)
  • EnumUnicodeForm (10-24)
src/omnibase_core/models/contracts/subcontracts/model_compute_subcontract.py (1)
src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py (1)
  • ModelComputePipelineStep (20-90)
src/omnibase_core/models/transformations/model_transform_regex_config.py (1)
src/omnibase_core/enums/enum_regex_flag.py (1)
  • EnumRegexFlag (10-22)
src/omnibase_core/utils/compute_executor.py (5)
src/omnibase_core/enums/enum_compute_step_type.py (1)
  • EnumComputeStepType (11-27)
src/omnibase_core/models/compute/model_compute_execution_context.py (1)
  • ModelComputeExecutionContext (44-95)
src/omnibase_core/models/compute/model_compute_pipeline_result.py (1)
  • ModelComputePipelineResult (53-122)
src/omnibase_core/models/compute/model_compute_step_metadata.py (1)
  • ModelComputeStepMetadata (14-26)
src/omnibase_core/models/compute/model_compute_step_result.py (1)
  • ModelComputeStepResult (23-43)
tests/unit/utils/test_compute_pipeline.py (10)
src/omnibase_core/models/compute/model_compute_execution_context.py (1)
  • ModelComputeExecutionContext (44-95)
src/omnibase_core/models/compute/model_compute_step_metadata.py (1)
  • ModelComputeStepMetadata (14-26)
src/omnibase_core/models/compute/model_compute_step_result.py (1)
  • ModelComputeStepResult (23-43)
src/omnibase_core/models/transformations/model_mapping_config.py (1)
  • ModelMappingConfig (13-29)
src/omnibase_core/models/transformations/model_transform_case_config.py (1)
  • ModelTransformCaseConfig (15-27)
src/omnibase_core/models/transformations/model_transform_json_path_config.py (1)
  • ModelTransformJsonPathConfig (13-25)
src/omnibase_core/models/transformations/model_transform_regex_config.py (1)
  • ModelTransformRegexConfig (15-31)
src/omnibase_core/models/transformations/model_transform_trim_config.py (1)
  • ModelTransformTrimConfig (15-27)
src/omnibase_core/models/transformations/model_transform_unicode_config.py (1)
  • ModelTransformUnicodeConfig (15-27)
src/omnibase_core/utils/compute_transformations.py (7)
  • execute_transformation (392-452)
  • transform_case (157-203)
  • transform_identity (76-99)
  • transform_json_path (298-377)
  • transform_regex (102-154)
  • transform_trim (206-253)
  • transform_unicode (256-295)
src/omnibase_core/enums/__init__.py (6)
src/omnibase_core/enums/enum_case_mode.py (1)
  • EnumCaseMode (10-22)
src/omnibase_core/enums/enum_compute_step_type.py (1)
  • EnumComputeStepType (11-27)
src/omnibase_core/enums/enum_regex_flag.py (1)
  • EnumRegexFlag (10-22)
src/omnibase_core/enums/enum_transformation_type.py (1)
  • EnumTransformationType (11-34)
src/omnibase_core/enums/enum_trim_mode.py (1)
  • EnumTrimMode (10-22)
src/omnibase_core/enums/enum_unicode_form.py (1)
  • EnumUnicodeForm (10-24)
src/omnibase_core/models/compute/model_compute_step_result.py (1)
src/omnibase_core/models/compute/model_compute_step_metadata.py (1)
  • ModelComputeStepMetadata (14-26)
src/omnibase_core/mixins/mixin_compute_execution.py (4)
src/omnibase_core/models/compute/model_compute_execution_context.py (1)
  • ModelComputeExecutionContext (44-95)
src/omnibase_core/models/compute/model_compute_pipeline_result.py (1)
  • ModelComputePipelineResult (53-122)
src/omnibase_core/models/contracts/subcontracts/model_compute_subcontract.py (1)
  • ModelComputeSubcontract (16-51)
src/omnibase_core/utils/compute_executor.py (1)
  • execute_compute_pipeline (379-539)
src/omnibase_core/models/transformations/model_transform_trim_config.py (1)
src/omnibase_core/enums/enum_trim_mode.py (1)
  • EnumTrimMode (10-22)
src/omnibase_core/models/contracts/subcontracts/__init__.py (2)
src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py (1)
  • ModelComputePipelineStep (20-90)
src/omnibase_core/models/contracts/subcontracts/model_compute_subcontract.py (1)
  • ModelComputeSubcontract (16-51)
src/omnibase_core/mixins/__init__.py (1)
src/omnibase_core/mixins/mixin_compute_execution.py (1)
  • MixinComputeExecution (49-204)
src/omnibase_core/models/compute/model_compute_pipeline_result.py (1)
src/omnibase_core/models/compute/model_compute_step_result.py (1)
  • ModelComputeStepResult (23-43)
src/omnibase_core/utils/compute_transformations.py (11)
src/omnibase_core/enums/enum_case_mode.py (1)
  • EnumCaseMode (10-22)
src/omnibase_core/enums/enum_core_error_code.py (1)
  • EnumCoreErrorCode (9-154)
src/omnibase_core/enums/enum_regex_flag.py (1)
  • EnumRegexFlag (10-22)
src/omnibase_core/enums/enum_transformation_type.py (1)
  • EnumTransformationType (11-34)
src/omnibase_core/enums/enum_trim_mode.py (1)
  • EnumTrimMode (10-22)
src/omnibase_core/enums/enum_unicode_form.py (1)
  • EnumUnicodeForm (10-24)
src/omnibase_core/models/transformations/model_transform_case_config.py (1)
  • ModelTransformCaseConfig (15-27)
src/omnibase_core/models/transformations/model_transform_json_path_config.py (1)
  • ModelTransformJsonPathConfig (13-25)
src/omnibase_core/models/transformations/model_transform_regex_config.py (1)
  • ModelTransformRegexConfig (15-31)
src/omnibase_core/models/transformations/model_transform_trim_config.py (1)
  • ModelTransformTrimConfig (15-27)
src/omnibase_core/models/transformations/model_transform_unicode_config.py (1)
  • ModelTransformUnicodeConfig (15-27)
src/omnibase_core/models/transformations/__init__.py (7)
src/omnibase_core/models/transformations/model_mapping_config.py (1)
  • ModelMappingConfig (13-29)
src/omnibase_core/models/transformations/model_transform_case_config.py (1)
  • ModelTransformCaseConfig (15-27)
src/omnibase_core/models/transformations/model_transform_json_path_config.py (1)
  • ModelTransformJsonPathConfig (13-25)
src/omnibase_core/models/transformations/model_transform_regex_config.py (1)
  • ModelTransformRegexConfig (15-31)
src/omnibase_core/models/transformations/model_transform_trim_config.py (1)
  • ModelTransformTrimConfig (15-27)
src/omnibase_core/models/transformations/model_transform_unicode_config.py (1)
  • ModelTransformUnicodeConfig (15-27)
src/omnibase_core/models/transformations/model_validation_step_config.py (1)
  • ModelValidationStepConfig (13-30)
🪛 LanguageTool
docs/architecture/NODECOMPUTE_VERSIONING_ROADMAP.md

[style] ~55-~55: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...itions. Boring code is debuggable code. Boring APIs are learnable APIs. Stable: O...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

🪛 markdownlint-cli2 (0.18.1)
docs/architecture/NODECOMPUTE_VERSIONING_ROADMAP.md

106-106: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


132-132: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


927-927: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

docs/architecture/CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md

482-482: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


503-503: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


677-677: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

docs/architecture/NODECOMPUTE_FULL_DESIGN_V1X_TARGET.md

849-849: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


1318-1318: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


1323-1323: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


1328-1328: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


1333-1333: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


1338-1338: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


1343-1343: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


1348-1348: Emphasis used instead of a heading

(MD036, no-emphasis-as-heading)


1366-1366: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


1879-1879: Multiple headings with the same content

(MD024, no-duplicate-heading)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: claude-review
  • GitHub Check: Smoke Tests
🔇 Additional comments (38)
src/omnibase_core/enums/enum_trim_mode.py (1)

7-22: LGTM!

The enum correctly defines the three standard trim modes with lowercase string values appropriate for JSON serialization. The (str, Enum) pattern ensures proper serialization.

Same optional consistency note: consider adding __all__ to match other modules with explicit exports.

tests/unit/enums/test_compute_enums.py (1)

12-111: Test implementations are correct and comprehensive.

The test assertions correctly validate:

  • Enum values match their string representations
  • All members are string types (ensuring JSON serialization compatibility)
  • Member counts for core step/transformation types

The tests effectively verify the v1.0 enum contracts.

src/omnibase_core/mixins/__init__.py (1)

27-79: MixinComputeExecution import and export wiring looks correct

Importing MixinComputeExecution and exposing it via __all__ is consistent with how other mixins are surfaced here, so projects can now depend on it through the standard omnibase_core.mixins namespace.

src/omnibase_core/enums/enum_regex_flag.py (1)

10-22: EnumRegexFlag definition aligns well with regex transformation needs

The string-backed enum with IGNORECASE, MULTILINE, and DOTALL is straightforward and readable, and the docstring clearly ties it to the REGEX transformation behavior.

src/omnibase_core/enums/enum_case_mode.py (1)

10-22: EnumCaseMode is clear and consistent with case-conversion configs

Using human-readable values ("uppercase", "lowercase", "titlecase") for the string enum keeps contracts easy to read while remaining type-safe for ModelTransformCaseConfig.

src/omnibase_core/enums/enum_compute_step_type.py (1)

11-27: EnumComputeStepType cleanly encodes the v1.0 step surface

The three published members (VALIDATION, TRANSFORMATION, MAPPING) and the docstring notes about deferred CONDITIONAL/PARALLEL steps line up with the v1.0 contract design and keep the future roadmap visible in code.

src/omnibase_core/models/transformations/model_transform_trim_config.py (1)

15-27: Trim config model matches the transformation-config pattern

ModelTransformTrimConfig uses a clear discriminator, sensible default (EnumTrimMode.BOTH), and an immutable ConfigDict, consistent with the other v1.0 transformation configs and the Pydantic immutability guidance. Based on learnings, this fits the expected model pattern.

src/omnibase_core/models/transformations/model_validation_step_config.py (1)

13-30: LGTM! Clean and well-documented validation config model.

The model correctly implements the discriminated union pattern with proper immutability guarantees (frozen=True) and strict validation (extra="forbid"). The docstring helpfully clarifies that VALIDATION is a step type, not a transformation.

src/omnibase_core/models/transformations/model_transform_unicode_config.py (1)

15-27: LGTM! Properly configured Unicode normalization model.

The model follows the established transformation config pattern with appropriate defaults (NFC is the recommended normalization form) and immutability guarantees.

src/omnibase_core/enums/enum_transformation_type.py (1)

11-34: LGTM! Well-documented transformation type enum for v1.0.

The enum clearly defines the 6 supported transformation types with helpful comments indicating future expansion plans. The string-backed values and comprehensive docstrings make this easy to use.

docs/architecture/NODECOMPUTE_VERSIONING_ROADMAP.md (1)

1-993: Excellent roadmap documentation for NodeCompute versioning strategy.

This comprehensive document clearly articulates the "boring first, earned complexity" philosophy and provides detailed versioning guarantees. The breakdown of what's included in each version (v1.0-v1.3) and the explicit "NOT in 1.x" section help set clear expectations.

src/omnibase_core/models/transformations/types.py (1)

19-28: LGTM! Properly implemented discriminated union for transformation configs.

The union correctly excludes IDENTITY (which has no config) and uses Pydantic's discriminated union feature with the config_type field. This enables type-safe parsing and validation of transformation configurations.

tests/unit/utils/test_compute_pipeline.py (1)

1-573: Excellent comprehensive test coverage for NodeCompute v1.0.

The test suite thoroughly exercises all transformation types, error handling, pipeline execution, and path resolution. Tests are well-organized into logical classes with descriptive names and cover both success and failure scenarios.

src/omnibase_core/models/contracts/subcontracts/__init__.py (1)

37-38: LGTM! Clean addition of compute subcontract models to public API.

The imports and exports are properly organized with a clear section comment, maintaining alphabetical ordering and consistency with the existing package structure.

Also applies to: 115-117

src/omnibase_core/models/transformations/model_transform_regex_config.py (1)

15-31: LGTM! Well-designed regex transformation config.

The model correctly uses Field(default_factory=list) for the mutable default, provides sensible defaults (empty replacement for deletion), and maintains immutability with frozen=True. The integration with EnumRegexFlag provides type-safe flag handling.

src/omnibase_core/models/contracts/subcontracts/model_compute_subcontract.py (1)

1-51: LGTM overall!

The model correctly implements v1.0 subcontract semantics with proper immutability (frozen=True) and strict validation (extra="forbid"). The docstring clearly documents abort-on-first-failure semantics and all attributes. As per coding guidelines, the model follows Pydantic 2.11+ patterns.

src/omnibase_core/models/compute/model_compute_step_result.py (2)

46-51: Forward reference resolution pattern is correct.

The runtime import with model_rebuild() is the standard Pydantic approach for resolving forward references when TYPE_CHECKING is used. The noqa: E402 suppression is appropriate here.


36-43: Model structure looks good.

The model correctly uses frozen=True for immutability and extra="forbid" for strict validation. The v1.0 string-based error type aligns with the design decision documented in the specification.

src/omnibase_core/models/compute/__init__.py (1)

1-29: Clean package initialization.

The module correctly re-exports all compute models with a proper __all__ declaration. The docstring provides a helpful overview of the public API surface.

src/omnibase_core/models/transformations/model_mapping_config.py (1)

13-29: Model structure is correct.

The discriminator pattern with config_type: Literal["mapping"] enables proper union type resolution. The model follows Pydantic 2.11+ patterns with immutability enforced via frozen=True.

docs/architecture/CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md (1)

1-921: Comprehensive and well-structured specification.

The document provides excellent coverage of v1.0 scope, design principles, and implementation plan. The explicit deferral of features (caching, parallelism, conditionals) to later versions demonstrates good incremental design. The abort-on-first-failure semantics and immutability guarantees are clearly documented.

tests/unit/models/compute/test_compute_models.py (1)

62-174: LGTM - Good test coverage for compute models.

The tests comprehensively cover:

  • Minimal and full construction scenarios
  • Success and failure paths with appropriate field validation
  • Immutability enforcement for all models

The test logic correctly validates the model contracts defined in the relevant code snippets.

src/omnibase_core/enums/__init__.py (2)

23-25: LGTM - Clean enum imports for NodeCompute v1.0.

The new enum imports are correctly organized with appropriate domain comments. The alphabetical placement maintains consistency with the existing codebase structure.


339-346: LGTM - Proper public API exposure.

The __all__ exports correctly match the new imports and are logically grouped under the v1.0 domain comment.

src/omnibase_core/mixins/mixin_compute_execution.py (2)

87-144: Sync function called in async context may block event loop.

The execute_contract_pipeline method is marked async but calls the synchronous execute_compute_pipeline directly without using asyncio.to_thread(). This can block the event loop during pipeline execution.

For v1.0 with simple transformations this may be acceptable, but consider documenting this limitation or wrapping with asyncio.to_thread for true async compatibility.

+import asyncio
+
 async def execute_contract_pipeline(
     self,
     contract: ModelComputeSubcontract,
     input_data: Any,
     correlation_id: "UUID | None" = None,
 ) -> ModelComputePipelineResult:
     # ... docstring ...
     context = ModelComputeExecutionContext(
         operation_id=uuid4(),
         correlation_id=correlation_id,
         node_id=str(self.node_id) if hasattr(self, 'node_id') else None,
     )
 
-    result = execute_compute_pipeline(contract, input_data, context)
+    # Use to_thread to avoid blocking the event loop
+    result = await asyncio.to_thread(
+        execute_compute_pipeline, contract, input_data, context
+    )
 
     return result

183-202: LGTM - Solid static validation logic.

The validation correctly detects:

  1. Duplicate step names using set comparison
  2. Forward references in mapping paths by tracking executed steps

The validation scope is appropriate for v1.0. Additional checks (empty step names, path syntax validation) could be added in future versions.

tests/integration/test_compute_pipeline_integration.py (1)

62-610: LGTM - Comprehensive integration test coverage.

Excellent coverage of pipeline execution scenarios including:

  • Multi-step transformations with chaining
  • Abort-on-first-failure error semantics
  • Mapping with cross-step references
  • Disabled step handling
  • Performance baselines with @pytest.mark.slow
  • Timing verification

The tests effectively validate the v1.0 contract-driven pipeline behavior.

src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py (2)

20-62: LGTM - Well-designed pipeline step model.

The model correctly implements v1.0 requirements:

  • Clear field documentation with step type requirements
  • Appropriate use of optional fields for type-specific configs
  • frozen=True ensures immutability as per coding guidelines
  • extra="forbid" prevents unrecognized fields

The docstring accurately describes the configuration requirements for each step type.


63-90: LGTM - Robust step configuration validation.

The validator correctly enforces the v1.0 contract:

  1. TRANSFORMATION requires transformation_type
  2. Non-IDENTITY transformations require transformation_config
  3. IDENTITY transformations must NOT have transformation_config (key design decision)
  4. MAPPING requires mapping_config
  5. VALIDATION requires validation_config

The validation will fail fast at model construction time, preventing invalid pipeline configurations from reaching runtime.

src/omnibase_core/models/compute/model_compute_pipeline_result.py (1)

53-123: Pipeline result model looks consistent and thread‑safe

The structure, field types, and frozen model_config align with the v1.0 executor behavior and step result model; the forward‑ref wiring via model_rebuild() is also correct for Pydantic 2.

src/omnibase_core/utils/compute_executor.py (5)

75-121: Error type extraction is reasonable for v1.0 string error_type

_get_error_type returning the underlying error_code.value (or "transformation_error" when absent) gives stable, debuggable identifiers for both step and pipeline error_type fields, and fits the “string only in v1.0” contract.


141-211: Mapping path resolver matches v1.0 scope but is intentionally strict

The resolver correctly enforces $‑prefixed paths, supports $.input.* and $.steps.<name>.output, and fails fast with ModelOnexError on invalid prefixes, missing keys, or private attributes. This matches the documented v1.0 mapping semantics and is appropriately defensive.


214-257: Mapping step execution is clear and defers all resolution errors to the pipeline

The mapping step handler validates mapping_config presence and then delegates each field to resolve_mapping_path, letting any ModelOnexError bubble to the main executor so failures are attributed to the correct step. This keeps the logic small and predictable.


260-315: Validation step’s v1.0 pass‑through behavior is well‑scoped

Requiring validation_config and logging a warning while returning the data unchanged makes the v1.0 “no real validation yet” behavior explicit without surprising callers; the TODO notes for v1.1 schema validation are clear.


379-539: Pipeline executor correctly implements abort‑on‑first‑failure semantics

The executor:

  • Skips disabled steps,
  • Measures per‑step and total durations,
  • Records a ModelComputeStepResult for every executed step (success or failure),
  • Aborts immediately on the first ModelOnexError or unexpected Exception,
  • Returns a ModelComputePipelineResult whose contents match the model’s docstring.

Catching generic Exception and converting it into an "unexpected_error" result rather than re‑raising also aligns with the goal of returning structured failures from pure compute utilities.

src/omnibase_core/utils/compute_transformations.py (2)

102-389: Transformation implementations and registry wiring look solid

  • Each string‑based transform (regex, case, trim, unicode) validates input type and raises ModelOnexError with appropriate EnumCoreErrorCode.
  • Regex flags mapping is correct for IGNORECASE, MULTILINE, and DOTALL, and invalid patterns are wrapped as OPERATION_FAILED.
  • transform_json_path gives a clear, documented v1.0 subset (dot‑notation only) with good error messages and private‑attribute blocking.
  • TRANSFORMATION_REGISTRY enumerates exactly the six v1.0 EnumTransformationType values and maps them to the correct handlers.

This module cleanly separates pure transformations from pipeline orchestration and matches the contract models shown in the PR.


392-453: execute_transformation dispatch and validation match the v1.0 contract

Special‑casing IDENTITY, validating that a handler exists for the given EnumTransformationType, and requiring non‑None config for all non‑IDENTITY types is exactly what the v1.0 contract describes. Errors are surfaced via ModelOnexError with clear messages, keeping pipeline‑level error propagation straightforward.

src/omnibase_core/models/transformations/__init__.py (1)

1-40: Transformation config package exports are clean and consistent

The __init__ nicely centralizes all v1.0 transformation and step config models plus the discriminated union, with documentation that matches the actual imports and __all__. This will make downstream imports (executor, mixins, tests) straightforward.

Comment thread docs/architecture/CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md
Comment thread tests/unit/enums/test_compute_enums.py
Comment thread tests/unit/utils/test_compute_pipeline.py
Address all PR #115 review feedback to prepare for release:

Documentation:
- Update ModelValidationConfig → ModelValidationStepConfig in docs
- Add language specifiers to all code fences
- Remove obsolete NODECOMPUTE_FULL_DESIGN_V1X_TARGET.md

Model Validations:
- Add duration_ms >= 0 constraint on ModelComputeStepMetadata
- Add JSONPath validation (must start with '$')
- Add pipeline_timeout_ms > 0 validation when provided
- Add field_mappings non-empty validation

Test Improvements:
- Add @pytest.mark.unit to all unit test classes
- Add @pytest.mark.integration to integration test classes
- Use ValidationError instead of generic Exception for frozen model tests
- Add test_member_count for all enum test classes
- Add comprehensive ModelComputeSubcontract tests

Code Quality:
- Align transform_identity signature with other handlers
- Add TODO(v1.1) comments for future TransformationError
- Verify security checks for private attribute access
@claude

claude Bot commented Dec 7, 2025

Copy link
Copy Markdown

Code Review: Contract-Driven NodeCompute v1.0 [OMN-465]

Summary

This is an excellent, production-ready implementation that delivers a clean, well-architected foundation for contract-driven compute pipelines. The PR demonstrates strong adherence to ONEX principles and best practices.


✅ Strengths

1. Architecture & Design

  • Perfect alignment with ONEX principles: Pure functions, protocol-driven patterns, and zero-boilerplate approach
  • Smart v1.0 scoping: Deliberately minimal feature set avoids over-engineering while establishing solid foundation
  • Thread safety by design: All executor functions are pure and stateless - excellent for future concurrent execution
  • Immutability guarantees: frozen=True on all result models prevents mutation and supports v1.2 replay/observability
  • Clean separation of concerns: Transformations, executor, and mixin each have single, well-defined responsibilities

2. Code Quality

  • Exceptional documentation: Every module, function, and parameter has clear, comprehensive docstrings
  • Type safety: Proper use of discriminated unions (ModelTransformationConfig), explicit Any annotations with justifications
  • Error handling: Consistent use of ModelOnexError with proper error codes - no generic exceptions
  • Security: Private attribute blocking in path resolution (lines 167-171, 376-380 in compute_executor.py)
  • Configuration validation: model_validator ensures IDENTITY transformations cannot have config (lines 77-83 in model_compute_pipeline_step.py)

3. Testing

  • Comprehensive coverage: 2,078 lines of tests across 6 test files (unit + integration)
  • Test organization: Clean separation between unit tests (582 lines for pipeline logic) and integration tests (817 lines)
  • 95 unit tests covering all transformation types, error paths, and edge cases

4. Developer Experience

  • Excellent examples: 358-line YAML contract demonstrates all features with real-world use case
  • Clear versioning roadmap: Documentation outlines v1.0 → v1.1 → v1.2 evolution path
  • Zero custom code pattern: Developers inherit from NodeCompute without writing transformation logic

🔍 Detailed Review

Code Organization (37 files, +6,525/-0)

Enums (6 files): ✅ Clean, well-documented enumerations

  • EnumComputeStepType - VALIDATION, TRANSFORMATION, MAPPING
  • EnumTransformationType - 6 transformation types with clear naming
  • Supporting enums (case mode, regex flags, unicode forms, trim modes)

Models (16 files): ✅ Excellent Pydantic usage

  • Proper use of ConfigDict(extra="forbid", frozen=True) throughout
  • Discriminated unions with config_type literal fields
  • Model validators enforcing configuration rules

Execution Layer (3 files): ✅ Pure, testable, thread-safe

  • compute_transformations.py: 481 lines of pure transformation functions
  • compute_executor.py: 548 lines with abort-on-first-failure semantics
  • MixinComputeExecution: Clean async wrapper with contract validation

Documentation (3 files): ✅ Comprehensive and actionable

  • v1.0 specification (921 lines)
  • Versioning roadmap (993 lines)
  • Clear migration paths and examples

🎯 Architectural Compliance

✅ Adheres to CLAUDE.md Standards

  1. Protocol-Driven DI: ✅ Not applicable (no DI usage in pure utility functions)
  2. Structured Errors: ✅ Perfect - only ModelOnexError with EnumCoreErrorCode
  3. Type Checking: ✅ All models use Pydantic with strict validation
  4. Thread Safety: ✅ Documented and enforced - all functions are pure
  5. Immutability: ✅ All result models use frozen=True
  6. Zero Boilerplate: ✅ Developers write zero transformation code

✅ Follows ONEX Patterns

  • Pure functions: All transformations follow (data, config) → result signature
  • Transformation registry: Clean dispatch pattern without custom registration
  • Abort-on-first-failure: Proper pipeline semantics with error context
  • Typed boundaries: All public surfaces use Pydantic models

💡 Minor Observations (Not Blocking)

1. Path Resolution Duplication

The path resolution logic appears twice (compute_executor.py:100-211 and compute_transformations.py:310-389). Consider extracting to a shared utility in v1.1 to maintain DRY principle.

Impact: Low - code is identical and well-tested
Suggestion: Add a TODO comment or defer to v1.1 refactoring

2. Validation Step is Pass-Through

v1.0 validation steps log warnings but don't validate (compute_executor.py:306-311). This is documented and intentional for v1.0.

Impact: None - clearly documented limitation
Recommendation: Ensure the warning appears in logs during testing so users are aware

3. Error Type Strings vs Enums

v1.0 uses string error types instead of enums. Per the spec, this is intentional.

Impact: None - v1.1 migration path is documented
Recommendation: Keep as-is; the versioning roadmap handles this

4. Timeout Enforcement

pipeline_timeout_ms is declared but not enforced in v1.0 executor.

Impact: Low - sequential pipelines are typically fast
Recommendation: Add a TODO comment or file as a v1.1 follow-up issue


🧪 Testing Assessment

Test Coverage: ✅ Excellent

Unit Tests (1,261 lines across 5 files):

  • Enum tests: 133 lines
  • Model tests: 544 lines
  • Pipeline executor tests: 582 lines

Integration Tests (817 lines):

  • Full pipeline execution tests
  • Example contract validation
  • Error scenario coverage

Strengths:

  • Tests are well-organized by concern
  • Comprehensive edge case coverage
  • Clear test names and documentation

Recommendation: Run poetry run pytest tests/ --cov=src/omnibase_core/utils/compute_executor.py --cov=src/omnibase_core/utils/compute_transformations.py --cov-report=term-missing to verify 90%+ coverage target


🔒 Security Review

✅ No security concerns identified

Positive findings:

  1. Private attribute blocking prevents access to internal state (compute_executor.py:167-171, 376-380)
  2. Path validation prevents malformed path attacks
  3. No dynamic code execution or eval usage
  4. Regex error handling prevents ReDoS attacks (try/except in transform_regex)

📊 Performance Considerations

✅ No performance issues expected

Positive patterns:

  • Pure functions enable easy parallelization in v1.2
  • Step result caching via immutable models
  • Early abort on failure reduces wasted computation
  • No database/network calls in executor (pure compute)

Future optimizations (deferred appropriately):

  • Parallel step execution (v1.2)
  • Pipeline result caching (v1.1)
  • Step-level timeouts (v1.1)

🎓 Recommendations for Next Steps

  1. Pre-merge: Ensure CI passes with all 95+ tests
  2. Pre-merge: Verify mypy strict mode shows 0 errors for new files
  3. Post-merge: File v1.1 issues for:
    • Schema validation implementation
    • Pipeline timeout enforcement
    • Path resolution DRY refactoring
  4. Documentation: Add v1.0 contract examples to docs/guides/node-building/03_COMPUTE_NODE_TUTORIAL.md

✅ Final Verdict

APPROVED - This PR is ready to merge pending CI checks.

Rationale:

  • Implements exactly what the v1.0 spec promises - no more, no less
  • Code quality exceeds project standards
  • Test coverage is comprehensive
  • Documentation is exemplary
  • No security, performance, or architectural concerns
  • Establishes clean foundation for v1.1/v1.2 evolution

Confidence Level: High - this is production-ready code.


📝 Nitpicks (Optional, Non-Blocking)

  1. Consider adding type stub (.pyi) files for compute_transformations.py if external projects will import these functions directly
  2. TRANSFORMATION_REGISTRY could use a TypedDict hint for better IDE support
  3. Example YAML contract could include a comment showing the expected input/output JSON structure

Great work on this foundation! 🎉 The disciplined scope, excellent documentation, and clean implementation make this a model PR for the ONEX framework.

Generated with Claude Code

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (5)
docs/architecture/NODECOMPUTE_VERSIONING_ROADMAP.md (2)

51-57: Consider rephrasing for improved readability (optional).

The repetition of "Boring" at the start of three consecutive sentences is flagged by style checkers. While this appears intentional for emphasis, consider slight variation for improved flow.


106-112: Add language specifiers to fenced code blocks (optional).

Per Markdown best practices, fenced code blocks should specify a language. For non-code content like version diagrams and text blocks, consider using text or plaintext.

Also applies to: 132-137, 927-931

tests/integration/test_compute_pipeline_integration.py (1)

520-562: Consider adding explicit timeout decorators to slow tests.

Per coding guidelines, tests should use @pytest.mark.timeout() to prevent hangs. While these tests have performance assertions, explicit timeouts would provide better protection in CI environments.

Example:

+@pytest.mark.timeout(5)
 @pytest.mark.slow
 def test_large_data_performance_baseline(self) -> None:

Based on learnings, adding timeouts prevents test hangs and improves CI reliability.

Also applies to: 564-610

src/omnibase_core/utils/compute_transformations.py (2)

310-390: Consider documenting the private attribute handling behavior.

The implementation correctly handles path traversal with good error messages. However, the private attribute blocking (line 376-380) only applies to object attributes, not dictionary keys. This means:

  • transform_json_path({"_private": "value"}, ...) → allowed
  • transform_json_path(obj_with_private_attr, ...) → blocked

This is a reasonable design decision (dict keys are not "private attributes"), but the distinction could be documented in the docstring for clarity.

Consider adding a note to the docstring:

     Raises:
         ModelOnexError: If the path cannot be resolved (key missing, attribute not found)
-            or if attempting to access private attributes (those starting with "_").
+            or if attempting to access private object attributes (those starting with "_").
+            Note: Dictionary keys starting with "_" are allowed, as they are not considered
+            private in the same way as object attributes.

404-465: Consider simplifying the IDENTITY special case.

The function special-cases IDENTITY (line 448-449) before using the registry, which means the registry entry for IDENTITY (line 395) is never used. This redundancy could be eliminated by:

Option 1: Remove the special case and adjust config validation
Option 2: Remove IDENTITY from the registry since it's always special-cased

The current approach works correctly and makes the "no config required" behavior explicit, but it creates a maintenance burden (IDENTITY appears in two places with different code paths).

If you prefer to keep the special case for clarity, consider adding a comment:

     if transformation_type == EnumTransformationType.IDENTITY:
+        # Special-cased to bypass config validation (IDENTITY requires config=None)
         return transform_identity(data, config=None)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8132d58 and 56e52a9.

📒 Files selected for processing (14)
  • docs/architecture/CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md (1 hunks)
  • docs/architecture/NODECOMPUTE_VERSIONING_ROADMAP.md (1 hunks)
  • examples/contracts/compute/user_profile_normalizer.yaml (1 hunks)
  • src/omnibase_core/models/compute/model_compute_step_metadata.py (1 hunks)
  • src/omnibase_core/models/contracts/subcontracts/model_compute_subcontract.py (1 hunks)
  • src/omnibase_core/models/transformations/model_mapping_config.py (1 hunks)
  • src/omnibase_core/models/transformations/model_transform_json_path_config.py (1 hunks)
  • src/omnibase_core/utils/compute_transformations.py (1 hunks)
  • tests/integration/test_compute_pipeline_integration.py (1 hunks)
  • tests/unit/enums/test_compute_enums.py (1 hunks)
  • tests/unit/models/compute/test_compute_models.py (1 hunks)
  • tests/unit/models/contracts/subcontracts/test_model_compute_subcontract.py (1 hunks)
  • tests/unit/models/transformations/test_transformation_configs.py (1 hunks)
  • tests/unit/utils/test_compute_pipeline.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • tests/unit/enums/test_compute_enums.py
  • docs/architecture/CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md
  • tests/unit/models/transformations/test_transformation_configs.py
  • tests/unit/models/compute/test_compute_models.py
  • src/omnibase_core/models/contracts/subcontracts/model_compute_subcontract.py
🧰 Additional context used
📓 Path-based instructions (4)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Always use Poetry for Python package management and task execution. Use poetry run for pytest, mypy, black, isort, and other tools. Never use pip directly or execute python commands without the poetry run prefix.
Enforce 100% strict mypy compliance. All functions must have complete type annotations. Use poetry run mypy src/omnibase_core/ to verify strict mode compliance with no errors.
Format code with black, sort imports with isort, and lint with ruff. Run poetry run black src/ tests/, poetry run isort src/ tests/, and poetry run ruff check --fix src/ tests/

Files:

  • tests/unit/models/contracts/subcontracts/test_model_compute_subcontract.py
  • tests/integration/test_compute_pipeline_integration.py
  • src/omnibase_core/models/transformations/model_mapping_config.py
  • tests/unit/utils/test_compute_pipeline.py
  • src/omnibase_core/models/transformations/model_transform_json_path_config.py
  • src/omnibase_core/models/compute/model_compute_step_metadata.py
  • src/omnibase_core/utils/compute_transformations.py
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Write tests using pytest with async support via pytest-asyncio. Maintain minimum 60% code coverage. Use pytest markers: @pytest.mark.unit, @pytest.mark.integration, @pytest.mark.slow
Add @pytest.mark.timeout() to prevent test hangs. Run tests with poetry run pytest tests/ --timeout=60 for 60-second timeout protection.

Files:

  • tests/unit/models/contracts/subcontracts/test_model_compute_subcontract.py
  • tests/integration/test_compute_pipeline_integration.py
  • tests/unit/utils/test_compute_pipeline.py
src/omnibase_core/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/omnibase_core/**/*.py: Use protocol names with container.get_service() for dependency injection, never resolve services by concrete class names. Example: container.get_service('ProtocolEventBus') instead of container.get_service('EventBusService')
Always use ModelONEXContainer for dependency injection in node constructors and service resolution. Never confuse it with ModelContainer[T], which is a generic value wrapper, not a DI container.
Use structured error handling with ModelOnexError and EnumCoreErrorCode, never raise generic Exception. Always chain exceptions with from e when catching and re-raising.
Use the @standard_error_handling decorator on methods to eliminate 6+ lines of try/catch boilerplate. Example: @standard_error_handling above async methods.
Respect thread safety constraints: Do NOT share node instances (NodeCompute, NodeEffect), cache, or circuit breaker instances across threads without synchronization. Use thread-local instances or locks.
Use duck typing with protocols. Do not use isinstance checks with protocol types. Rely on the protocol interface directly.
Use EnumNodeKind for high-level architectural classification (EFFECT, COMPUTE, REDUCER, ORCHESTRATOR) when routing data through the ONEX pipeline. Use EnumNodeType for specific implementation discovery and capability matching.
Use ModelEventEnvelope for inter-service event-driven communication. Process events through the envelope pattern for consistent event handling.

Files:

  • src/omnibase_core/models/transformations/model_mapping_config.py
  • src/omnibase_core/models/transformations/model_transform_json_path_config.py
  • src/omnibase_core/models/compute/model_compute_step_metadata.py
  • src/omnibase_core/utils/compute_transformations.py
src/omnibase_core/models/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Use Pydantic 2.11+ models for all data validation and serialization. Ensure models are immutable after creation for thread safety.

Files:

  • src/omnibase_core/models/transformations/model_mapping_config.py
  • src/omnibase_core/models/transformations/model_transform_json_path_config.py
  • src/omnibase_core/models/compute/model_compute_step_metadata.py
🧠 Learnings (3)
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to tests/**/*.py : Write tests using pytest with async support via pytest-asyncio. Maintain minimum 60% code coverage. Use pytest markers: pytest.mark.unit, pytest.mark.integration, pytest.mark.slow

Applied to files:

  • tests/unit/utils/test_compute_pipeline.py
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to tests/**/*.py : Add pytest.mark.timeout() to prevent test hangs. Run tests with `poetry run pytest tests/ --timeout=60` for 60-second timeout protection.

Applied to files:

  • tests/unit/utils/test_compute_pipeline.py
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to docs/guides/node-building/**/*.md : Node building guide is the critical starting point for developers and AI agents. Follow the sequence: What is a Node → Node Types → COMPUTE Tutorial → EFFECT Tutorial → REDUCER Tutorial → ORCHESTRATOR Tutorial.

Applied to files:

  • docs/architecture/NODECOMPUTE_VERSIONING_ROADMAP.md
🧬 Code graph analysis (2)
tests/unit/models/contracts/subcontracts/test_model_compute_subcontract.py (2)
src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py (1)
  • ModelComputePipelineStep (20-90)
src/omnibase_core/models/contracts/subcontracts/model_compute_subcontract.py (1)
  • ModelComputeSubcontract (16-51)
tests/integration/test_compute_pipeline_integration.py (4)
src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py (1)
  • ModelComputePipelineStep (20-90)
src/omnibase_core/models/contracts/subcontracts/model_compute_subcontract.py (1)
  • ModelComputeSubcontract (16-51)
src/omnibase_core/models/transformations/model_mapping_config.py (1)
  • ModelMappingConfig (13-37)
src/omnibase_core/utils/compute_executor.py (1)
  • execute_compute_pipeline (379-539)
🪛 LanguageTool
docs/architecture/NODECOMPUTE_VERSIONING_ROADMAP.md

[style] ~55-~55: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...itions. Boring code is debuggable code. Boring APIs are learnable APIs. Stable: O...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

🪛 markdownlint-cli2 (0.18.1)
docs/architecture/NODECOMPUTE_VERSIONING_ROADMAP.md

106-106: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


132-132: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


927-927: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: claude-review
  • GitHub Check: Smoke Tests
🔇 Additional comments (15)
src/omnibase_core/models/compute/model_compute_step_metadata.py (1)

14-26: LGTM! Clean and well-structured metadata model.

The implementation correctly enforces immutability and non-negative duration constraints, aligning with the v1.0 design principles from the PR objectives.

src/omnibase_core/models/transformations/model_mapping_config.py (1)

13-37: LGTM! Well-designed mapping configuration model.

The model correctly implements:

  • Discriminated union pattern with config_type
  • Non-empty validation for field_mappings
  • Immutability via frozen=True
  • Clear documentation of path expression syntax
tests/unit/utils/test_compute_pipeline.py (1)

60-582: LGTM! Comprehensive unit test coverage.

The test suite thoroughly validates all transformation types, the dispatch mechanism, path resolution, and pipeline execution semantics. All test classes are properly marked with @pytest.mark.unit per coding guidelines.

tests/unit/models/contracts/subcontracts/test_model_compute_subcontract.py (1)

16-156: LGTM! Thorough validation test coverage.

The test suite comprehensively validates:

  • Minimal and full contract creation
  • Timeout constraint enforcement (None, positive, zero, negative edge cases)
  • Immutability guarantees
  • Extra field rejection

All tests properly use @pytest.mark.unit per coding guidelines.

src/omnibase_core/models/transformations/model_transform_json_path_config.py (1)

13-35: LGTM! Correct JSONPath configuration implementation.

The model properly validates JSONPath syntax requirements:

  • Non-empty path
  • Must start with "$" (JSONPath root)
  • Immutable via frozen=True
  • Follows discriminated union pattern
examples/contracts/compute/user_profile_normalizer.yaml (1)

1-358: LGTM! Exemplary documentation and contract example.

This is an outstanding example contract that:

  • Demonstrates all 3 step types (VALIDATION, TRANSFORMATION, MAPPING)
  • Shows 5 of 6 transformation types in realistic scenarios
  • Includes detailed inline documentation explaining each step
  • Provides concrete input/output examples
  • Shows proper path resolution patterns
  • Demonstrates the sequential execution model with abort-on-first-failure

This will serve as an excellent reference for developers implementing NodeCompute contracts.

tests/integration/test_compute_pipeline_integration.py (1)

52-814: LGTM! Excellent integration test coverage.

The test suite comprehensively validates:

  • Multi-step pipeline execution and chaining
  • Abort-on-first-failure semantics with error propagation
  • Complex mapping scenarios referencing multiple prior steps
  • Disabled step handling
  • Regex flags and unicode normalization integration
  • Performance baselines for large data and many steps
  • Error scenarios (invalid regex, missing paths, type mismatches)
  • Context propagation with operation_id and correlation_id

All test classes properly use @pytest.mark.integration per coding guidelines.

src/omnibase_core/utils/compute_transformations.py (8)

1-82: LGTM! Well-structured module with clear documentation.

The module structure is excellent:

  • Comprehensive docstring with thread safety guarantees
  • Well-documented type aliases for JSON structures and handler functions
  • Proper import organization (stdlib then project imports)
  • Helpful future planning comment about TransformationError

The decision to use Callable[..., Any] for TransformationHandler appropriately balances type safety with flexibility for handlers with varying signatures.


84-111: LGTM! Clean identity transformation.

The intentional unused config parameter is well-justified in the docstring and inline comment for registry handler signature consistency.


114-167: LGTM! Robust regex transformation with proper error handling.

The implementation correctly:

  • Validates string input type
  • Maps enum flags to Python re flags (enum guarantees only valid values)
  • Chains exceptions with from e following coding guidelines
  • Uses structured error codes (VALIDATION_ERROR, OPERATION_FAILED)

169-216: LGTM! Clean case transformation with exhaustive mode handling.

Proper input validation and comprehensive mode coverage with appropriate error handling for unexpected cases.


218-266: LGTM! Clean trim transformation following consistent patterns.

Mirrors the case transformation structure with proper validation and mode handling.


268-308: LGTM! Unicode normalization with enum-guaranteed correctness.

The implementation correctly delegates form validation to the enum type system, trusting that EnumUnicodeForm.value provides valid Unicode normalization forms.


392-401: LGTM! Complete transformation registry.

The registry correctly maps all transformation types to their handlers with proper type annotations.


467-481: LGTM! Complete and well-organized public API exports.

The __all__ list properly exposes type aliases, transformation functions, and the registry with clear section comments.

- Add TODO(v1.1) comments for deferred features:
  - Path resolution duplication (extract to shared utility)
  - Pipeline timeout enforcement (currently declared but not enforced)
  - TransformationError custom exception consideration
- Align transform_identity signature with registry pattern (Any = None)
- Fix markdown formatting (MD031/MD032 blank line issues)

All 993+ tests pass, mypy --strict clean.
@claude

claude Bot commented Dec 7, 2025

Copy link
Copy Markdown

Code Review: Contract-Driven NodeCompute v1.0 [OMN-465]

Overview

This is an excellent, well-architected implementation of the v1.0 contract-driven NodeCompute specification. The PR delivers exactly what it promises: a minimal, stable foundation for declarative compute pipelines with sequential execution, abort-on-first-failure semantics, and 6 built-in transformations.

Summary: ✅ APPROVED with minor recommendations for future iterations.


Strengths

1. Architecture & Design Excellence ⭐

  • Scope Discipline: Clear v1.0 boundaries with explicit roadmap (v1.1 for caching, v1.2 for parallelism)
  • Pure Functions: All transformation and execution logic is stateless and side-effect-free
  • Thread Safety: Explicit documentation and frozen=True on all result models
  • Type Safety: Discriminated unions with Pydantic for ModelTransformationConfig
  • Progressive Complexity: Ships boring first, complexity deferred to later versions

2. Code Quality ⭐

  • Documentation: Outstanding - every module has comprehensive docstrings with thread safety notes, examples, and cross-references
  • Validation: Strong model validators (e.g., validate_step_config in ModelComputePipelineStep)
  • Error Handling: Consistent use of ModelOnexError with appropriate error codes
  • Naming: Clear, self-documenting names (execute_compute_pipeline, ModelComputeStepResult)
  • Immutability: All result models use frozen=True for future-proofing

3. Testing ⭐

  • 95 unit tests covering all transformation types and execution paths
  • Integration tests for end-to-end pipeline validation
  • Test organization follows project conventions (tests/unit/, tests/integration/)
  • Good use of pytest markers (@pytest.mark.unit)

4. ONEX Compliance ⭐

  • Poetry-only: No pip usage (critical for ONEX standards)
  • Protocol-driven: Uses structured error models, not generic exceptions
  • Base class patterns: Mixin design allows composition with NodeCompute
  • Documentation standards: Follows CLAUDE.md conventions

Issues & Recommendations

Critical Issues: None ✅

No blocking issues found. The implementation is production-ready for v1.0 scope.

Minor Issues & Suggestions

1. TODO Comments - Schema Validation Not Implemented

Location: src/omnibase_core/utils/compute_executor.py:303

# TODO(v1.1): Implement actual schema validation against schema_ref
def execute_validation_step(
    data: Any,
    config: ModelValidationStepConfig,
    context: ModelComputeExecutionContext,
) -> Any:
    """v1.0: Validation steps are pass-through."""
    return data

Concern: The VALIDATION step type is currently a no-op pass-through. This means:

  • Contracts declaring validation_config with fail_on_error: true won't actually validate
  • Users might assume validation is working when it's not

Recommendation:

  • Option A (Preferred): Implement basic schema validation in v1.0 using Pydantic or jsonschema
  • Option B: Document this limitation prominently in:
    • CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md
    • Example contract comments
    • Function docstrings
  • Rationale: VALIDATION is one of only 3 step types in v1.0. Having it be a no-op undermines the "minimal but stable" promise.

Impact: Medium - Could cause confusion in production use


2. Pipeline Timeout Not Enforced

Location: src/omnibase_core/utils/compute_executor.py:382

# TODO(v1.1): Enforce pipeline_timeout_ms - currently declared in contract but not enforced.

Concern:

  • pipeline_timeout_ms is declared in ModelComputeSubcontract
  • Example contract uses pipeline_timeout_ms: 5000
  • But timeouts are never checked during execution

Recommendation:

  • Option A: Implement timeout enforcement in v1.0 (simple time.time() check per step)
  • Option B: Remove pipeline_timeout_ms from v1.0 spec entirely, add in v1.1
  • Rationale: Declaring a config option that does nothing violates least-surprise principle

Impact: Low-Medium - Timeout is listed in v1.0 scope table but not implemented


3. Path Resolution Duplication

Location: src/omnibase_core/utils/compute_executor.py:100

# TODO(v1.1): Extract path resolution to shared utility - duplicated in compute_transformations.py

Observation: Path resolution logic appears in both compute_executor.py and compute_transformations.py

Recommendation:

  • Extract to src/omnibase_core/utils/path_resolution.py before v1.0 ships
  • Benefits:
    • Single source of truth for path grammar
    • Easier to extend in v1.2 (when full JSONPath support arrives)
    • Better testability

Impact: Low - Tech debt but doesn't affect functionality


4. Transformation Error Handling

Location: src/omnibase_core/utils/compute_transformations.py:76

# TODO(v1.1): Create TransformationError for more specific error handling.

Observation: All transformation errors use generic ModelOnexError

Assessment: This is fine for v1.0. The TODO comment is good documentation.

Recommendation: Keep as-is, but ensure error messages are clear and actionable.


Performance Considerations

✅ No concerns for v1.0:

  • Sequential execution has predictable performance
  • Pure functions enable easy optimization later
  • No global state or locks to cause contention
  • frozen=True models prevent defensive copying overhead

Future (v1.2+): When adding parallelism, consider:

  • Thread pool sizing strategy
  • Backpressure for large pipelines
  • Memory usage for large step_results dicts

Security Review

✅ No security concerns found:

  • No command injection vectors (all transformations are pure functions)
  • No SQL injection (no database access)
  • No XSS vectors (transformations operate on data, not rendering)
  • Regex patterns validated at model level (Pydantic will catch invalid patterns)
  • extra="forbid" on all models prevents injection attacks via unknown fields

Note: Regex DoS protection is implicit (Python's re module has built-in catastrophic backtracking prevention since Python 3.11)


Test Coverage Assessment

Current: 95 unit tests + integration tests

Coverage gaps (not blocking, but worth tracking):

  1. Error recovery paths: What happens when:

    • transformation_config is malformed JSON
    • Step names contain special characters
    • Circular references in path expressions (e.g., step A → step B → step A)
  2. Edge cases:

    • Empty pipeline (0 steps)
    • All steps disabled (enabled: false)
    • Very large step_results dict (1000+ steps)
  3. Thread safety: Tests don't verify concurrent execution (though code is designed for it)

Recommendation: Add these as test cases in v1.1 cleanup sprint.


Documentation Quality ⭐⭐⭐

Outstanding work on documentation:

Architecture Docs

  • ✅ CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md: Comprehensive specification with examples
  • ✅ NODECOMPUTE_VERSIONING_ROADMAP.md: Clear evolution path
  • ✅ Example contract with inline comments (user_profile_normalizer.yaml)

Code Documentation

  • ✅ Every module has detailed docstrings
  • ✅ Thread safety notes in every file
  • ✅ See Also sections for discoverability
  • ✅ Type hints with Any annotations explaining polymorphism

Minor suggestion: Add a migration guide for existing NodeCompute users (code-driven → contract-driven).


Alignment with ONEX Standards

Standard Status Notes
Poetry-only ✅ Pass No pip usage detected
Type Safety ✅ Pass Discriminated unions, proper Pydantic models
Error Handling ✅ Pass Uses ModelOnexError consistently
Immutability ✅ Pass All result models frozen=True
Thread Safety ✅ Pass Explicit documentation, pure functions
Documentation ✅ Pass Outstanding quality
Testing ✅ Pass 95 tests, good coverage
No Generic Exception ✅ Pass No raise Exception() found

File-by-File Review

Enums (6 files) ✅

  • Clean, well-documented
  • String enums for JSON compatibility
  • Clear future version comments

Models (16 files) ✅

  • extra="forbid" on all models ✅
  • frozen=True on result models ✅
  • Strong validators (@model_validator) ✅
  • Discriminated unions properly typed ✅

Execution (3 files) ✅

  • compute_transformations.py: Pure functions, excellent documentation
  • compute_executor.py: Sequential execution, clear error handling
  • MixinComputeExecution: Clean async wrapper

Tests (5 files) ✅

  • Good coverage of success and error paths
  • Clear test names
  • Proper use of pytest markers

CI/CD Status

Observation: PR description shows:

  • mypy --strict passes (0 errors in 25 source files) ✅
  • 95 unit tests pass covering all components ✅
  • CI pipeline passes - marked as incomplete ☐

Recommendation: Wait for CI to pass before merge. Given the PR adds 6,542 lines, ensure:

  • All 20 test splits complete successfully
  • Test runtime per split stays under 4 minutes (per CLAUDE.md CI benchmarks)
  • No type checking regressions

Final Recommendation

Verdict: ✅ APPROVE (with minor follow-ups)

This is excellent work that demonstrates:

  • Strong architectural thinking (clear v1.0 scope)
  • High code quality (pure functions, immutability, type safety)
  • Outstanding documentation
  • ONEX compliance

Pre-Merge Checklist

  • CI pipeline passes (all 20 splits)
  • Address TODO items:
    • Implement schema validation OR document as limitation
    • Implement timeout enforcement OR remove from v1.0
    • Extract path resolution to shared utility (optional)

Post-Merge Follow-Ups (v1.1)

  1. Implement actual schema validation
  2. Implement pipeline timeout enforcement
  3. Add migration guide (code-driven → contract-driven)
  4. Add test coverage for edge cases (empty pipeline, all disabled, etc.)
  5. Consider performance benchmarks for large pipelines

Summary

This PR successfully delivers the v1.0 contract-driven NodeCompute specification with:

  • 6,542 additions across 37 files
  • 0 deletions (pure addition, no breaking changes)
  • 95 unit tests with integration tests
  • Clean architecture with clear evolution path

The implementation is production-ready for the defined v1.0 scope. The minor issues identified are primarily about ensuring declared features work as expected (validation, timeouts) rather than fundamental design flaws.

Great work, @jonahgabriel! 🎉


Reviewed by: Claude Code (Sonnet 4.5)
Review Date: 2025-12-07

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (7)
src/omnibase_core/utils/compute_executor.py (4)

75-97: Default "transformation_error" label may be too specific for generic ModelOnexError cases

_get_error_type (Line 75) uses "transformation_error" as the fallback when error.error_code is None. Since this helper is used at the pipeline level (Line 478 and Line 501) for any ModelOnexError, not just transformation failures, this label might be slightly misleading if a future caller raises a ModelOnexError without an error_code from non-transformation paths.

Consider using a more generic fallback (e.g. "unknown_error" or error.__class__.__name__) to avoid over-constraining semantics for future callers, or at least documenting that a None error_code is interpreted as a transformation failure.


103-214: Path resolution semantics are clear and guarded; behavior for $.steps.<name> vs $.steps.<name>.output is slightly asymmetric

resolve_mapping_path (Lines 103-214) is well-structured: it strictly enforces a leading $, blocks private attribute access (Line 170), and distinguishes validation vs operation errors cleanly.

One nuance: $.steps.<step_name> (with no .output) returns result.output (Lines 198-200), while $.steps.<step_name>.output is the only explicitly documented form (Lines 19-24 and 118-123), and more complex suffixes like $.steps.<step_name>.output.field are rejected (Lines 202-209). That’s perfectly fine for v1.0, but it’s worth:

  • Documenting this convenience behavior for bare $.steps.<step_name> if you intend to keep it, or
  • Disallowing it in v1.x to keep the surface area minimal until nested step-output paths are supported.

Either option is small and non-blocking, but clarifying it will make contract authors’ expectations more predictable.


263-317: Validation pass-through warning may be noisy at scale

execute_validation_step logs a warning every time a validation step runs (Lines 309-314), even though v1.0 intentionally treats validation as pass-through. In a high-throughput environment, this could spam logs for entirely expected behavior.

Consider either:

  • Downgrading this to logger.info or logger.debug, or
  • Guarding with a feature flag / configuration so you can enable it only during rollout or debugging.

The strict requirement that validation_config is present (Lines 297-301) is good and should remain.


385-545: Pipeline executor logic is solid; consider wiring context and unexpected-error observability

The main pipeline loop in execute_compute_pipeline (Lines 441-537) cleanly enforces:

  • Skip disabled steps (Lines 441-443),
  • Abort-on-first-failure with structured ModelOnexError handling (Lines 473-505),
  • A last-resort catch for unexpected exceptions (Lines 506-535),
  • Per-step and total timing via ModelComputeStepMetadata and processing_time_ms.

A couple of small, non-blocking refinements to consider:

  • context is currently unused in this function. If ModelComputePipelineResult does not already carry operation_id / correlation_id, consider adding them or at least using context in structured logging around failures so callers can tie pipelines back to the broader ONEX traces.
  • For the generic except Exception block (Lines 506-535), you currently only capture str(e). If you have a centralized logging layer, emitting the stack trace there (with the same operation_id) would improve debuggability while still returning a safe "unexpected_error" to callers.

Functionally, the executor looks correct and aligns with the v1.0 design.

src/omnibase_core/utils/compute_transformations.py (3)

115-267: String transformation functions are consistent; consider DRY-ing the input-type validation

transform_regex, transform_case, and transform_trim (Lines 115-267) all:

  • Enforce str input with ModelOnexError + EnumCoreErrorCode.VALIDATION_ERROR, and
  • Raise OPERATION_FAILED on configuration issues (invalid regex, unknown modes).

This is correct and matches the error-handling guidelines. The only minor downside is the repeated if not isinstance(data, str) pattern and near-identical error messages.

If you find these functions growing further, consider a tiny internal helper like:

+def _ensure_str_input(name: str, data: Any) -> str:
+    if not isinstance(data, str):
+        raise ModelOnexError(
+            error_code=EnumCoreErrorCode.VALIDATION_ERROR,
+            message=f"{name} transformation requires string input, got {type(data).__name__}",
+        )
+    return data

and then use _ensure_str_input("REGEX", data), _ensure_str_input("CASE_CONVERSION", data), etc., to reduce repetition while keeping the error messages explicit. Purely a readability/maintenance win; current code is functionally fine.


269-309: Minor doc example nit in transform_unicode

transform_unicode (Lines 269-309) correctly delegates to unicodedata.normalize(config.form.value, data) after validating string input, which is the right approach.

The example in the docstring (Lines 295-300) shows:

transform_unicode("cafe\\u0301", config) → 'cafe' # Single precomposed character

The normalized result would still contain the accented character (precomposed 'é'), so the string literal in the comment should reflect that accent. This is just a documentation typo and doesn’t affect behavior, but updating it will prevent confusion for anyone copy/pasting the example.


311-402: JSON path logic is solid; good candidate to share with resolve_mapping_path in v1.1

transform_json_path (Lines 311-390) implements simple, well-bounded path traversal:

  • Handles optional $ prefix (Lines 351-359),
  • Traverses dicts and attributes, blocking private attributes (Lines 369-381),
  • Raises ModelOnexError with clear messages for missing keys/attributes (Lines 371-374 and 385-388).

This behavior is nearly parallel to the mapping-path logic in resolve_mapping_path from compute_executor.py, which you’ve already flagged with a TODO for v1.1. When you get to that, this function is a good reference point:

  • Extract a shared internal _resolve_path(data: Any, path: str, source_label: str) utility that both JSON_PATH and mapping resolution can call.
  • Keep the error messages differentiated via source_label (e.g. “in input” vs “in step ''”) while using shared traversal rules, especially around private attribute blocking.

No changes are needed for v1.0; just reinforcing that the eventual refactor will reduce duplication and drift risk.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 56e52a9 and 253f4ce.

📒 Files selected for processing (3)
  • docs/architecture/CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md (1 hunks)
  • src/omnibase_core/utils/compute_executor.py (1 hunks)
  • src/omnibase_core/utils/compute_transformations.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Always use Poetry for Python package management and task execution. Use poetry run for pytest, mypy, black, isort, and other tools. Never use pip directly or execute python commands without the poetry run prefix.
Enforce 100% strict mypy compliance. All functions must have complete type annotations. Use poetry run mypy src/omnibase_core/ to verify strict mode compliance with no errors.
Format code with black, sort imports with isort, and lint with ruff. Run poetry run black src/ tests/, poetry run isort src/ tests/, and poetry run ruff check --fix src/ tests/

Files:

  • src/omnibase_core/utils/compute_transformations.py
  • src/omnibase_core/utils/compute_executor.py
src/omnibase_core/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/omnibase_core/**/*.py: Use protocol names with container.get_service() for dependency injection, never resolve services by concrete class names. Example: container.get_service('ProtocolEventBus') instead of container.get_service('EventBusService')
Always use ModelONEXContainer for dependency injection in node constructors and service resolution. Never confuse it with ModelContainer[T], which is a generic value wrapper, not a DI container.
Use structured error handling with ModelOnexError and EnumCoreErrorCode, never raise generic Exception. Always chain exceptions with from e when catching and re-raising.
Use the @standard_error_handling decorator on methods to eliminate 6+ lines of try/catch boilerplate. Example: @standard_error_handling above async methods.
Respect thread safety constraints: Do NOT share node instances (NodeCompute, NodeEffect), cache, or circuit breaker instances across threads without synchronization. Use thread-local instances or locks.
Use duck typing with protocols. Do not use isinstance checks with protocol types. Rely on the protocol interface directly.
Use EnumNodeKind for high-level architectural classification (EFFECT, COMPUTE, REDUCER, ORCHESTRATOR) when routing data through the ONEX pipeline. Use EnumNodeType for specific implementation discovery and capability matching.
Use ModelEventEnvelope for inter-service event-driven communication. Process events through the envelope pattern for consistent event handling.

Files:

  • src/omnibase_core/utils/compute_transformations.py
  • src/omnibase_core/utils/compute_executor.py
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/nodes/node_compute.py : NodeCompute is for data processing and transformation. Inherit from NodeCompute for COMPUTE nodes that perform calculations, validations, and data mapping.
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/nodes/node_compute.py : NodeCompute is for data processing and transformation. Inherit from NodeCompute for COMPUTE nodes that perform calculations, validations, and data mapping.

Applied to files:

  • src/omnibase_core/utils/compute_executor.py
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Smoke Tests
  • GitHub Check: claude-review
🔇 Additional comments (2)
docs/architecture/CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md (1)

1-930: Comprehensive specification document with past validation naming issue properly resolved.

This documentation is well-structured and technically accurate. The v1.0 scope is clearly delineated from future versions, models and enums are thoroughly documented with code examples, and the example contract effectively demonstrates all step types and configuration patterns. The past issue flagging ModelValidationConfig vs. ModelValidationStepConfig (addressed in commit 56e52a9) has been properly resolved—line 141 and the ModelValidationStepConfig section (lines 433–452) now use the correct terminology consistently.

A few observations:

  1. Lines 518–539 and 579–592 (pseudocode sections): These reference ModelOnexError in transformation execution and path resolution contexts. Verify that this error class exists in the actual implementation and is the intended type for contract validation failures and runtime errors.

  2. Lines 598–609 and 155–156 (IDENTITY handling): The requirement that IDENTITY transformation must not have a config is clearly stated in both the spec and the validator logic. This is good—the constraint is reinforced in both places.

  3. Lines 703–729 (schema resolution): The alias feature for input_schema and output_schema within validation steps is useful, though the current description could clarify whether these aliases are case-sensitive and whether unrecognized aliases fail validation at load time or runtime.

Verification task: Please confirm that ModelOnexError is defined in the actual implementation and serves as the error type for transformation and path resolution failures. If it's a placeholder, consider aligning with the final error taxonomy.

src/omnibase_core/utils/compute_transformations.py (1)

393-467: Transformation registry and dispatcher look correct and future-proof

The TRANSFORMATION_REGISTRY and execute_transformation (Lines 393-467) cleanly map EnumTransformationType values to handlers and centralize dispatch:

  • All six v1.0 types are present in the registry (IDENTITY, REGEX, CASE_CONVERSION, TRIM, NORMALIZE_UNICODE, JSON_PATH) (Lines 395-402).
  • IDENTITY is correctly treated as a special case where config is optional and ignored (Lines 457-458).
  • All other transformations enforce config is not None and raise a VALIDATION_ERROR otherwise (Lines 460-464).
  • Unknown transformation types are rejected with OPERATION_FAILED (Lines 449-454).

This matches the contract-driven design and should integrate cleanly with the executor. No changes needed here.

## Critical Fixes
- Documentation already uses ModelValidationStepConfig correctly

## Major Fixes
- Added @pytest.mark.unit to 28 test classes across 5 files
- Fixed UUID import pattern in mixin_compute_execution.py
- Changed error label from "transformation_error" to "compute_error"
- Created ComputePipelineError custom exception with 12 new tests
- Added TODO comments with version targets (v1.1)
- Added pipeline_timeout_ms upper bound (1 hour max)
- Added 18 new integration tests (36 total)

## Minor Fixes
- Added comprehensive docstrings to 8 compute module files
- Added language specifiers to markdown code blocks

## Nitpick Fixes
- Created conftest.py with 14 shared test fixtures
- Added timeout decorators to 23 test classes
- Aligned transform_identity signature with other handlers
- Documented path resolution behavior asymmetry
- Simplified IDENTITY transformation special case
- Changed logger.error with exc_info to logger.exception

Files Modified: 22 files changed, 1754 insertions(+), 127 deletions(-)
@claude

claude Bot commented Dec 7, 2025

Copy link
Copy Markdown

Code Review: Contract-Driven NodeCompute v1.0 [OMN-465]

Summary

This PR implements a solid foundation for contract-driven NodeCompute with sequential pipelines, 6 built-in transformations, and abort-on-first-failure semantics. The implementation demonstrates excellent adherence to omnibase_core conventions and includes comprehensive documentation and testing.


✅ Strengths

1. Architecture & Design

  • ✅ Strong separation of concerns: Pure transformation functions in compute_transformations.py, orchestration in compute_executor.py, async wrapper in MixinComputeExecution
  • ✅ Immutability guarantees: All result models use frozen=True, preventing mutation and enabling future parallelism
  • ✅ Thread-safe implementation: Pure, stateless functions throughout with explicit thread safety documentation
  • ✅ Clear v1.0 scope: Intentionally minimal feature set with deferred complexity (caching, parallelism, conditionals)

2. Type Safety & Validation

  • ✅ Discriminated unions: ModelTransformationConfig uses Field(discriminator="config_type") for type-safe config dispatch
  • ✅ extra="forbid" everywhere: Prevents typos and undocumented fields in contracts
  • ✅ Model validators: ModelComputePipelineStep.validate_step_config() enforces step-type-specific config requirements
  • ✅ Type annotations: Comprehensive Any annotations with explanatory comments (e.g., # Any: pipeline accepts dict, Pydantic model, or JSON-compatible data)

3. Error Handling

  • ✅ Structured errors: Uses ModelOnexError with EnumCoreErrorCode (not generic Exception)
  • ✅ Security: Blocks private attribute access (_ prefix) in path resolution (compute_executor.py:193-196)
  • ✅ Fail-fast: Schema validation at contract load time, not runtime
  • ✅ Abort-on-first-failure: Clear semantics with full error context preservation

4. Documentation

  • ✅ Comprehensive specs: 930-line v1.0 spec + 993-line versioning roadmap with clear rationale for deferred features
  • ✅ Excellent docstrings: Module-level docstrings explain thread safety, examples, and cross-references
  • ✅ TODOs with context: All TODOs reference version roadmap (e.g., # TODO(v1.1): Enforce pipeline_timeout_ms)
  • ✅ Example contracts: user_profile_normalizer.yaml demonstrates full pipeline usage

5. Testing

  • ✅ 95 unit tests covering all components (enums, models, transformations, executor, integration)
  • ✅ Test organization: Separate test classes per transformation type with descriptive test names
  • ✅ Edge case coverage: Tests for error conditions, type mismatches, invalid configs

⚠️ Issues Found

1. CI Failures ❌ CRITICAL

  • Code Quality check: FAILED
  • Documentation Validation check: FAILED
  • Action Required: Must investigate and fix CI failures before merge
  • Likely causes: mypy strict mode errors, missing __all__ exports, or doc validation issues

2. Code Duplication ⚠️ MEDIUM PRIORITY

Location: compute_executor.py:112-239 and compute_transformations.py:319-399

Both resolve_mapping_path() and transform_json_path() implement nearly identical path traversal logic:

  • Dot-notation path splitting
  • Dict key access vs object attribute access
  • Private attribute blocking (_ prefix)
  • Identical error messages

Already tracked: Line 109 TODO acknowledges this duplication

Recommendation: Extract to shared _resolve_path() utility in v1.1 to ensure consistent behavior and reduce maintenance burden.

3. IDENTITY Transformation Config Inconsistency ⚠️ LOW PRIORITY

Location: compute_transformations.py:84-121

The transform_identity() signature is (data: Any, config: None = None) but the registry call in execute_transformation() (line 466) explicitly passes None:

if transformation_type == EnumTransformationType.IDENTITY:
    return handler(data, None)  # Explicit None

This works but creates asymmetry with other handlers that receive their configs naturally through the dispatcher.

Recommendation: Consider removing the special case and allowing IDENTITY to receive config=None through normal dispatch flow. This would simplify execute_transformation() logic.

4. Unused Parameter Documentation ⚠️ LOW PRIORITY

Location: compute_transformations.py:119

The del config statement to mark the parameter as unused is good practice, but the docstring could be clearer:

# config parameter is intentionally unused - exists for registry uniformity
del config  # Explicitly mark as unused to satisfy linters

Suggestion: The docstring already explains this well (lines 97-108), but adding a note at the top of the function would improve clarity:

"""
Identity transformation - returns data unchanged.

Note: config parameter is unused (IDENTITY requires no config) but present
for uniform registry signature.
"""

5. Pipeline Timeout Not Enforced ⚠️ LOW PRIORITY

Location: compute_executor.py:406-408 and model_compute_subcontract.py:145

The contract declares pipeline_timeout_ms with validation (gt=0, le=3600000), but the executor doesn't enforce it:

# TODO(v1.1): Enforce pipeline_timeout_ms - currently declared in contract but not enforced.

Current State: This is intentionally deferred to v1.1 (documented in roadmap)

Recommendation: Consider adding a runtime warning if pipeline_timeout_ms is set, similar to the validation warning (line 334). This would remind users that the timeout is not yet enforced:

if contract.pipeline_timeout_ms:
    logger.warning(
        "pipeline_timeout_ms is set but not enforced in v1.0. "
        "Timeout enforcement will be added in v1.1."
    )

6. Missing Context in Error Messages ⚠️ LOW PRIORITY

Location: compute_executor.py:189, 203

Path resolution errors could include the input type for better debugging:

# Current
message=f"Path '{path}' not found: key '{part}' missing in input"

# Suggestion
message=f"Path '{path}' not found: key '{part}' missing in input (type: {type(input_data).__name__})"

This would help users understand whether they passed a dict, Pydantic model, or other type.


🔍 Code Quality Observations

Excellent Practices Followed

  1. ✅ Poetry usage: No pip commands anywhere
  2. ✅ No backwards-compatibility hacks: Clean implementation without technical debt
  3. ✅ Security: Private attribute blocking prevents introspection attacks
  4. ✅ Pydantic best practices: ConfigDict(extra="forbid", frozen=True) throughout
  5. ✅ No magic strings: All transformation types and step types use enums

Alignment with CLAUDE.md

  • ✅ Protocol-driven DI: Ready for container.get_service("ProtocolEventBus") pattern
  • ✅ Zero boilerplate: Contract-driven approach eliminates manual transformation code
  • ✅ Structured errors: Uses ModelOnexError exclusively
  • ✅ Comprehensive testing: 95 tests align with 12,000+ test suite culture
  • ✅ Thread safety: Explicitly documented and enforced

🎯 Recommendations

Before Merge (Required)

  1. ❌ Fix CI failures - Code Quality and Documentation Validation must pass
  2. ⚠️ Run mypy strict: poetry run mypy src/omnibase_core/
  3. ⚠️ Verify test coverage: poetry run pytest tests/ --cov=src/omnibase_core --cov-report=term-missing

Post-Merge Improvements (v1.1 Backlog)

  1. Extract shared path resolution - Tracked in TODO at line 109
  2. Implement timeout enforcement - Tracked in versioning roadmap
  3. Add schema validation - Tracked for v1.1 (lines 327-331)
  4. Replace string error types with enums - EnumComputeErrorType in v1.1

Optional Enhancements

  1. Add runtime warning for unenforcedfields
  2. Enrich error messages with type context
  3. Consider simplifying IDENTITY handler dispatch

📊 Metrics

Metric Value Target Status
Files Added 48 - ✅
Lines Added 8,707 - ✅
Test Files 8 - ✅
Test Cases 95 60+ ✅
Documentation 3 major docs - ✅
mypy Strict TBD 0 errors ⚠️
CI Status 2 failures All pass ❌

🚀 Conclusion

This is high-quality foundational work that demonstrates:

  • Deep understanding of omnibase_core architecture
  • Excellent separation of concerns
  • Strong type safety and error handling
  • Comprehensive documentation and testing

The v1.0 scope is appropriately minimal with clear upgrade paths. The implementation is production-ready pending CI fixes.

Recommendation: ✅ APPROVE after CI fixes

The architecture is sound, the code is clean, and the documentation is exemplary. Once the CI failures are resolved, this PR will be a strong foundation for future NodeCompute enhancements.


Next Steps

  1. Investigate Code Quality failure (likely mypy strict mode issues)
  2. Investigate Documentation Validation failure
  3. Run full test suite locally: poetry run pytest tests/ -x
  4. Verify poetry run mypy src/omnibase_core/ passes with 0 errors
  5. Re-request review after CI is green

Great work on this foundational implementation! 🎉

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (1)
tests/unit/errors/test_compute_pipeline_error.py (1)

12-206: Add @pytest.mark.unit to these test classes for consistency

These tests do a good job exercising ComputePipelineError creation, serialization, and import behavior. To keep test categorization consistent with other unit suites (and prior guidance on this repo), consider adding @pytest.mark.unit above TestComputePipelineError, TestComputePipelineErrorImport, and TestComputePipelineErrorInvariants in addition to the existing timeout marks.

🧹 Nitpick comments (12)
src/omnibase_core/models/model_compute_output.py (1)

53-101: Consider adding frozen=True for consistency with other compute models.

The docstring notes "If thread-safety is needed, treat instances as read-only after creation," but this isn't enforced. Per the coding guidelines, Pydantic 2.11+ models should be immutable after creation for thread safety.

Other compute models in this PR (e.g., ModelComputeStepResult, ModelComputePipelineResult) use ConfigDict(frozen=True). Consider adding:

+    model_config = ConfigDict(frozen=True)

If mutability is intentionally required, consider documenting the specific use case.

src/omnibase_core/utils/compute_transformations.py (1)

319-399: Consider consistent handling of underscore-prefixed keys in dicts.

The private attribute check (line 385) only applies to object attributes, not dict keys. Dict keys like _private are still accessible:

# This is blocked (object attribute):
data = SomeObject()  # has _private attribute
transform_json_path(data, config_with_path="_private")  # Error

# This is allowed (dict key):
data = {"_private": "secret"}
transform_json_path(data, config_with_path="_private")  # Returns "secret"

If this is intentional (dicts represent data, objects have real private state), consider adding a comment. If not, consider adding:

         if isinstance(current, dict):
+            if part.startswith("_"):
+                raise ModelOnexError(
+                    error_code=EnumCoreErrorCode.VALIDATION_ERROR,
+                    message=f"Cannot access private key: '{part}'",
+                )
             if part not in current:
tests/unit/models/contracts/subcontracts/test_model_compute_subcontract.py (3)

16-17: Missing @pytest.mark.timeout() decorator.

Per coding guidelines, test classes should have timeout markers to prevent test hangs. Consider adding @pytest.mark.timeout(30) to this test class.

 @pytest.mark.unit
+@pytest.mark.timeout(30)
 class TestModelComputeSubcontractCreation:

59-60: Missing @pytest.mark.timeout() decorator.

 @pytest.mark.unit
+@pytest.mark.timeout(30)
 class TestModelComputeSubcontractTimeoutValidation:

154-155: Missing @pytest.mark.timeout() decorator.

 @pytest.mark.unit
+@pytest.mark.timeout(30)
 class TestModelComputeSubcontractFrozen:
tests/integration/test_compute_pipeline_integration.py (3)

464-499: Tighten assertion in test_regex_with_flags

The assertion:

assert (
    "hello" not in result.output.lower()
    or result.output == "hi World, hi friend, hi there"
)

passes for any output that simply lacks "hello", even if the rest of the string is wrong. If you want to assert both full correctness and full replacement, consider changing this to require both conditions (or just the exact expected string), e.g.:

assert result.output == "hi World, hi friend, hi there"

or

assert "hello" not in result.output.lower()
assert result.output == "hi World, hi friend, hi there"

545-590: Performance thresholds in integration tests may be brittle

The assertions that processing_time_ms is below fixed limits (e.g., < 1000 ms for large strings, < 500 ms for many steps, < 1000 ms for large lists) encode hardware‑dependent expectations. On slower or heavily loaded CI hosts these could occasionally fail even when the implementation is fine. If you see flaky behavior, consider either relaxing these bounds or converting them to sanity checks (e.g., “less than 10s”) rather than tight performance targets.

Also applies to: 593-639, 677-708, 1677-1708


48-53: Consider sharing _create_context via a fixture

Several integration test classes define an identical _create_context helper. If you want to DRY this up and centralize any future tweaks to context construction, you could move it into a module‑level @pytest.fixture (e.g., compute_context) and inject it into tests instead. Not required, but it would slightly reduce duplication.

Also applies to: 645-650, 853-858, 972-977, 1206-1211, 1370-1375, 1507-1512

src/omnibase_core/mixins/mixin_compute_execution.py (2)

137-147: Avoid serializing node_id=None as the literal string "None"

In the execution context construction you currently do:

context = ModelComputeExecutionContext(
    operation_id=uuid4(),
    correlation_id=correlation_id,
    node_id=str(self.node_id) if hasattr(self, "node_id") else None,
)

If a mixing class sets self.node_id = None, this will produce "None" rather than None, which can be misleading in logs/metrics. A small tweak keeps semantics cleaner:

node_id_value = getattr(self, "node_id", None)
context = ModelComputeExecutionContext(
    operation_id=uuid4(),
    correlation_id=correlation_id,
    node_id=str(node_id_value) if node_id_value is not None else None,
)

186-205: Minor optimization/readability for duplicate step detection

The duplicate step check repeatedly calls step_names.count(name), which is O(n²). Pipelines are small so this isn’t a practical issue, but you could make it clearer and linear using a counter or set:

seen: set[str] = set()
dups: set[str] = set()
for name in step_names:
    if name in seen:
        dups.add(name)
    else:
        seen.add(name)
if dups:
    errors.append(f"Duplicate step names: {dups}")

Not required, but slightly easier to read and scales better if pipelines grow.

src/omnibase_core/utils/compute_executor.py (2)

112-239: Path resolver correctly implements v1.0 grammar; consider documenting $input alias

The resolver cleanly supports the documented v1.0 forms ($.input[...] and $.steps.<name>[.output]), distinguishes validation vs operation faults, and blocks private attribute access, which is good for safety and observability. One small nit: you also accept the $input alias, but it’s not mentioned under “Supported Path Formats”; either documenting this alias or dropping it for stricter grammar would avoid surprises for contract authors.


287-342: Validation-step pass-through behavior is clearly scoped for v1.0

The function enforces validation_config presence and clearly documents/logs the current pass-through behavior with a TODO for v1.1 schema validation, which aligns with the staged rollout described in the docs. If you see log noise in high-throughput scenarios, you could later gate or downgrade the warning, but it’s fine for v1.0.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 253f4ce and 8b7ea15.

📒 Files selected for processing (25)
  • docs/architecture/CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md (1 hunks)
  • docs/architecture/NODECOMPUTE_VERSIONING_ROADMAP.md (1 hunks)
  • src/omnibase_core/enums/enum_compute_step_type.py (1 hunks)
  • src/omnibase_core/errors/__init__.py (3 hunks)
  • src/omnibase_core/errors/exception_compute_pipeline_error.py (1 hunks)
  • src/omnibase_core/mixins/mixin_compute_execution.py (1 hunks)
  • src/omnibase_core/models/compute/__init__.py (1 hunks)
  • src/omnibase_core/models/compute/model_compute_step_metadata.py (1 hunks)
  • src/omnibase_core/models/compute/model_compute_step_result.py (1 hunks)
  • src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py (1 hunks)
  • src/omnibase_core/models/contracts/subcontracts/model_compute_subcontract.py (1 hunks)
  • src/omnibase_core/models/model_compute_input.py (2 hunks)
  • src/omnibase_core/models/model_compute_output.py (2 hunks)
  • src/omnibase_core/utils/compute_executor.py (1 hunks)
  • src/omnibase_core/utils/compute_transformations.py (1 hunks)
  • tests/integration/test_compute_pipeline_integration.py (1 hunks)
  • tests/unit/errors/test_compute_pipeline_error.py (1 hunks)
  • tests/unit/models/compute/conftest.py (1 hunks)
  • tests/unit/models/configuration/test_model_compute_cache_config.py (7 hunks)
  • tests/unit/models/contracts/subcontracts/test_model_compute_subcontract.py (1 hunks)
  • tests/unit/models/nodes/node_services/test_model_service_compute_health.py (4 hunks)
  • tests/unit/models/nodes/node_services/test_model_service_compute_integration.py (2 hunks)
  • tests/unit/models/nodes/node_services/test_model_service_compute_invocation.py (11 hunks)
  • tests/unit/models/nodes/node_services/test_model_service_compute_lifecycle.py (4 hunks)
  • tests/unit/utils/test_compute_pipeline.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/omnibase_core/enums/enum_compute_step_type.py
  • src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py
🧰 Additional context used
📓 Path-based instructions (5)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Always use Poetry for Python package management and task execution. Use poetry run for pytest, mypy, black, isort, and other tools. Never use pip directly or execute python commands without the poetry run prefix.
Enforce 100% strict mypy compliance. All functions must have complete type annotations. Use poetry run mypy src/omnibase_core/ to verify strict mode compliance with no errors.
Format code with black, sort imports with isort, and lint with ruff. Run poetry run black src/ tests/, poetry run isort src/ tests/, and poetry run ruff check --fix src/ tests/

Files:

  • tests/unit/models/nodes/node_services/test_model_service_compute_lifecycle.py
  • src/omnibase_core/utils/compute_executor.py
  • tests/unit/utils/test_compute_pipeline.py
  • src/omnibase_core/models/model_compute_input.py
  • tests/unit/models/nodes/node_services/test_model_service_compute_health.py
  • src/omnibase_core/errors/__init__.py
  • src/omnibase_core/models/model_compute_output.py
  • src/omnibase_core/errors/exception_compute_pipeline_error.py
  • tests/unit/errors/test_compute_pipeline_error.py
  • src/omnibase_core/models/contracts/subcontracts/model_compute_subcontract.py
  • src/omnibase_core/utils/compute_transformations.py
  • tests/integration/test_compute_pipeline_integration.py
  • tests/unit/models/compute/conftest.py
  • tests/unit/models/contracts/subcontracts/test_model_compute_subcontract.py
  • src/omnibase_core/mixins/mixin_compute_execution.py
  • src/omnibase_core/models/compute/__init__.py
  • src/omnibase_core/models/compute/model_compute_step_result.py
  • tests/unit/models/nodes/node_services/test_model_service_compute_integration.py
  • tests/unit/models/configuration/test_model_compute_cache_config.py
  • tests/unit/models/nodes/node_services/test_model_service_compute_invocation.py
  • src/omnibase_core/models/compute/model_compute_step_metadata.py
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Write tests using pytest with async support via pytest-asyncio. Maintain minimum 60% code coverage. Use pytest markers: @pytest.mark.unit, @pytest.mark.integration, @pytest.mark.slow
Add @pytest.mark.timeout() to prevent test hangs. Run tests with poetry run pytest tests/ --timeout=60 for 60-second timeout protection.

Files:

  • tests/unit/models/nodes/node_services/test_model_service_compute_lifecycle.py
  • tests/unit/utils/test_compute_pipeline.py
  • tests/unit/models/nodes/node_services/test_model_service_compute_health.py
  • tests/unit/errors/test_compute_pipeline_error.py
  • tests/integration/test_compute_pipeline_integration.py
  • tests/unit/models/compute/conftest.py
  • tests/unit/models/contracts/subcontracts/test_model_compute_subcontract.py
  • tests/unit/models/nodes/node_services/test_model_service_compute_integration.py
  • tests/unit/models/configuration/test_model_compute_cache_config.py
  • tests/unit/models/nodes/node_services/test_model_service_compute_invocation.py
src/omnibase_core/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/omnibase_core/**/*.py: Use protocol names with container.get_service() for dependency injection, never resolve services by concrete class names. Example: container.get_service('ProtocolEventBus') instead of container.get_service('EventBusService')
Always use ModelONEXContainer for dependency injection in node constructors and service resolution. Never confuse it with ModelContainer[T], which is a generic value wrapper, not a DI container.
Use structured error handling with ModelOnexError and EnumCoreErrorCode, never raise generic Exception. Always chain exceptions with from e when catching and re-raising.
Use the @standard_error_handling decorator on methods to eliminate 6+ lines of try/catch boilerplate. Example: @standard_error_handling above async methods.
Respect thread safety constraints: Do NOT share node instances (NodeCompute, NodeEffect), cache, or circuit breaker instances across threads without synchronization. Use thread-local instances or locks.
Use duck typing with protocols. Do not use isinstance checks with protocol types. Rely on the protocol interface directly.
Use EnumNodeKind for high-level architectural classification (EFFECT, COMPUTE, REDUCER, ORCHESTRATOR) when routing data through the ONEX pipeline. Use EnumNodeType for specific implementation discovery and capability matching.
Use ModelEventEnvelope for inter-service event-driven communication. Process events through the envelope pattern for consistent event handling.

Files:

  • src/omnibase_core/utils/compute_executor.py
  • src/omnibase_core/models/model_compute_input.py
  • src/omnibase_core/errors/__init__.py
  • src/omnibase_core/models/model_compute_output.py
  • src/omnibase_core/errors/exception_compute_pipeline_error.py
  • src/omnibase_core/models/contracts/subcontracts/model_compute_subcontract.py
  • src/omnibase_core/utils/compute_transformations.py
  • src/omnibase_core/mixins/mixin_compute_execution.py
  • src/omnibase_core/models/compute/__init__.py
  • src/omnibase_core/models/compute/model_compute_step_result.py
  • src/omnibase_core/models/compute/model_compute_step_metadata.py
src/omnibase_core/models/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Use Pydantic 2.11+ models for all data validation and serialization. Ensure models are immutable after creation for thread safety.

Files:

  • src/omnibase_core/models/model_compute_input.py
  • src/omnibase_core/models/model_compute_output.py
  • src/omnibase_core/models/contracts/subcontracts/model_compute_subcontract.py
  • src/omnibase_core/models/compute/__init__.py
  • src/omnibase_core/models/compute/model_compute_step_result.py
  • src/omnibase_core/models/compute/model_compute_step_metadata.py
src/omnibase_core/mixins/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Mixin classes should be composed into node classes for specific capabilities. Available mixins include: MixinDiscoveryResponder, MixinEventHandler, MixinEventListener, MixinNodeExecutor, MixinNodeLifecycle, MixinRequestResponseIntrospection, MixinWorkflowSupport.

Files:

  • src/omnibase_core/mixins/mixin_compute_execution.py
🧠 Learnings (7)
📓 Common learnings
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/nodes/node_compute.py : NodeCompute is for data processing and transformation. Inherit from NodeCompute for COMPUTE nodes that perform calculations, validations, and data mapping.
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to tests/**/*.py : Add pytest.mark.timeout() to prevent test hangs. Run tests with `poetry run pytest tests/ --timeout=60` for 60-second timeout protection.

Applied to files:

  • tests/unit/models/nodes/node_services/test_model_service_compute_lifecycle.py
  • tests/unit/utils/test_compute_pipeline.py
  • tests/unit/models/nodes/node_services/test_model_service_compute_health.py
  • tests/unit/models/nodes/node_services/test_model_service_compute_integration.py
  • tests/unit/models/nodes/node_services/test_model_service_compute_invocation.py
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to docs/guides/node-building/**/*.md : Node building guide is the critical starting point for developers and AI agents. Follow the sequence: What is a Node → Node Types → COMPUTE Tutorial → EFFECT Tutorial → REDUCER Tutorial → ORCHESTRATOR Tutorial.

Applied to files:

  • docs/architecture/NODECOMPUTE_VERSIONING_ROADMAP.md
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/nodes/node_compute.py : NodeCompute is for data processing and transformation. Inherit from NodeCompute for COMPUTE nodes that perform calculations, validations, and data mapping.

Applied to files:

  • src/omnibase_core/utils/compute_executor.py
  • src/omnibase_core/models/model_compute_input.py
  • src/omnibase_core/models/model_compute_output.py
  • src/omnibase_core/errors/exception_compute_pipeline_error.py
  • src/omnibase_core/mixins/mixin_compute_execution.py
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to tests/**/*.py : Write tests using pytest with async support via pytest-asyncio. Maintain minimum 60% code coverage. Use pytest markers: pytest.mark.unit, pytest.mark.integration, pytest.mark.slow

Applied to files:

  • tests/unit/utils/test_compute_pipeline.py
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/**/*.py : Use structured error handling with ModelOnexError and EnumCoreErrorCode, never raise generic Exception. Always chain exceptions with `from e` when catching and re-raising.

Applied to files:

  • src/omnibase_core/errors/__init__.py
  • src/omnibase_core/errors/exception_compute_pipeline_error.py
  • tests/unit/errors/test_compute_pipeline_error.py
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/mixins/**/*.py : Mixin classes should be composed into node classes for specific capabilities. Available mixins include: MixinDiscoveryResponder, MixinEventHandler, MixinEventListener, MixinNodeExecutor, MixinNodeLifecycle, MixinRequestResponseIntrospection, MixinWorkflowSupport.

Applied to files:

  • src/omnibase_core/mixins/mixin_compute_execution.py
🧬 Code graph analysis (13)
src/omnibase_core/utils/compute_executor.py (1)
src/omnibase_core/models/compute/model_compute_execution_context.py (1)
  • ModelComputeExecutionContext (44-95)
tests/unit/utils/test_compute_pipeline.py (20)
src/omnibase_core/enums/enum_case_mode.py (1)
  • EnumCaseMode (10-22)
src/omnibase_core/enums/enum_compute_step_type.py (1)
  • EnumComputeStepType (50-91)
src/omnibase_core/enums/enum_regex_flag.py (1)
  • EnumRegexFlag (10-22)
src/omnibase_core/enums/enum_trim_mode.py (1)
  • EnumTrimMode (10-22)
src/omnibase_core/enums/enum_unicode_form.py (1)
  • EnumUnicodeForm (10-24)
src/omnibase_core/models/compute/model_compute_execution_context.py (1)
  • ModelComputeExecutionContext (44-95)
src/omnibase_core/models/compute/model_compute_step_metadata.py (1)
  • ModelComputeStepMetadata (37-77)
src/omnibase_core/models/compute/model_compute_step_result.py (1)
  • ModelComputeStepResult (64-122)
src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py (1)
  • ModelComputePipelineStep (81-200)
src/omnibase_core/models/contracts/subcontracts/model_compute_subcontract.py (1)
  • ModelComputeSubcontract (73-147)
src/omnibase_core/models/transformations/model_mapping_config.py (1)
  • ModelMappingConfig (13-37)
src/omnibase_core/models/transformations/model_transform_case_config.py (1)
  • ModelTransformCaseConfig (15-27)
src/omnibase_core/models/transformations/model_transform_json_path_config.py (1)
  • ModelTransformJsonPathConfig (13-35)
src/omnibase_core/models/transformations/model_transform_regex_config.py (1)
  • ModelTransformRegexConfig (15-31)
src/omnibase_core/models/transformations/model_transform_trim_config.py (1)
  • ModelTransformTrimConfig (15-27)
src/omnibase_core/models/transformations/model_transform_unicode_config.py (1)
  • ModelTransformUnicodeConfig (15-27)
src/omnibase_core/models/transformations/model_validation_step_config.py (1)
  • ModelValidationStepConfig (13-30)
src/omnibase_core/utils/compute_executor.py (2)
  • execute_compute_pipeline (409-582)
  • resolve_mapping_path (112-238)
src/omnibase_core/utils/compute_transformations.py (7)
  • execute_transformation (413-474)
  • transform_case (178-224)
  • transform_identity (84-120)
  • transform_json_path (319-398)
  • transform_regex (123-175)
  • transform_trim (227-274)
  • transform_unicode (277-316)
src/omnibase_core/protocols/event_bus.py (1)
  • operation_name (156-158)
src/omnibase_core/errors/__init__.py (1)
src/omnibase_core/errors/exception_compute_pipeline_error.py (1)
  • ComputePipelineError (56-129)
src/omnibase_core/errors/exception_compute_pipeline_error.py (1)
src/omnibase_core/enums/enum_core_error_code.py (1)
  • EnumCoreErrorCode (9-154)
tests/unit/errors/test_compute_pipeline_error.py (2)
src/omnibase_core/errors/exception_compute_pipeline_error.py (1)
  • ComputePipelineError (56-129)
src/omnibase_core/enums/enum_core_error_code.py (1)
  • EnumCoreErrorCode (9-154)
src/omnibase_core/models/contracts/subcontracts/model_compute_subcontract.py (1)
src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py (1)
  • ModelComputePipelineStep (81-200)
src/omnibase_core/utils/compute_transformations.py (10)
src/omnibase_core/enums/enum_case_mode.py (1)
  • EnumCaseMode (10-22)
src/omnibase_core/enums/enum_core_error_code.py (1)
  • EnumCoreErrorCode (9-154)
src/omnibase_core/enums/enum_regex_flag.py (1)
  • EnumRegexFlag (10-22)
src/omnibase_core/enums/enum_transformation_type.py (1)
  • EnumTransformationType (11-34)
src/omnibase_core/enums/enum_trim_mode.py (1)
  • EnumTrimMode (10-22)
src/omnibase_core/models/transformations/model_transform_case_config.py (1)
  • ModelTransformCaseConfig (15-27)
src/omnibase_core/models/transformations/model_transform_json_path_config.py (1)
  • ModelTransformJsonPathConfig (13-35)
src/omnibase_core/models/transformations/model_transform_regex_config.py (1)
  • ModelTransformRegexConfig (15-31)
src/omnibase_core/models/transformations/model_transform_trim_config.py (1)
  • ModelTransformTrimConfig (15-27)
src/omnibase_core/models/transformations/model_transform_unicode_config.py (1)
  • ModelTransformUnicodeConfig (15-27)
tests/integration/test_compute_pipeline_integration.py (6)
src/omnibase_core/enums/enum_compute_step_type.py (1)
  • EnumComputeStepType (50-91)
src/omnibase_core/models/compute/model_compute_execution_context.py (1)
  • ModelComputeExecutionContext (44-95)
src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py (1)
  • ModelComputePipelineStep (81-200)
src/omnibase_core/models/contracts/subcontracts/model_compute_subcontract.py (1)
  • ModelComputeSubcontract (73-147)
src/omnibase_core/models/transformations/model_mapping_config.py (1)
  • ModelMappingConfig (13-37)
src/omnibase_core/utils/compute_executor.py (1)
  • execute_compute_pipeline (409-582)
tests/unit/models/contracts/subcontracts/test_model_compute_subcontract.py (4)
src/omnibase_core/enums/enum_compute_step_type.py (1)
  • EnumComputeStepType (50-91)
src/omnibase_core/enums/enum_transformation_type.py (1)
  • EnumTransformationType (11-34)
src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py (1)
  • ModelComputePipelineStep (81-200)
src/omnibase_core/models/contracts/subcontracts/model_compute_subcontract.py (1)
  • ModelComputeSubcontract (73-147)
src/omnibase_core/mixins/mixin_compute_execution.py (4)
src/omnibase_core/models/compute/model_compute_execution_context.py (1)
  • ModelComputeExecutionContext (44-95)
src/omnibase_core/models/compute/model_compute_pipeline_result.py (1)
  • ModelComputePipelineResult (53-122)
src/omnibase_core/models/contracts/subcontracts/model_compute_subcontract.py (1)
  • ModelComputeSubcontract (73-147)
src/omnibase_core/utils/compute_executor.py (1)
  • execute_compute_pipeline (409-582)
src/omnibase_core/models/compute/__init__.py (4)
src/omnibase_core/models/compute/model_compute_execution_context.py (1)
  • ModelComputeExecutionContext (44-95)
src/omnibase_core/models/compute/model_compute_pipeline_result.py (1)
  • ModelComputePipelineResult (53-122)
src/omnibase_core/models/compute/model_compute_step_metadata.py (1)
  • ModelComputeStepMetadata (37-77)
src/omnibase_core/models/compute/model_compute_step_result.py (1)
  • ModelComputeStepResult (64-122)
src/omnibase_core/models/compute/model_compute_step_result.py (1)
src/omnibase_core/models/compute/model_compute_step_metadata.py (1)
  • ModelComputeStepMetadata (37-77)
tests/unit/models/nodes/node_services/test_model_service_compute_integration.py (1)
src/omnibase_core/models/infrastructure/model_time_based.py (1)
  • timeout (288-310)
🪛 LanguageTool
docs/architecture/NODECOMPUTE_VERSIONING_ROADMAP.md

[style] ~55-~55: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...itions. Boring code is debuggable code. Boring APIs are learnable APIs. Stable: O...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Smoke Tests
  • GitHub Check: claude-review
🔇 Additional comments (36)
tests/unit/models/nodes/node_services/test_model_service_compute_lifecycle.py (4)

94-95: LGTM! Pytest markers correctly applied.

The @pytest.mark.unit and @pytest.mark.timeout(60) markers are correctly added to categorize this as a unit test class and prevent test hangs. The 60-second timeout is appropriate given the complex async lifecycle operations, including service start/stop cycles and multiple sleep delays.

Based on coding guidelines: "Write tests using pytest with async support via pytest-asyncio. Use pytest markers: @pytest.mark.unit, @pytest.mark.integration, @pytest.mark.slow. Add @pytest.mark.timeout() to prevent test hangs."


542-543: LGTM! Appropriate timeout for tool invocation tests.

The markers are correctly applied. The 30-second timeout is well-suited for these simpler tool invocation tests, which have faster execution patterns compared to the lifecycle tests.


607-608: LGTM! Timeout is more than sufficient.

The markers are correctly applied. The 30-second timeout is more than adequate for these predominantly synchronous health monitoring tests.


681-682: LGTM! Markers correctly applied.

The markers properly categorize these shutdown handling tests and provide adequate timeout protection for the async shutdown operations.

tests/unit/models/configuration/test_model_compute_cache_config.py (1)

16-16: LGTM! Proper test categorization with unit markers.

The addition of @pytest.mark.unit to all test classes correctly categorizes these as unit tests, aligning with the project's coding guidelines. This enables selective test execution and improves test organization.

Also applies to: 51-51, 132-132, 190-190, 257-257, 294-294, 347-347

docs/architecture/NODECOMPUTE_VERSIONING_ROADMAP.md (1)

1-993: Well-structured versioning roadmap.

The document provides a comprehensive versioning strategy with clear:

  • Philosophy ("boring first" principle)
  • Feature progression across v1.0-v1.3
  • Version guarantees and migration paths
  • Success criteria for each version

The explicit deferral of features (caching, parallelism, conditionals) to later versions aligns well with the PR's v1.0 scope.

docs/architecture/CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md (1)

1-930: Comprehensive v1.0 specification.

The document provides a clear, implementable specification with:

  • Well-defined core models with immutability guarantees
  • Clear transformation config patterns using discriminated unions
  • Detailed execution model with abort-on-first-failure semantics
  • Comprehensive example contract demonstrating all step types
  • Realistic implementation plan with acceptance criteria

The separation of VALIDATION as a step type (not transformation) is a good design decision that keeps semantic boundaries clean.

src/omnibase_core/models/model_compute_output.py (1)

1-51: Excellent documentation.

The module and class docstrings are comprehensive with:

  • Clear thread safety notes
  • Well-documented type parameters
  • Practical usage examples
  • Cross-references to related modules
src/omnibase_core/utils/compute_transformations.py (4)

84-121: LGTM - Clean identity transformation implementation.

The identity transformation correctly:

  • Accepts any input type unchanged
  • Requires no config (enforced by contract validation)
  • Uses del config to explicitly mark unused parameter
  • Documents the uniform registry handler pattern

123-176: LGTM - Robust regex transformation.

Good defensive implementation with:

  • Input type validation
  • Explicit flag conversion (no implicit Python flag usage)
  • Proper error wrapping with exception chaining (from e)

178-317: LGTM - Clean string transformation implementations.

All three transformations (transform_case, transform_trim, transform_unicode) follow a consistent pattern:

  • Input type validation
  • Exhaustive enum matching with defensive else clause
  • Clear error messages with appropriate error codes

The defensive else clauses for unknown enum values are good practice even though they should be unreachable with proper typing.


401-491: LGTM - Well-designed transformation registry and executor.

The implementation correctly:

  • Maps all 6 v1.0 transformation types to handlers
  • Handles IDENTITY special case (no config required)
  • Validates config presence for non-IDENTITY transformations
  • Provides clear error messages with appropriate error codes
  • Exports all public symbols in __all__
tests/unit/models/nodes/node_services/test_model_service_compute_invocation.py (2)

101-107: LGTM - Timeout markers added per coding guidelines.

Adding @pytest.mark.unit and @pytest.mark.timeout(30) to test classes follows the coding guidelines for preventing test hangs. The 30-second timeout is appropriate for service invocation tests that may involve async operations.

Based on learnings: "Add pytest.mark.timeout() to prevent test hangs."


229-925: Consistent marker application across all test classes.

All 11 test classes now have @pytest.mark.unit and @pytest.mark.timeout(30) markers applied consistently. This ensures:

  • Tests are properly categorized for selective execution
  • Timeout protection prevents hangs during CI/CD
src/omnibase_core/errors/exception_compute_pipeline_error.py (1)

56-129: Well-structured exception class following project conventions.

The implementation correctly:

  • Inherits from ModelOnexError per coding guidelines for structured error handling
  • Uses EnumCoreErrorCode.PROCESSING_ERROR as the default error code
  • Provides complete type annotations for mypy strict compliance
  • Injects step_name and operation into context while also storing as attributes for direct access

The dual storage (in context dict and as attributes) is intentional and useful for both serialization and programmatic access.

tests/unit/models/nodes/node_services/test_model_service_compute_health.py (4)

131-133: Test markers properly applied per coding guidelines.

The @pytest.mark.unit and @pytest.mark.timeout(30) decorators are correctly applied. The 30-second timeout is appropriate for health status tests.


240-242: Appropriate timeout for health monitoring tests.


371-373: Good choice of longer timeout for graceful shutdown tests.

The 60-second timeout is appropriate for TestModelServiceComputeGracefulShutdown since these tests involve async shutdown operations, signal handlers, and waiting for active invocations to complete.


655-657: Edge case tests properly marked.

tests/unit/models/nodes/node_services/test_model_service_compute_integration.py (2)

73-75: Integration test markers appropriately applied.

The 60-second timeout for TestModelServiceComputeIntegration is suitable given the comprehensive end-to-end tests including cache operations, health checks, and tool invocations.


601-603: MRO detail tests properly marked.

The 30-second timeout is appropriate for these synchronous MRO verification tests.

tests/unit/models/contracts/subcontracts/test_model_compute_subcontract.py (1)

1-176: Comprehensive test coverage for ModelComputeSubcontract.

The tests thoroughly cover:

  • Minimal/default construction
  • Pipeline with steps
  • Timeout validation boundaries (1ms, 1hr max, rejection of 0/negative/exceeds-max)
  • Immutability enforcement
  • Extra field rejection

Good use of pytest.raises with match patterns for validation error assertions.

src/omnibase_core/models/compute/model_compute_step_result.py (3)

48-61: Correct forward reference pattern for avoiding circular imports.

The TYPE_CHECKING guard with runtime import and model_rebuild() is the proper pattern for handling forward references in Pydantic while avoiding circular import issues.


64-123: Well-designed immutable step result model.

The model correctly:

  • Uses frozen=True for thread safety per coding guidelines
  • Uses extra="forbid" to reject unknown fields
  • Documents success/failure semantics clearly
  • Uses str | None for error_type (v1.0 design decision documented)
  • Provides comprehensive docstrings with usage examples

125-130: Runtime import for forward reference resolution.

The # noqa: E402 suppresses the late import warning, which is intentional here. The model_rebuild() call finalizes the forward reference resolution.

tests/unit/utils/test_compute_pipeline.py (1)

60-585: Well‑scoped unit coverage for transformations, mapping, and executor

The tests here exercise all transformation handlers (including flag/error paths), mapping path resolution, and core pipeline semantics (multi‑step, abort‑on‑failure, disabled steps, timing) in a focused, deterministic way. This gives strong protection around the new NodeCompute v1.0 surface without introducing brittle coupling to internal details.

src/omnibase_core/errors/__init__.py (1)

7-9: ComputePipelineError export aligns with existing lazy‑load pattern

TYPE_CHECKING import, __all__ entry, and the __getattr__ branch for ComputePipelineError mirror how other error types are exposed from this package, giving a clean public API without adding eager imports or new cycles.

Also applies to: 46-67, 110-116

src/omnibase_core/models/compute/model_compute_step_metadata.py (1)

37-77: Step metadata model matches executor semantics

Freezing the model and constraining duration_ms to be non‑negative fits how execute_compute_pipeline constructs metadata and how tests assert on it. Using a plain str | None for transformation_type is consistent with storing the enum’s .value while keeping the model simple.

tests/integration/test_compute_pipeline_integration.py (1)

44-1200: Comprehensive integration coverage for NodeCompute v1.0

This module gives very strong end‑to‑end coverage: step sequencing, abort‑on‑first‑failure, mapping over prior outputs, disabled steps, timing metadata, concurrency, and edge cases across all step types are all exercised against the public API. This should make regressions in the executor or transformation layer highly visible.

src/omnibase_core/models/model_compute_input.py (1)

61-102: Input model metadata cleanly matches described semantics

The additional fields on ModelComputeInput (operation_id, computation_type, cache/parallel flags, metadata, timestamp) are well‑documented and their defaults align with the examples. This should give NodeCompute implementations enough context for routing, caching, and basic observability without complicating the call‑site.

Also applies to: 104-110

src/omnibase_core/models/compute/__init__.py (1)

1-78: Public compute models API is clear and minimal

Re‑exporting just the four core compute models with a descriptive module docstring gives a tidy import surface (from omnibase_core.models.compute import ...) that matches how the executor and tests use these types.

src/omnibase_core/utils/compute_executor.py (4)

77-107: Error-type extraction helper is robust and aligned with result model

_get_error_type cleanly normalizes ModelOnexError.error_code for use in pipeline results, handling None, enum-like values, and raw strings without leaking implementation details. No changes needed.


241-285: Mapping-step execution is straightforward and leverages the resolver correctly

execute_mapping_step enforces presence of mapping_config and delegates all value extraction to resolve_mapping_path, which keeps mapping logic simple and consistent with path semantics. Implementation looks solid.


344-404: Step dispatcher cleanly separates concerns across step types

execute_pipeline_step respects step.enabled, enforces transformation_type for transformation steps, and routes to the appropriate helper for TRANSFORMATION/MAPPING/VALIDATION, raising a ModelOnexError for unknown types. The separation keeps per-step logic focused and matches the EnumComputeStepType contract.


409-582: Pipeline executor correctly implements abort-on-first-failure and structured errors

The main loop in execute_compute_pipeline:

  • Skips disabled steps.
  • Times each executed step and records per-step metadata.
  • Stores results in a dict keyed by step_name, which enables subsequent path resolution.
  • Cleanly distinguishes ModelOnexError (mapped via _get_error_type) from unexpected exceptions (logged and surfaced as "unexpected_error"), while always returning a structured ModelComputePipelineResult.

This matches the v1.0 contract description and the coding guideline of using ModelOnexError and EnumCoreErrorCode as the primary error surface, with a safe fallback for unexpected failures. As per coding guidelines, this is a solid implementation of contract-driven, structured error handling.

tests/unit/models/compute/conftest.py (1)

37-189: Fixture set cleanly covers typical compute contracts and contexts

The fixtures provide focused, reusable builders for execution contexts, transformation configs, pipeline steps, and several representative ModelComputeSubcontract shapes (empty, single-step, multi-step, with timeout). This should keep unit and integration tests concise and consistent. No issues spotted.

Comment thread docs/architecture/CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md Outdated
Comment thread docs/architecture/NODECOMPUTE_VERSIONING_ROADMAP.md Outdated
…465]

Documentation:
- Add $input alias documentation for path resolution
- Fix version inconsistencies (v1.1/v1.2/v1.3 alignment)
- Change specific dates to relative milestones
- Add example contract reference

Model Validators:
- Add unique step_name validator with helpful error messages
- Add 6 new tests for step name uniqueness validation

Code Quality & Observability:
- Add logging for pipeline step execution with correlation_id
- Add context to all error messages (13 error sites)
- Add validation step warning with deduplication
- Add TODO comments with target versions

Code Consistency:
- DRY: Create _validate_string_input() helper function
- Align transform_identity signature with other handlers
- Document private attribute security behavior
- Optimize duplicate step detection from O(n²) to O(n)

Test Infrastructure:
- Add @pytest.mark.timeout(60) to integration tests
- Tighten frozen model test assertions
- Simplify regex test assertion
- Add shared conftest.py for integration test fixtures
@claude

claude Bot commented Dec 7, 2025

Copy link
Copy Markdown

PR Review: Contract-Driven NodeCompute v1.0 [OMN-465]

Summary

This is a well-architected, production-ready implementation of contract-driven NodeCompute v1.0. The PR demonstrates exceptional attention to detail, strong adherence to ONEX design principles, and comprehensive documentation. The incremental versioning approach (v1.0 → v1.1 → v1.2) is exemplary.

✅ Strengths

1. Architecture & Design

  • Excellent separation of concerns: Pure transformation functions, pipeline executor, and async mixin are cleanly separated
  • Protocol-driven approach: Consistent with ONEX principles (transformations registered by enum, not by class name)
  • Immutability guarantees: All result models use frozen=True, setting foundation for future parallel execution
  • Abort-on-first-failure semantics: Clear, predictable error handling with full step result preservation

2. Code Quality

  • Exceptional documentation: Every function has comprehensive docstrings with thread safety notes, examples, and v1.1+ migration paths
  • Type safety: Proper use of Any with justification comments, discriminated unions for transformation configs
  • Error handling: Structured errors with ModelOnexError, rich context, and security considerations (private attribute blocking)
  • DRY principles: _validate_string_input() helper eliminates duplication across string transformations

3. Testing

  • Comprehensive coverage: 95 unit tests covering all transformations, edge cases, and error paths
  • Integration tests: Full pipeline scenarios in test_compute_pipeline_integration.py
  • Well-organized: Tests are grouped by transformation type with clear naming

4. Documentation

  • Exceptional spec documents: CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md and NODECOMPUTE_VERSIONING_ROADMAP.md are comprehensive
  • Clear scope boundaries: v1.0 vs deferred features explicitly documented
  • Example contracts: user_profile_normalizer.yaml provides concrete usage example

5. Performance & Security

  • Security-conscious: Private attribute blocking in path resolution (lines 204, 440 in compute_executor.py)
  • Efficient validation: O(n) duplicate detection using Counter (mixin_compute_execution.py:189)
  • Observability: Structured logging with correlation IDs and detailed metrics

🔍 Issues & Recommendations

Critical Issues

None identified - Code is production-ready.

Minor Issues

1. TODO Comments Need Tracking (Low Priority)

Several TODOs reference v1.1/v1.2 features but lack ticket numbers:

  • compute_executor.py:113-115: Path resolution duplication
  • compute_executor.py:427-429: Pipeline timeout enforcement
  • compute_transformations.py:118-123: TransformationError class

Recommendation: Create Linear tickets for each TODO and reference them in comments (e.g., TODO(OMN-XXX)).

2. Validation Step Warning Could Be Noisy (Low Priority)

compute_executor.py:345-353 emits a UserWarning for validation steps. While session-deduplicated, this may still clutter logs in production.

Recommendation: Consider:

  • Downgrade to debug-level logging only (already done on line 356)
  • Or add a feature flag to disable warnings in production

3. Path Resolution Duplication (Already Tracked in Code)

resolve_mapping_path() (compute_executor.py) and transform_json_path() (compute_transformations.py) share similar traversal logic.

Recommendation: Defer to v1.1 as already noted in TODO (line 113).

Potential Improvements

1. Type Narrowing for Error Codes

_get_error_type() (compute_executor.py:81-110) could use TypeGuard or more precise typing:

def _get_error_type(error: ModelOnexError) -> str:
    if error.error_code is None:
        return "compute_error"
    # Use value if enum, otherwise convert to string
    return getattr(error.error_code, "value", str(error.error_code))

This is cleaner but current implementation is also acceptable.

2. Contract Validation Could Validate Schema Refs

MixinComputeExecution.validate_compute_contract() validates step names and mappings but doesn't check if input_schema_ref / output_schema_ref exist in the registry.

Recommendation: Add schema ref validation in v1.1 (when schema validation is fully implemented).

3. Missing Enum Export in __init__.py

Verify that all new enums are exported from omnibase_core.enums.__init__.py (appears correct but worth double-checking).

📊 Test Coverage Analysis

Excellent coverage with 95 unit tests and integration tests covering:

  • ✅ All 6 transformation types (IDENTITY, REGEX, CASE_CONVERSION, TRIM, NORMALIZE_UNICODE, JSON_PATH)
  • ✅ Step types (TRANSFORMATION, MAPPING, VALIDATION)
  • ✅ Error paths (invalid input, missing config, unknown step references)
  • ✅ Edge cases (private attribute access, nested paths, disabled steps)
  • ✅ Integration scenarios (full pipeline execution)

Recommendation: Ensure CI runs pass before merge (appears to be in progress).

🔒 Security Considerations

Strong security practices:

  • ✅ Private attribute blocking in path resolution prevents internal state exposure
  • ✅ No eval/exec usage - all transformations are pure functions
  • ✅ Regex patterns validated before compilation
  • ✅ Immutable result models prevent mutation attacks

Recommendation: None - security posture is excellent.

📝 Documentation Quality

Exceptional:

  • ✅ Comprehensive spec documents with clear versioning roadmap
  • ✅ Every function has detailed docstrings with thread safety notes
  • ✅ Example contracts provided
  • ✅ Clear migration guidance from code-driven to contract-driven approach

Recommendation: Consider adding a migration guide in docs/guides/ for developers upgrading from pre-v0.4.0 NodeCompute.

🚀 Performance Considerations

Well-optimized:

  • ✅ Pure functions enable easy caching in future versions
  • ✅ Sequential execution avoids complexity in v1.0
  • ✅ Efficient duplicate detection using Counter
  • ✅ Minimal allocations in transformation functions

Note: Pipeline timeout enforcement is deferred to v1.1 (tracked in TODO).

🎯 Adherence to CLAUDE.md Standards

Excellent compliance:

  • ✅ Uses Poetry for all dependencies
  • ✅ Follows ONEX four-node architecture
  • ✅ Protocol-driven dependency injection pattern
  • ✅ Structured errors with ModelOnexError
  • ✅ Proper use of frozen=True for immutability
  • ✅ Thread safety documented
  • ✅ mypy strict mode compliance (0 errors reported in description)

Final Recommendation

✅ APPROVE with minor suggestions

This is exemplary work that sets a high bar for future ONEX implementations. The code is:

  • Production-ready with no critical issues
  • Comprehensively tested
  • Exceptionally well-documented
  • Security-conscious
  • Performance-optimized

Merge Checklist

  • CI pipeline passes (all 20 splits)
  • mypy --strict shows 0 errors
  • Test coverage ≥60% (likely much higher given 95 tests)
  • Create Linear tickets for TODOs (optional but recommended)

Estimated Effort to Address Suggestions: 1-2 hours (optional enhancements only)


Outstanding work, @jonahgabriel! This implementation is a textbook example of how to build contract-driven infrastructure with clarity, safety, and extensibility.

Review completed by Claude Code
Correlation ID: 95cac850-05a3-43e2-9e57-ccbbef683f43

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (5)
src/omnibase_core/utils/compute_executor.py (2)

54-56: Global mutable state contradicts "pure and stateless" claim.

The global _validation_warning_emitted flag introduces mutable module-level state, which contradicts the docstring claim that "All functions in this module are pure and stateless" (line 10). While the warning deduplication intent is reasonable, this creates a side effect that persists across calls.

Consider using Python's warnings.warn with a custom warning class and warnings.filterwarnings('once', ...) to achieve deduplication without module-level state, or document this exception explicitly.

-# Track if validation warning has been emitted for session deduplication
-_validation_warning_emitted = False
+# Custom warning class for filtering
+class ValidationPassthroughWarning(UserWarning):
+    """Warning emitted when validation steps use pass-through mode in v1.0."""
+    pass

Then in execute_validation_step:

import warnings
warnings.warn(
    "Validation steps are pass-through in v1.0. "
    "Schema validation will be implemented in v1.1.",
    ValidationPassthroughWarning,
    stacklevel=2,
)

And let the caller configure warnings.filterwarnings('once', category=ValidationPassthroughWarning) if deduplication is desired.


184-186: Undocumented path alias may cause confusion.

Line 184 accepts both "$.input" and "$input" (without the dot), but only $.input is documented in the docstring. This undocumented alias could lead to inconsistent usage patterns.

Either document $input as an accepted alias or remove it for consistency:

-    if path == "$.input" or path == "$input":
+    if path == "$.input":
         return input_data
tests/integration/conftest.py (1)

19-49: Fixtures are well-designed but appear unused in the test file.

The fixtures correctly provide both single-use and factory patterns for execution contexts. However, reviewing test_compute_pipeline_integration.py, each test class defines its own _create_context() method instead of using these fixtures.

Consider refactoring the test classes to use these fixtures to reduce duplication:

# In test class:
def test_example(self, compute_execution_context):
    result = execute_compute_pipeline(contract, data, compute_execution_context)

Or for multiple contexts in one test:

def test_example(self, compute_execution_context_factory):
    ctx1 = compute_execution_context_factory()
    ctx2 = compute_execution_context_factory()
tests/integration/test_compute_pipeline_integration.py (2)

60-65: Consider using the shared fixtures from conftest.py.

The _create_context() method is duplicated across 7 test classes (lines 60-65, 658-663, 874-879, 997-1002, 1235-1240, 1403-1408, 1544-1549). The tests/integration/conftest.py provides compute_execution_context and compute_execution_context_factory fixtures specifically to eliminate this duplication.

Example refactor:

 class TestComputePipelineIntegration:
-    def _create_context(self) -> ModelComputeExecutionContext:
-        """Create a test execution context."""
-        return ModelComputeExecutionContext(
-            operation_id=uuid4(),
-            correlation_id=uuid4(),
-        )
-
     def test_multi_step_pipeline_execution(
+        self, compute_execution_context: ModelComputeExecutionContext
     ) -> None:
         # ...
         result = execute_compute_pipeline(
             contract=contract,
             input_data="  hello world  ",
-            context=self._create_context(),
+            context=compute_execution_context,
         )

1359-1360: Move import to module level for consistency.

The inline import of ModelValidationStepConfig (line 1359) is inconsistent with the other imports at the top of the file. While functional, module-level imports improve readability and catch import errors earlier.

 # At top of file with other imports
+from omnibase_core.models.transformations.model_validation_step_config import (
+    ModelValidationStepConfig,
+)

 # In test method
-        from omnibase_core.models.transformations.model_validation_step_config import \
-            ModelValidationStepConfig
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8b7ea15 and 161800c.

📒 Files selected for processing (10)
  • docs/architecture/CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md (1 hunks)
  • docs/architecture/NODECOMPUTE_VERSIONING_ROADMAP.md (1 hunks)
  • src/omnibase_core/mixins/mixin_compute_execution.py (1 hunks)
  • src/omnibase_core/models/contracts/subcontracts/model_compute_subcontract.py (1 hunks)
  • src/omnibase_core/utils/compute_executor.py (1 hunks)
  • src/omnibase_core/utils/compute_transformations.py (1 hunks)
  • tests/integration/conftest.py (1 hunks)
  • tests/integration/test_compute_pipeline_integration.py (1 hunks)
  • tests/unit/models/compute/test_compute_models.py (1 hunks)
  • tests/unit/models/contracts/subcontracts/test_model_compute_subcontract.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • tests/unit/models/contracts/subcontracts/test_model_compute_subcontract.py
  • tests/unit/models/compute/test_compute_models.py
  • docs/architecture/CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md
  • src/omnibase_core/mixins/mixin_compute_execution.py
  • src/omnibase_core/utils/compute_transformations.py
🧰 Additional context used
📓 Path-based instructions (4)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Always use Poetry for Python package management and task execution. Use poetry run for pytest, mypy, black, isort, and other tools. Never use pip directly or execute python commands without the poetry run prefix.
Enforce 100% strict mypy compliance. All functions must have complete type annotations. Use poetry run mypy src/omnibase_core/ to verify strict mode compliance with no errors.
Format code with black, sort imports with isort, and lint with ruff. Run poetry run black src/ tests/, poetry run isort src/ tests/, and poetry run ruff check --fix src/ tests/

Files:

  • tests/integration/conftest.py
  • src/omnibase_core/utils/compute_executor.py
  • tests/integration/test_compute_pipeline_integration.py
  • src/omnibase_core/models/contracts/subcontracts/model_compute_subcontract.py
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Write tests using pytest with async support via pytest-asyncio. Maintain minimum 60% code coverage. Use pytest markers: @pytest.mark.unit, @pytest.mark.integration, @pytest.mark.slow
Add @pytest.mark.timeout() to prevent test hangs. Run tests with poetry run pytest tests/ --timeout=60 for 60-second timeout protection.

Files:

  • tests/integration/conftest.py
  • tests/integration/test_compute_pipeline_integration.py
src/omnibase_core/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/omnibase_core/**/*.py: Use protocol names with container.get_service() for dependency injection, never resolve services by concrete class names. Example: container.get_service('ProtocolEventBus') instead of container.get_service('EventBusService')
Always use ModelONEXContainer for dependency injection in node constructors and service resolution. Never confuse it with ModelContainer[T], which is a generic value wrapper, not a DI container.
Use structured error handling with ModelOnexError and EnumCoreErrorCode, never raise generic Exception. Always chain exceptions with from e when catching and re-raising.
Use the @standard_error_handling decorator on methods to eliminate 6+ lines of try/catch boilerplate. Example: @standard_error_handling above async methods.
Respect thread safety constraints: Do NOT share node instances (NodeCompute, NodeEffect), cache, or circuit breaker instances across threads without synchronization. Use thread-local instances or locks.
Use duck typing with protocols. Do not use isinstance checks with protocol types. Rely on the protocol interface directly.
Use EnumNodeKind for high-level architectural classification (EFFECT, COMPUTE, REDUCER, ORCHESTRATOR) when routing data through the ONEX pipeline. Use EnumNodeType for specific implementation discovery and capability matching.
Use ModelEventEnvelope for inter-service event-driven communication. Process events through the envelope pattern for consistent event handling.

Files:

  • src/omnibase_core/utils/compute_executor.py
  • src/omnibase_core/models/contracts/subcontracts/model_compute_subcontract.py
src/omnibase_core/models/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Use Pydantic 2.11+ models for all data validation and serialization. Ensure models are immutable after creation for thread safety.

Files:

  • src/omnibase_core/models/contracts/subcontracts/model_compute_subcontract.py
🧠 Learnings (4)
📓 Common learnings
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/nodes/node_compute.py : NodeCompute is for data processing and transformation. Inherit from NodeCompute for COMPUTE nodes that perform calculations, validations, and data mapping.
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to docs/guides/node-building/**/*.md : Node building guide is the critical starting point for developers and AI agents. Follow the sequence: What is a Node → Node Types → COMPUTE Tutorial → EFFECT Tutorial → REDUCER Tutorial → ORCHESTRATOR Tutorial.

Applied to files:

  • docs/architecture/NODECOMPUTE_VERSIONING_ROADMAP.md
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/nodes/node_compute.py : NodeCompute is for data processing and transformation. Inherit from NodeCompute for COMPUTE nodes that perform calculations, validations, and data mapping.

Applied to files:

  • src/omnibase_core/utils/compute_executor.py
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/nodes/node_orchestrator.py : NodeOrchestrator is for workflow-driven coordination. Use ModelAction with Leases for multi-step workflows and parallel execution. This is the PRIMARY implementation as of v0.4.0 (replaces NodeOrchestratorDeclarative).

Applied to files:

  • src/omnibase_core/utils/compute_executor.py
🧬 Code graph analysis (3)
tests/integration/conftest.py (1)
src/omnibase_core/models/compute/model_compute_execution_context.py (1)
  • ModelComputeExecutionContext (44-95)
tests/integration/test_compute_pipeline_integration.py (7)
src/omnibase_core/enums/enum_compute_step_type.py (1)
  • EnumComputeStepType (50-91)
src/omnibase_core/enums/enum_transformation_type.py (1)
  • EnumTransformationType (11-34)
src/omnibase_core/models/compute/model_compute_execution_context.py (1)
  • ModelComputeExecutionContext (44-95)
src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py (1)
  • ModelComputePipelineStep (81-200)
src/omnibase_core/models/contracts/subcontracts/model_compute_subcontract.py (1)
  • ModelComputeSubcontract (73-181)
src/omnibase_core/models/transformations/model_mapping_config.py (1)
  • ModelMappingConfig (13-37)
src/omnibase_core/utils/compute_executor.py (1)
  • execute_compute_pipeline (430-642)
src/omnibase_core/models/contracts/subcontracts/model_compute_subcontract.py (1)
src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py (1)
  • ModelComputePipelineStep (81-200)
🪛 LanguageTool
docs/architecture/NODECOMPUTE_VERSIONING_ROADMAP.md

[style] ~55-~55: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...itions. Boring code is debuggable code. Boring APIs are learnable APIs. Stable: O...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Smoke Tests
  • GitHub Check: claude-review
🔇 Additional comments (8)
docs/architecture/NODECOMPUTE_VERSIONING_ROADMAP.md (1)

1-993: Comprehensive and well-structured versioning roadmap.

The document establishes a clear versioning philosophy with the "boring first" principle, appropriate for a platform primitive. The milestone-based timeline (lines 130-139) correctly avoids fixed calendar dates in favor of production-validated progression. The clear delineation between what's in scope for each version and the backward compatibility guarantees are well-articulated.

The three successive uses of "Boring" at line 55 appear intentional for rhetorical emphasis and fit the document's tone.

src/omnibase_core/utils/compute_executor.py (3)

298-362: LGTM: Validation step correctly implements v1.0 pass-through.

The pass-through behavior with appropriate warnings is well-documented and aligned with the v1.0 specification. The debug logging provides good observability for troubleshooting.


365-424: LGTM: Clean step dispatcher with proper error handling.

The dispatch logic covers all v1.0 step types with appropriate error handling for unknown types. The early return for disabled steps is efficient.


430-642: LGTM: Well-implemented pipeline executor with abort-on-first-failure.

The implementation correctly follows the v1.0 specification:

  • Sequential execution in definition order
  • Comprehensive timing metrics with time.perf_counter()
  • Failed steps are properly recorded before aborting
  • Structured logging with context IDs for observability

The TODO for timeout enforcement is appropriately documented for v1.1.

tests/integration/test_compute_pipeline_integration.py (2)

1410-1464: LGTM: Excellent concurrency tests verifying thread safety.

The concurrent execution tests properly verify that:

  • Each execution creates its own context (line 1448)
  • Multiple executions don't interfere with each other
  • Results are correctly matched to inputs

This aligns with the coding guidelines requirement to respect thread safety constraints.


1536-1746: LGTM: Comprehensive edge case coverage.

The edge case tests cover important boundary conditions including:

  • All-disabled pipelines returning input unchanged
  • Special characters (Unicode, regex metacharacters, newlines)
  • Deeply nested structures
  • Null/empty values
  • Large collections

This provides confidence in the pipeline's robustness.

src/omnibase_core/models/contracts/subcontracts/model_compute_subcontract.py (2)

149-180: LGTM: Unique step name validation correctly implemented.

The @field_validator on the pipeline field properly enforces unique step names, addressing the requirement from the past review comment. The error message helpfully includes the list of duplicate names for debugging.

The use of field_validator over model_validator is appropriate here since validation only depends on the pipeline field itself.


73-147: LGTM: Well-designed immutable model following Pydantic best practices.

The model correctly implements:

  • Immutability via frozen=True for thread safety (per coding guidelines)
  • extra="forbid" to prevent unknown fields
  • Appropriate field constraints on pipeline_timeout_ms
  • Clear default values for optional fields

The docstring comprehensively documents attributes, thread safety, and versioning semantics.

Documentation:
- Fix version inconsistencies (FILTER/MAP/REDUCE/SORT → v1.1, Expression Language → v1.1/v1.3)

Model Validators:
- Add ge=0 constraint to processing_time_ms in ModelComputePipelineResult
- Add extra="forbid" to ConfigDict for consistency across compute models
- Add frozen=True and ConfigDict to ModelComputeOutput

Test Quality:
- Add @pytest.mark.unit markers to test_compute_pipeline_error.py
- Extract _create_context helper to shared fixture in conftest.py
- Tighten test_regex_with_flags assertion with exact match verification
- Use specific exception types (ValidationError, AttributeError) for frozen model tests
- Move imports to module level in integration tests
- Add 13 new tests for compute models

CI Verification: All tests pass (3,836+ passed), mypy 0 errors
@claude

claude Bot commented Dec 7, 2025

Copy link
Copy Markdown

Code Review: Contract-Driven NodeCompute v1.0 [OMN-465]

Overview

This is an impressive and well-architected implementation of contract-driven compute pipelines. The PR introduces 9,283 additions across 52 files with excellent documentation, comprehensive testing (95 unit tests), and strong adherence to omnibase_core conventions.

✅ Strengths

1. Exceptional Documentation (935+ lines)

  • CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md is remarkably thorough with clear v1.0 scope boundaries
  • NODECOMPUTE_VERSIONING_ROADMAP.md provides excellent future planning
  • Inline documentation is consistently high-quality with detailed docstrings
  • Example contract (user_profile_normalizer.yaml) demonstrates real-world usage

2. Clean Architecture & Design Patterns

✅ Pure Functions: All transformation logic in utility modules (thread-safe by design)

  • compute_transformations.py: Pure transformation functions with no side effects
  • compute_executor.py: Stateless pipeline execution
  • Clear separation of concerns: Models → Executors → Mixins → Nodes

✅ Protocol-Driven: Follows omnibase_core's dependency injection patterns

  • Uses ModelONEXContainer for service resolution
  • ModelComputeExecutionContext for typed execution context
  • frozen=True on all result models for immutability guarantees

✅ Error Handling: Uses ModelOnexError with proper error codes throughout

  • Consistent error context in transformations (transform_type, input_type)
  • Structured error propagation in pipeline executor

3. Strong Type Safety

  • All models use Pydantic v2 with ConfigDict(extra="forbid", frozen=True)
  • Discriminated unions for transformation configs (ModelTransformationConfig)
  • @model_validator ensures config consistency at validation time
  • Comprehensive type annotations with Any properly documented

4. Security Considerations

✅ Private Attribute Protection (lines 204-208 in compute_executor.py, 440-449 in compute_transformations.py):

elif part.startswith("_"):
    raise ModelOnexError(
        error_code=EnumCoreErrorCode.VALIDATION_ERROR,
        message=f"Cannot access private attribute: '{part}'"
    )

This prevents path traversal attacks through object introspection while allowing dictionary keys starting with "_" (user data).

5. Testing Strategy

  • 95 unit tests covering enums, models, transformations, executor, and integration
  • Test organization follows source structure (tests/unit/enums/, tests/unit/models/compute/)
  • Integration tests demonstrate end-to-end pipeline execution

6. Performance & Observability

  • time.perf_counter() for microsecond-precision timing
  • Per-step metadata with duration tracking
  • Structured logging with operation_id/correlation_id
  • Debug logs for step transitions and skipped steps

⚠️ Issues & Recommendations

CRITICAL: CI Failures

🚨 Code Quality and Documentation Validation checks are failing. Must be addressed before merge.

Action Required: Investigate and fix CI failures:

  1. Run poetry run mypy src/omnibase_core/ locally to check type errors
  2. Run poetry run pytest tests/ to verify all tests pass
  3. Check pre-commit hooks with pre-commit run --all-files

1. Code Duplication: Path Resolution Logic ⚠️

Severity: Medium | Effort: 2-3 hours

Issue: Path resolution logic is duplicated between:

  • resolve_mapping_path() in compute_executor.py (lines 116-249)
  • transform_json_path() in compute_transformations.py (lines 360-464)

Both implement similar dot-notation traversal with private attribute blocking.

Evidence:

# compute_executor.py:113
# TODO(v1.1): Extract path resolution to shared utility

# Duplication:
- Both split paths on '.'
- Both handle dict vs object attribute access
- Both block private attributes (part.startswith('_'))
- Both raise similar ModelOnexError exceptions

Recommendation: Extract to shared _resolve_path() utility in v1.1:

# src/omnibase_core/utils/path_resolution.py
def resolve_dot_notation_path(
    path: str, 
    data: Any,
    allow_private: bool = False
) -> Any:
    """Shared path resolution for both mapping and JSON_PATH."""
    # Common traversal logic

Rationale: DRY principle, easier testing, consistent behavior across transformations.


2. Missing Timeout Enforcement ⚠️

Severity: Medium | Effort: 3-4 hours

Issue: pipeline_timeout_ms is declared in ModelComputeSubcontract but not enforced during execution.

Evidence:

# compute_executor.py:427
# TODO(v1.1): Enforce pipeline_timeout_ms - currently declared but not enforced

Current State:

  • Contract specifies pipeline_timeout_ms: int | None = None
  • Executor measures total time but doesn't abort on timeout
  • Long-running pipelines could hang indefinitely

Recommendation: For v1.0, either:

  1. Option A (Preferred): Implement basic timeout in v1.0
import signal
from contextlib import contextmanager

@contextmanager
def timeout_context(seconds: float):
    def timeout_handler(signum, frame):
        raise TimeoutError(f"Pipeline exceeded {seconds}s timeout")
    
    signal.signal(signal.SIGALRM, timeout_handler)
    signal.alarm(int(seconds))
    try:
        yield
    finally:
        signal.alarm(0)

# In execute_compute_pipeline:
if contract.pipeline_timeout_ms:
    with timeout_context(contract.pipeline_timeout_ms / 1000):
        # Execute pipeline
  1. Option B: Remove pipeline_timeout_ms from v1.0 contract entirely, defer to v1.1
    • Update documentation to reflect deferred feature
    • Add to v1.1 roadmap explicitly

Rationale: Either enforce the feature or remove it. Half-implemented features create false expectations.


3. Validation Steps Are Pass-Through ℹ️

Severity: Low (Documented) | Effort: Out of v1.0 scope

Issue: VALIDATION step type exists but doesn't validate (lines 298-362 in compute_executor.py).

Current Behavior:

# v1.0: Pass through data (schema validation deferred)
warnings.warn(
    "Validation steps are pass-through in v1.0. "
    "Schema validation will be implemented in v1.1.",
    UserWarning
)
return data

Assessment: ✅ Acceptable for v1.0

  • Well-documented limitation in spec
  • UserWarning alerts users appropriately
  • Deferred to v1.1 roadmap
  • Does not break backward compatibility

Recommendation: Consider adding enabled=False default for VALIDATION steps in v1.0 to prevent confusion:

# Example contract
- step_name: validate_input
  step_type: validation
  enabled: false  # Explicit: validation not yet implemented
  validation_config:
    schema_ref: input_schema

4. Type Annotations: Excessive Any Usage ℹ️

Severity: Low | Effort: 4-6 hours (v1.1)

Observation: Many functions use Any for data parameters, which is correct for polymorphic pipelines but could be more precise.

Examples:

def execute_pipeline_step(
    step: ModelComputePipelineStep,
    current_data: Any,  # Could be TypeVar or Union
    input_data: Any,
    step_results: dict[str, ModelComputeStepResult],
) -> Any:

Assessment: ✅ Acceptable for v1.0

  • Any is intentional for dynamic pipeline data types
  • Well-documented with inline comments explaining why Any is used
  • Full type inference would require complex TypeVars

Recommendation (v1.2+): Consider introducing PipelineData[T] generic wrapper:

from typing import Generic, TypeVar

T = TypeVar('T')

class PipelineData(Generic[T]):
    value: T
    metadata: dict[str, Any]

5. Error Type Strings vs Enums ℹ️

Severity: Low (Design Decision) | Effort: Already planned for v1.1

Current Design:

error_type: str | None = None  # v1.0: Simple string, not enum

Assessment: ✅ Correct for v1.0

  • Documented design decision (page 10 of spec)
  • Allows iteration without breaking changes
  • Planned migration to EnumComputeErrorType in v1.1

No action required - design is sound.


🎯 Additional Observations

Positive Patterns

  1. ✅ Session-Level Warning Deduplication (compute_executor.py:54-55, 345-353)
_validation_warning_emitted = False

if not _validation_warning_emitted:
    warnings.warn(...)
    _validation_warning_emitted = True

Prevents warning spam while maintaining visibility.

  1. ✅ Explicit Unused Parameter Handling (compute_transformations.py:162)
del config  # Explicitly mark as unused to satisfy linters

Clean pattern for required-but-unused parameters.

  1. ✅ Abort-on-First-Failure Semantics (compute_executor.py:540-588)
  • Failed steps are recorded in step_results
  • Pipeline immediately returns with error context
  • Prevents cascading failures

Minor Suggestions

  1. Logging Levels: Consider using logger.info() for pipeline start/completion instead of debug() for better production visibility.

  2. Path Alias Documentation: The $input alias for $.input is mentioned in docs but could be more prominent in examples.

  3. Error Context Richness: transformation errors include helpful context (available_keys, object_type) - excellent for debugging.


📊 Test Coverage Assessment

Metrics:

  • ✅ 95 unit tests added
  • ✅ Integration tests cover end-to-end pipelines
  • ✅ Test files mirror source structure
  • ✅ Fixtures in tests/unit/models/compute/conftest.py

Coverage Expectations:

  • Transformation functions: Should be near 100% (6 types × multiple test cases)
  • Executor logic: Should cover success, failure, and abort paths
  • Contract validation: Should test duplicate names, forward references

Recommendation: Verify coverage meets 60% threshold:

poetry run pytest tests/ --cov=src/omnibase_core --cov-report=term-missing

🔒 Security Review

✅ No security concerns identified

Security Features:

  1. ✅ Private attribute blocking prevents introspection attacks
  2. ✅ Path expressions validated before resolution
  3. ✅ No eval() or exec() usage
  4. ✅ Regex patterns wrapped in try/except for malicious patterns
  5. ✅ All inputs validated through Pydantic models

📋 Merge Checklist

Before Merging:

  • ✅ Fix CI failures (Code Quality + Documentation Validation)
  • ⚠️ Decide on pipeline_timeout_ms: Implement or remove from v1.0
  • ✅ Verify mypy --strict passes with 0 errors
  • ✅ Confirm test coverage ≥ 60%
  • ✅ Run poetry run pytest tests/ -x locally
  • ⚠️ Add TODO issue for path resolution refactoring (v1.1)

Nice to Have (Can defer):

  • Extract shared path resolution utility (v1.1)
  • Add more prominent $input alias examples
  • Consider enabled=false default for VALIDATION steps

🎖️ Final Assessment

Overall Score: ⭐⭐⭐⭐½ (4.5/5)

Verdict: APPROVE with required CI fixes

This is exceptional work that demonstrates:

  • Deep understanding of omnibase_core architecture
  • Strong software engineering practices (DRY, separation of concerns, type safety)
  • Excellent documentation and forward planning
  • Comprehensive testing strategy

Blocking Issues: CI failures must be resolved.

Non-Blocking Issues: Timeout enforcement and path resolution duplication should be tracked for v1.1.

Once CI passes, this PR will be a solid foundation for contract-driven compute pipelines. The incremental versioning strategy (v1.0 → v1.1 → v1.2) is wise and shows restraint in avoiding over-engineering.


Great work, @jonahgabriel! 🎉

Reviewed by Claude Code on 2025-12-07

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (5)
tests/unit/models/container/test_model_service.py (1)

6-6: Importing ValidationError is appropriate and scoped

The new ValidationError import is correctly limited to this test module and matches its only usage in test_frozen_model. As a follow-up (not blocking), this file still lacks pytest markers and timeouts; consider adding @pytest.mark.unit and @pytest.mark.timeout(60) at the class or test level to align with the test guidelines.

docs/architecture/CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md (2)

192-199: Minor documentation inconsistency: duration_ms constraint not shown.

The actual implementation in model_compute_step_metadata.py uses duration_ms: float = Field(ge=0) to enforce non-negative values, but this code snippet omits the constraint. Consider updating for accuracy:

 class ModelComputeStepMetadata(BaseModel):
     """Metadata for a single pipeline step execution."""

-    duration_ms: float
+    duration_ms: float = Field(ge=0)
     transformation_type: str | None = None

     model_config = ConfigDict(frozen=True)

198-199: Documentation shows inconsistent ConfigDict settings across model snippets.

ModelComputeStepMetadata (line 198) shows ConfigDict(frozen=True) but the actual implementation uses ConfigDict(extra="forbid", frozen=True). Meanwhile, ModelComputeStepResult (line 217) correctly shows extra="forbid". Consider aligning for consistency:

-    model_config = ConfigDict(frozen=True)
+    model_config = ConfigDict(extra="forbid", frozen=True)
tests/integration/test_compute_pipeline_integration.py (2)

172-175: Consider making error message assertion more flexible.

The assertion checking for "string" or "str" in the error message works but could be brittle if error message format changes. Consider using a more general assertion or documenting that this checks for type-related error hints:

# Current - works but coupled to message format
assert (
    "string" in result.error_message.lower()
    or "str" in result.error_message.lower()
)

# Alternative - just verify an error message exists (already tested above)
# The specific message format is an implementation detail

This is a minor observation - the current approach is acceptable for integration tests where you want to verify meaningful error messages.


837-871: Consider removing unused fixture parameter.

The compute_execution_context_factory fixture is declared but not used in test_context_ids_are_preserved since the test creates its own context with specific IDs. This is appropriate for the test's purpose, but the unused parameter could be removed for clarity:

 def test_context_ids_are_preserved(
-    self, compute_execution_context_factory: ComputeContextFactory
+    self,
 ) -> None:

Alternatively, keep it for consistency with other tests in the file - this is a minor style preference.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 161800c and 9601d77.

📒 Files selected for processing (12)
  • docs/architecture/CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md (1 hunks)
  • src/omnibase_core/models/compute/model_compute_execution_context.py (1 hunks)
  • src/omnibase_core/models/compute/model_compute_pipeline_result.py (1 hunks)
  • src/omnibase_core/models/compute/model_compute_step_metadata.py (1 hunks)
  • src/omnibase_core/models/model_compute_output.py (2 hunks)
  • tests/integration/conftest.py (1 hunks)
  • tests/integration/test_compute_pipeline_integration.py (1 hunks)
  • tests/unit/errors/test_compute_pipeline_error.py (1 hunks)
  • tests/unit/mixins/test_mixin_completion_data.py (2 hunks)
  • tests/unit/models/compute/test_compute_models.py (1 hunks)
  • tests/unit/models/container/test_model_service.py (2 hunks)
  • tests/unit/utils/test_model_field_converter.py (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • tests/unit/models/compute/test_compute_models.py
🚧 Files skipped from review as they are similar to previous changes (4)
  • tests/unit/errors/test_compute_pipeline_error.py
  • src/omnibase_core/models/model_compute_output.py
  • src/omnibase_core/models/compute/model_compute_execution_context.py
  • tests/integration/conftest.py
🧰 Additional context used
📓 Path-based instructions (4)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Always use Poetry for Python package management and task execution. Use poetry run for pytest, mypy, black, isort, and other tools. Never use pip directly or execute python commands without the poetry run prefix.
Enforce 100% strict mypy compliance. All functions must have complete type annotations. Use poetry run mypy src/omnibase_core/ to verify strict mode compliance with no errors.
Format code with black, sort imports with isort, and lint with ruff. Run poetry run black src/ tests/, poetry run isort src/ tests/, and poetry run ruff check --fix src/ tests/

Files:

  • tests/unit/mixins/test_mixin_completion_data.py
  • tests/unit/models/container/test_model_service.py
  • tests/integration/test_compute_pipeline_integration.py
  • tests/unit/utils/test_model_field_converter.py
  • src/omnibase_core/models/compute/model_compute_step_metadata.py
  • src/omnibase_core/models/compute/model_compute_pipeline_result.py
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Write tests using pytest with async support via pytest-asyncio. Maintain minimum 60% code coverage. Use pytest markers: @pytest.mark.unit, @pytest.mark.integration, @pytest.mark.slow
Add @pytest.mark.timeout() to prevent test hangs. Run tests with poetry run pytest tests/ --timeout=60 for 60-second timeout protection.

Files:

  • tests/unit/mixins/test_mixin_completion_data.py
  • tests/unit/models/container/test_model_service.py
  • tests/integration/test_compute_pipeline_integration.py
  • tests/unit/utils/test_model_field_converter.py
src/omnibase_core/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/omnibase_core/**/*.py: Use protocol names with container.get_service() for dependency injection, never resolve services by concrete class names. Example: container.get_service('ProtocolEventBus') instead of container.get_service('EventBusService')
Always use ModelONEXContainer for dependency injection in node constructors and service resolution. Never confuse it with ModelContainer[T], which is a generic value wrapper, not a DI container.
Use structured error handling with ModelOnexError and EnumCoreErrorCode, never raise generic Exception. Always chain exceptions with from e when catching and re-raising.
Use the @standard_error_handling decorator on methods to eliminate 6+ lines of try/catch boilerplate. Example: @standard_error_handling above async methods.
Respect thread safety constraints: Do NOT share node instances (NodeCompute, NodeEffect), cache, or circuit breaker instances across threads without synchronization. Use thread-local instances or locks.
Use duck typing with protocols. Do not use isinstance checks with protocol types. Rely on the protocol interface directly.
Use EnumNodeKind for high-level architectural classification (EFFECT, COMPUTE, REDUCER, ORCHESTRATOR) when routing data through the ONEX pipeline. Use EnumNodeType for specific implementation discovery and capability matching.
Use ModelEventEnvelope for inter-service event-driven communication. Process events through the envelope pattern for consistent event handling.

Files:

  • src/omnibase_core/models/compute/model_compute_step_metadata.py
  • src/omnibase_core/models/compute/model_compute_pipeline_result.py
src/omnibase_core/models/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Use Pydantic 2.11+ models for all data validation and serialization. Ensure models are immutable after creation for thread safety.

Files:

  • src/omnibase_core/models/compute/model_compute_step_metadata.py
  • src/omnibase_core/models/compute/model_compute_pipeline_result.py
🧠 Learnings (1)
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/models/**/*.py : Use Pydantic 2.11+ models for all data validation and serialization. Ensure models are immutable after creation for thread safety.

Applied to files:

  • tests/unit/mixins/test_mixin_completion_data.py
  • tests/unit/models/container/test_model_service.py
🧬 Code graph analysis (1)
src/omnibase_core/models/compute/model_compute_pipeline_result.py (1)
src/omnibase_core/models/compute/model_compute_step_result.py (1)
  • ModelComputeStepResult (64-122)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: claude-review
  • GitHub Check: Smoke Tests
🔇 Additional comments (16)
tests/unit/utils/test_model_field_converter.py (1)

456-458: LGTM! Excellent test precision improvement.

Changing from catching generic Exception to the more specific AttributeError makes the test assertion more precise and accurate. The comment clearly explains the Python version compatibility consideration, which is helpful for maintainability.

tests/unit/models/container/test_model_service.py (1)

59-60: Stricter frozen-model assertion matches Pydantic v2 behavior

Using pytest.raises(ValidationError, match="frozen") when mutating a frozen ModelService aligns with Pydantic v2’s behavior, where frozen models raise ValidationError (error type frozen_instance) on attribute assignment.(deepwiki.com) The # type: ignore[misc] is also appropriate to satisfy strict mypy while exercising the mutation. This strengthens the immutability contract for service models and matches the Pydantic-based immutability learning for this repo. Based on learnings, this looks correct.

tests/unit/mixins/test_mixin_completion_data.py (2)

5-7: Importing ValidationError is appropriate for frozen Pydantic models

Using ValidationError from pydantic for the immutability assertions is correct and keeps the dependency explicit in this test module. No changes needed here.


156-168: Test implementation is correct; error message matching is reliable and aligns with codebase patterns

The test_mixin_completion_data_immutable correctly validates that MixinCompletionData raises ValidationError when attempting to assign to a frozen instance. Pydantic v2.12.5 (pinned in your project) raises ValidationError with error type frozen_instance and message text containing "frozen" when assigning to a frozen model field, making the match="frozen" assertion reliable.

This approach is consistent with existing frozen model tests across your codebase (e.g., test_compute_models.py, test_model_service.py). No changes required.

For future reference, you could optionally assert on the error type directly (exc.value.errors()[0]["type"] == "frozen_instance") for slightly more precision, but this is not necessary given the message text is stable.

src/omnibase_core/models/compute/model_compute_step_metadata.py (1)

1-77: LGTM! Well-structured immutable metadata model.

The model correctly implements:

  • Immutability via frozen=True for thread safety
  • extra="forbid" for strict validation
  • Proper constraint on duration_ms with ge=0
  • Clear documentation with thread safety notes and examples
docs/architecture/CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md (1)

1-935: Comprehensive v1.0 specification document - good overall structure.

The document effectively covers:

  • Clear design principles and scope boundaries
  • Detailed model definitions with validation rules
  • Well-defined execution semantics (abort-on-first-failure, path resolution)
  • Explicit roadmap for deferred features (v1.1, v1.2)
  • Actionable acceptance criteria

The previous review comments regarding ModelValidationStepConfig naming and version alignment have been addressed.

src/omnibase_core/models/compute/model_compute_pipeline_result.py (2)

53-122: LGTM! Well-documented pipeline result model.

The model correctly implements:

  • Comprehensive field documentation with success/failure semantics
  • Immutability via frozen=True for thread safety
  • extra="forbid" for strict validation
  • processing_time_ms with ge=0 constraint
  • Proper forward reference typing for step_results

125-130: Forward reference resolution pattern is correct and necessary.

The runtime import with model_rebuild() at lines 126-130 is the correct approach for Pydantic 2.x when using from __future__ import annotations with TYPE_CHECKING. Since the field step_results: dict[str, "ModelComputeStepResult"] needs the actual class available at runtime for proper model schema resolution, the deferred import and explicit rebuild are necessary and idiomatic. No circular import issues exist; the dependency chain is clean (pipeline_result → step_result → step_metadata).

tests/integration/test_compute_pipeline_integration.py (8)

1-56: LGTM! Well-organized imports and module docstring.

The imports are properly organized with standard library, third-party (pytest), and local imports separated. The module docstring clearly describes the test coverage scope.


58-66: Good test class structure with appropriate markers.

The class correctly uses:

  • @pytest.mark.integration for integration test categorization
  • @pytest.mark.timeout(60) to prevent test hangs (per coding guidelines)
  • Clear class docstring explaining the fixture usage

67-118: LGTM! Solid multi-step pipeline test.

Good coverage of sequential execution verification including step order and final output correctness.


680-827: LGTM! Comprehensive error scenario coverage.

Tests properly verify:

  • Invalid regex pattern handling
  • Missing mapping path detection
  • Nonexistent step reference failures
  • Type mismatch propagation in middle of pipeline

All tests correctly verify that error_step and error_message are populated on failure.


1430-1437: Good: Extended timeout for concurrency tests.

The 120-second timeout appropriately accounts for concurrent execution overhead. The test class docstring correctly explains this.


1439-1494: LGTM! Well-designed concurrency test.

The test correctly:

  • Creates fresh context for each execution (line 1477)
  • Uses frozen/immutable contract (safe to share across threads)
  • Collects results from all futures before assertions
  • Verifies each execution produces correct output for its input

This aligns with the coding guidelines note about thread safety for immutable models.


1702-1742: LGTM! Good coverage of null and empty value handling.

The test comprehensively covers:

  • None input
  • Empty strings, lists, and dicts
  • Nested structures with null/empty values

This ensures the identity transformation handles edge cases correctly.


1781-1782: LGTM! Standard pytest entry point.

The if __name__ == "__main__" block allows running tests directly via python test_compute_pipeline_integration.py -v.

…N-465]

Address all remaining PR #115 review issues for release-ready state:

## Critical & Major Fixes
- Add pytest markers (@pytest.mark.unit) to 20+ test classes
- Fix error labels: transformation_error → compute_error
- Add ge=0 constraint to duration_ms and processing_duration_ms fields
- Fix node_id=None serialization to avoid "None" string output
- Align transform_identity signature with other handlers
- Simplify IDENTITY transformation special case

## Test Improvements
- Replace generic Exception with ValidationError/OnexError in tests
- Create shared fixture for CLI command tests (conftest.py)
- Update frozen model tests to use specific exception types

## Documentation
- Document $input alias and path resolution semantics
- Document global state limitation with TODO(v1.1)
- Add EBNF grammar for path expressions

## New Files
- src/omnibase_core/utils/compute_path_resolver.py - Shared path resolution utility
- tests/unit/utils/test_compute_path_resolver.py - 63 comprehensive tests
- tests/unit/models/core/conftest.py - Shared test fixtures

## Linear Tickets Created
- OMN-497: Global state refactor
- OMN-498: Error type enum
- OMN-499: DRY path resolution
- OMN-500: Schema validation
- OMN-501: Timeout enforcement
- OMN-502: Structured logging
- OMN-503: TransformationError

All tests pass, mypy --strict shows 0 errors.
@claude

claude Bot commented Dec 7, 2025

Copy link
Copy Markdown

Code Review: Contract-Driven NodeCompute v1.0

I've completed a comprehensive review of this PR. Overall, this is exceptionally well-designed and implemented foundational work. The code demonstrates strong architectural principles, comprehensive testing, and excellent documentation.


✅ Strengths

1. Excellent Architecture & Design Principles

  • ✅ Clear separation of concerns: pure transformation functions, executor, and mixin integration
  • ✅ Thread-safe by design: All transformation and executor functions are pure and stateless
  • ✅ Immutability enforced: All models use frozen=True for future parallel execution safety
  • ✅ Strong typing: Full mypy strict compliance with comprehensive type annotations
  • ✅ Follows ONEX conventions: protocol-based DI, structured errors with ModelOnexError

2. Code Quality

  • ✅ Excellent documentation: Every function has detailed docstrings with thread safety notes, examples, and edge case documentation
  • ✅ Security-conscious: Private attribute access blocked (_attribute) to prevent internal state exposure
  • ✅ Error handling: Comprehensive error context with structured ModelOnexError usage throughout
  • ✅ DRY principle: _validate_string_input() helper reduces code duplication
  • ✅ Observability: Structured logging with operation_id, correlation_id, step timings

3. Testing

  • ✅ 95 unit tests covering all transformation types, edge cases, and error conditions
  • ✅ Integration tests for full pipeline execution
  • ✅ Tests include positive cases, negative cases, and boundary conditions
  • ✅ Test coverage for security features (private attribute blocking)

4. Documentation

  • ✅ Comprehensive specification: CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md provides complete v1.0 spec
  • ✅ Clear versioning roadmap: Deferred features (caching, parallelism) documented with rationale
  • ✅ Example contract: user_profile_normalizer.yaml demonstrates all features with annotations
  • ✅ Inline TODOs reference future work items with Linear ticket numbers

⚠️ Issues to Address

1. Global Mutable State (Minor)

Location: src/omnibase_core/utils/compute_executor.py:59

_validation_warning_emitted = False  # Global mutable state

Issue: Violates the "pure and stateless" principle documented in the module header.

Impact: Low - only affects warning output, not computation results. However, in multithreaded contexts, this could lead to race conditions where the warning is emitted multiple times.

Recommendation:

# Option 1: Use threading.local() for thread-safe warning tracking
import threading
_validation_warnings = threading.local()

# Option 2: Move to context-based tracking (as noted in TODO OMN-497)
# Option 3: Accept this as technical debt and document it clearly ✅ (already done)

Verdict: This is acceptable for v1.0 given the TODO and clear documentation. Address in v1.1 as planned.


2. Code Duplication: Path Resolution Logic

Locations:

  • compute_executor.py:122-255 (resolve_mapping_path)
  • compute_transformations.py:367-471 (transform_json_path)

Issue: Both functions implement similar dot-notation path traversal with slight variations. The TODO comments acknowledge this:

  • OMN-499 in compute_executor.py:117
  • OMN-499 in compute_transformations.py:361

Recommendation:

  • ✅ Acceptable for v1.0 - The TODO references compute_path_resolver.py which exists
  • Consolidate in v1.1 to use shared resolve_pipeline_path() from compute_path_resolver.py

3. Missing Timeout Enforcement

Location: compute_executor.py:433-435

# TODO(OMN-501): Enforce pipeline_timeout_ms - currently declared but not enforced.

Issue: ModelComputeSubcontract.pipeline_timeout_ms is declared but never checked during execution.

Security/Reliability Impact: Pipelines can run indefinitely, potentially causing DoS or resource exhaustion.

Recommendation:

import asyncio
import signal

async def execute_compute_pipeline_with_timeout(contract, input_data, context):
    timeout_ms = contract.pipeline_timeout_ms
    if timeout_ms:
        timeout_sec = timeout_ms / 1000
        try:
            return await asyncio.wait_for(
                asyncio.to_thread(execute_compute_pipeline, contract, input_data, context),
                timeout=timeout_sec
            )
        except asyncio.TimeoutError:
            raise ModelOnexError(
                error_code=EnumCoreErrorCode.TIMEOUT_ERROR,
                message=f"Pipeline execution exceeded timeout of {timeout_ms}ms"
            )
    else:
        return execute_compute_pipeline(contract, input_data, context)

Verdict: This is critical for production use but acceptable to defer to v1.1 if v1.0 is internal/MVP only.


4. Validation Step is Incomplete (By Design)

Location: compute_executor.py:304-368 (execute_validation_step)

# v1.0: Pass through data (schema validation deferred)
return data

Issue: VALIDATION step type exists but performs no actual validation - it's a no-op pass-through.

Concerns:

  • Users might assume validation is happening when it's not
  • Security risk if contracts rely on schema validation for input sanitization
  • The warning is only emitted once per session, so users might miss it

Recommendation:

  1. ✅ UserWarning is good - but consider making it more prominent
  2. Consider raising an error in v1.0 instead of silently passing through:
raise ModelOnexError(
    error_code=EnumCoreErrorCode.NOT_IMPLEMENTED,
    message="VALIDATION step type is not yet implemented. Use v1.1 for schema validation."
)
  1. OR document very clearly in contracts that VALIDATION is a placeholder

Verdict: Current approach is acceptable if this is clearly documented in user-facing docs. Consider renaming to VALIDATION_PLACEHOLDER for v1.0 clarity.


5. Inconsistent Error Types (v1.0 Limitation)

Location: Multiple files use string error types instead of enums

error_type="unexpected_error"  # String literal
error_type="compute_error"      # String literal

Issue: Error types are strings in v1.0, not typed enums. This makes error handling fragile:

  • Typos won't be caught by type checker
  • No IDE autocomplete for error type checking
  • Difficult to enumerate all possible error types

Recommendation:

  • This is noted as deferred to v1.1 in the spec ✅
  • For v1.0, document all possible string error types in a comment or constant:
# v1.0 Error Types (will be EnumComputeErrorType in v1.1)
ERROR_TYPE_COMPUTE_ERROR = "compute_error"
ERROR_TYPE_UNEXPECTED_ERROR = "unexpected_error"
ERROR_TYPE_VALIDATION_ERROR = "validation_error"
# etc.

🎯 Best Practices Observations

✅ Security

  • Private attribute blocking prevents accidental exposure of internal state
  • Path expressions validated before traversal
  • Regex error handling prevents injection via invalid patterns
  • Structured error messages don't leak sensitive data

✅ Performance

  • Pure functions enable future parallelization
  • Frozen models prevent accidental mutations
  • Minimal object allocations in hot paths
  • Step timing captured for profiling

✅ Maintainability

  • Clear module boundaries (transformations, executor, mixin)
  • Comprehensive inline documentation
  • Future work tracked with Linear tickets in TODOs
  • Version roadmap prevents feature creep

📊 Test Coverage Assessment

Based on test file review:

  • ✅ All 6 transformation types have unit tests
  • ✅ Edge cases covered (empty strings, invalid types, private attributes)
  • ✅ Error conditions tested (invalid regex, missing keys, type mismatches)
  • ✅ Integration tests for full pipeline execution
  • ✅ Path resolution thoroughly tested

Recommendation: Add tests for:

  1. Concurrent execution - Verify thread safety claims
  2. Large pipelines - 50+ steps to test abort-on-first-failure
  3. Memory limits - Very large input data (e.g., 10MB JSON)

🚀 Recommendations for v1.0 Ship Criteria

Must Fix Before Merge:

  1. ❌ CI failures - Code Quality and Documentation Validation are failing
  2. ⚠️ VALIDATION step - Either implement basic validation OR raise NotImplementedError

Should Fix (but can defer to v1.1):

  1. ⚠️ Timeout enforcement - Critical for production, but OK to defer if v1.0 is internal
  2. 📝 Path resolution consolidation - Already tracked in OMN-499

Nice to Have:

  1. 📝 Error type constants - Document string error types for v1.0
  2. 🧵 Thread safety tests - Verify pure function claims empirically

🎉 Summary

This is production-quality foundational work with excellent architecture, comprehensive testing, and clear documentation. The v1.0 scope is appropriately minimal and the roadmap for future enhancements is well-reasoned.

Recommendation: APPROVE with minor revisions

Action Items:

  1. ✅ Fix CI failures (Code Quality + Documentation)
  2. ⚠️ Decide on VALIDATION step behavior (implement basic validation OR raise NotImplementedError)
  3. 📝 Document that pipeline_timeout_ms is not enforced in v1.0
  4. 📝 Consider adding error type constants for v1.0 string literals

Code Quality: ⭐⭐⭐⭐⭐ (5/5)
Architecture: ⭐⭐⭐⭐⭐ (5/5)
Testing: ⭐⭐⭐⭐☆ (4/5) - Missing thread safety tests
Documentation: ⭐⭐⭐⭐⭐ (5/5)
Security: ⭐⭐⭐⭐☆ (4/5) - Timeout enforcement needed

Overall: ⭐⭐⭐⭐⭐ (5/5) - Exceptional work!


Review conducted by Claude Code following omnibase_core CLAUDE.md conventions

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)
tests/unit/contracts/test_model_effect_retry_config.py (1)

175-233: Update exception types in validation tests for consistency with Pydantic behavior.

All five fields (max_attempts, base_delay_ms, max_delay_ms, circuit_breaker_threshold, circuit_breaker_timeout_s) use identical Pydantic Field validation with ge=1 constraint. Lines 183–210 incorrectly expect generic Exception for the first three fields, while lines 217–232 correctly expect ValidationError for the last two. Pydantic field constraints raise ValidationError, not generic Exception.

Update lines 183, 186, 194, 197, 206, and 209 to expect ValidationError instead of Exception to match actual Pydantic behavior and maintain test consistency across all minimum-value validations.

🧹 Nitpick comments (13)
tests/unit/nodes/test_rollback_failure_handling.py (1)

27-357: Add timeout markers to prevent test hangs.

All async test methods should include @pytest.mark.timeout() markers to prevent potential hangs during CI execution, as specified in the coding guidelines.

As per coding guidelines, add timeout markers to all async test methods. For example:

+    @pytest.mark.timeout(60)
     @pytest.mark.asyncio
     async def test_rollback_returns_success_when_all_operations_succeed(self):

Apply this pattern to all 10 async test methods in both test classes.

tests/unit/models/security/test_model_permission.py (1)

1-27: Consider adding pytest markers and timeout to align with test guidelines

Given this is a unit test module, you may want to add a module- or class-level @pytest.mark.unit and @pytest.mark.timeout(...) (or ensure they’re applied via shared fixtures/config) to match the stated testing guidelines, even though these tests are fast in practice.

src/omnibase_core/models/operations/model_event_metadata.py (1)

72-76: ModelEventMetadata remains mutable; consider alignment with immutable‑model guideline

Unrelated to this field change, ModelEventMetadata is still mutable (validate_assignment=True and execute() mutating via setattr), which diverges from the guideline that models under src/omnibase_core/models should be immutable after creation for thread safety. If this model is used across threads or shared widely, consider a future refactor toward immutability (e.g., frozen=True/no in‑place mutation, using model_copy(update=...) instead), or explicitly document this as an intentional exception so consumers know it is safe to mutate.

Also applies to: 80-88

tests/unit/models/core/conftest.py (2)

19-23: default_version fixture is simple and correct; optionally add a return type

The fixture is clear and does exactly what tests need. To better align with the “all functions annotated”/strict-typing guideline, you could give it an explicit return type:

-@pytest.fixture
-def default_version():
+@pytest.fixture
+def default_version() -> ModelSemVer:
     """Provide default SemVer version for tests."""
     return ModelSemVer(major=1, minor=0, patch=0)

This keeps usage unchanged while making the type obvious to readers and future mypy runs, should you extend checking to tests as well. As per coding guidelines, this helps maintain strict typing consistency.


25-55: create_test_command factory fixture looks good; consider typing its interface

The factory pattern and default values are solid and make tests concise. To make the fixture’s contract explicit and keep type discipline consistent with the rest of the project, you could:

  1. Annotate the fixture’s parameter and return type.
  2. Import Callable for the factory type.

Example:

from collections.abc import Callable  # near the other imports
-@pytest.fixture
-def create_test_command(default_version):
+@pytest.fixture
+def create_test_command(
+    default_version: ModelSemVer,
+) -> Callable[[str, str, str], ModelCliCommandDefinition]:
@@
-    def _create(
-        command_name: str, node_name: str, category: str = "general"
-    ) -> ModelCliCommandDefinition:
+    def _create(
+        command_name: str,
+        node_name: str,
+        category: str = "general",
+    ) -> ModelCliCommandDefinition:
         return ModelCliCommandDefinition(
             version=default_version,
             command_name=command_name,
             target_node=ModelNodeReference.create_local(node_name),
             action=command_name,
             description=f"Test command {command_name}",
             event_type=ModelEventType(
                 schema_version=default_version,
                 event_name="NODE_START",
                 namespace="onex",
                 description="Test event",
             ),
             category=category,
         )

This keeps the runtime behavior identical while making the fixture’s shape explicit for anyone reading or type-checking tests. As per coding guidelines, it prepares you for stricter mypy coverage over tests if you choose to enable it later.

tests/unit/nodes/test_retry_count_tracking.py (1)

35-36: Consider adding @pytest.mark.timeout() to async tests.

Per coding guidelines, async tests should have timeout protection to prevent CI hangs. These tests involve file I/O and async operations.

+    @pytest.mark.timeout(30)
     @pytest.mark.asyncio
     async def test_retry_count_zero_on_success(self, service_effect):

Apply similar timeouts to the other async test methods in this class.

src/omnibase_core/models/common/model_validation_metadata.py (2)

8-11: Consider adding frozen=True for thread safety consistency.

Per coding guidelines, Pydantic models should be immutable after creation for thread safety. Other models in this PR (e.g., ModelComputeStepMetadata, ModelComputePipelineResult) use frozen=True. Consider aligning this model if immutability is desirable.

-    model_config = ConfigDict(extra="allow")
+    model_config = ConfigDict(extra="allow", frozen=True)

22-25: Consider adding ge=0 to other count fields for consistency.

Since duration_ms now has ge=0, similar non-negative constraints could apply to files_processed, rules_applied, violations_found, etc., as negative counts are semantically invalid.

     files_processed: int | None = Field(
         default=None,
+        ge=0,
         description="Number of files processed during validation",
     )
src/omnibase_core/mixins/mixin_compute_execution.py (1)

187-192: Duplicate step name check is redundant with model validation.

Per ModelComputeSubcontract (see relevant snippets), a field_validator already raises ValueError if duplicate step names exist during model instantiation. Since the contract parameter is typed as ModelComputeSubcontract, it has already passed this validation.

Consider removing this check or documenting that it's intentionally retained for a different error reporting format (list vs. exception).

tests/unit/models/compute/test_compute_models.py (1)

13-348: Good, focused coverage of model invariants

The tests exercise minimal/full construction, immutability, extra-field rejection, and non-negative constraints across all compute result models and metadata. This gives solid confidence in the Pydantic config (extra="forbid", frozen=True, ge=0) and how these models will behave in pipelines. If you ever want to trim duplication, the negative-duration / negative-processing-time tests could be parameterized, but that’s optional.

src/omnibase_core/utils/compute_path_resolver.py (1)

317-329: Preserve original path in error context and align input-path error message

Two small polish points:

  1. In resolve_path (Line 317+), path is mutated when stripping leading "$." / "$", and that normalized value is then passed into _traverse_path_segments. This means error messages and PathResolutionError.path won’t reflect the exact user-supplied expression (e.g. "$.user.name" becomes "user.name"). Consider preserving an original_path and passing that into _traverse_path_segments for clearer diagnostics:
-def resolve_path(
-    path: str,
+def resolve_path(
+    path: str,
     data: Any,
     *,
     check_private: bool = True,
 ) -> Any:
@@
-    # Handle root-level access
-    if not path or path == "$":
-        return data
-
-    # Normalize path: remove leading "$." or "$" if present
-    if path.startswith("$."):
-        path = path[2:]
-    elif path.startswith("$"):
-        path = path[1:]
-
-    # Split path and traverse
-    parts = path.split(".")
-    return _traverse_path_segments(data, parts, path, check_private=check_private)
+    original_path = path
+    if not path or path == "$":
+        return data
+
+    if path.startswith("$."):
+        path = path[2:]
+    elif path.startswith("$"):
+        path = path[1:]
+
+    parts = path.split(".")
+    return _traverse_path_segments(
+        data,
+        parts,
+        original_path,
+        check_private=check_private,
+    )
  1. In resolve_input_path (Lines 371–381), invalid-path errors currently say:

Expected '$.input' or '$.input.<field>'

but the implementation also supports the $input alias. Updating the message to mention $input as well would make the error text accurately reflect the accepted forms.

Also applies to: 371-381

src/omnibase_core/utils/compute_executor.py (1)

117-255: Reduce duplication by delegating to compute_path_resolver.resolve_pipeline_path

resolve_mapping_path re-implements path parsing and traversal that now lives in omnibase_core.utils.compute_path_resolver (with richer error context via PathResolutionError). There’s already a TODO (OMN-499); given the new shared utility is in place, it’s worth collapsing this sooner rather than later to avoid drift.

A minimal approach would be:

  • Import resolve_pipeline_path and PathResolutionError.
  • Wrap resolve_pipeline_path and translate PathResolutionError into ModelOnexError once, preserving error codes and messages.

For example (sketch only):

-from omnibase_core.enums.enum_core_error_code import EnumCoreErrorCode
+from omnibase_core.enums.enum_core_error_code import EnumCoreErrorCode
+from omnibase_core.utils.compute_path_resolver import (
+    PathResolutionError,
+    resolve_pipeline_path,
+)
@@
 def resolve_mapping_path(
     path: str,
     input_data: Any,
     step_results: dict[str, ModelComputeStepResult],
 ) -> Any:
@@
-    if not path.startswith("$"):
-        raise ModelOnexError(
-            error_code=EnumCoreErrorCode.VALIDATION_ERROR,
-            message=f"Invalid path: must start with '$', got '{path}'",
-        )
-    ...
-    raise ModelOnexError(
-        error_code=EnumCoreErrorCode.VALIDATION_ERROR,
-        message=f"Invalid path prefix: '{path}'. Must be '$.input' or '$.steps.<name>'",
-    )
+    try:
+        # Step results dict holds ModelComputeStepResult; resolver returns either
+        # the raw output or the object’s `.output` depending on configuration.
+        return resolve_pipeline_path(path, input_data, step_results)
+    except PathResolutionError as e:
+        # Preserve error_code and message, just normalize type to ModelOnexError
+        raise ModelOnexError(
+            error_code=e.error_code or EnumCoreErrorCode.OPERATION_FAILED,
+            message=e.message,
+            context=e.context,
+        ) from e

That keeps the compute executor’s public surface the same while centralizing path semantics and error-context behavior in one place.

src/omnibase_core/utils/compute_transformations.py (1)

361-371: Delegate JSON_PATH traversal to the shared resolver to avoid drift

transform_json_path re-implements simple dot-notation traversal that is now centralized in compute_path_resolver.resolve_path. There’s already a TODO (OMN-499); wiring it up now would reduce duplication and keep JSON_PATH semantics in sync with other path consumers.

A minimal change could be:

-from omnibase_core.models.transformations.model_transform_json_path_config import (
-    ModelTransformJsonPathConfig,
-)
+from omnibase_core.models.transformations.model_transform_json_path_config import (
+    ModelTransformJsonPathConfig,
+)
+from omnibase_core.utils.compute_path_resolver import resolve_path, PathResolutionError
@@
-def transform_json_path(
-    data: Any,
-    config: ModelTransformJsonPathConfig,
-) -> Any:
-    ...
-    path = config.path
-    # Handle root-level access, normalization, and traversal manually...
-    ...
-    return current
+def transform_json_path(
+    data: Any,
+    config: ModelTransformJsonPathConfig,
+) -> Any:
+    """
+    Extract data using simple JSONPath-like path notation.
+
+    Delegates traversal to `resolve_path` to share semantics with other
+    path-based operations (e.g., mapping steps).
+    """
+    try:
+        return resolve_path(config.path, data)
+    except PathResolutionError as e:
+        # Re-wrap as ModelOnexError to keep transformation-layer error type stable
+        raise ModelOnexError(
+            error_code=e.error_code or EnumCoreErrorCode.OPERATION_FAILED,
+            message=e.message,
+            context=e.context,
+        ) from e

This keeps the transformation’s external behavior (raising ModelOnexError with appropriate codes) while ensuring path semantics and edge cases remain consistent with the shared resolver.

Also applies to: 413-471

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9601d77 and 0abac04.

📒 Files selected for processing (27)
  • docs/architecture/CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md (1 hunks)
  • src/omnibase_core/infrastructure/node_base.py (1 hunks)
  • src/omnibase_core/mixins/mixin_compute_execution.py (1 hunks)
  • src/omnibase_core/models/common/model_validation_metadata.py (1 hunks)
  • src/omnibase_core/models/operations/model_event_metadata.py (1 hunks)
  • src/omnibase_core/utils/compute_executor.py (1 hunks)
  • src/omnibase_core/utils/compute_path_resolver.py (1 hunks)
  • src/omnibase_core/utils/compute_transformations.py (1 hunks)
  • tests/unit/container/test_container_service_resolver.py (6 hunks)
  • tests/unit/container/test_service_registry.py (2 hunks)
  • tests/unit/contracts/test_model_effect_retry_config.py (2 hunks)
  • tests/unit/core/test_model_base_factory.py (2 hunks)
  • tests/unit/models/compute/test_compute_models.py (1 hunks)
  • tests/unit/models/core/conftest.py (1 hunks)
  • tests/unit/models/core/test_model_container.py (3 hunks)
  • tests/unit/models/health/test_model_health_check.py (3 hunks)
  • tests/unit/models/health/test_model_health_metric.py (2 hunks)
  • tests/unit/models/health/test_model_health_status.py (5 hunks)
  • tests/unit/models/security/test_model_permission.py (2 hunks)
  • tests/unit/nodes/test_retry_count_tracking.py (1 hunks)
  • tests/unit/nodes/test_rollback_failure_handling.py (2 hunks)
  • tests/unit/test_init_exports.py (7 hunks)
  • tests/unit/utils/test_compute_path_resolver.py (1 hunks)
  • tests/unit/utils/test_compute_pipeline.py (1 hunks)
  • tests/unit/utils/test_field_converter.py (1 hunks)
  • tests/unit/validation/test_contracts.py (2 hunks)
  • tests/unit/validation/test_contracts_extended.py (4 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Always use Poetry for Python package management and task execution. Use poetry run for pytest, mypy, black, isort, and other tools. Never use pip directly or execute python commands without the poetry run prefix.
Enforce 100% strict mypy compliance. All functions must have complete type annotations. Use poetry run mypy src/omnibase_core/ to verify strict mode compliance with no errors.
Format code with black, sort imports with isort, and lint with ruff. Run poetry run black src/ tests/, poetry run isort src/ tests/, and poetry run ruff check --fix src/ tests/

Files:

  • tests/unit/contracts/test_model_effect_retry_config.py
  • src/omnibase_core/infrastructure/node_base.py
  • tests/unit/models/health/test_model_health_check.py
  • tests/unit/models/core/conftest.py
  • tests/unit/utils/test_field_converter.py
  • src/omnibase_core/utils/compute_path_resolver.py
  • tests/unit/validation/test_contracts_extended.py
  • tests/unit/nodes/test_rollback_failure_handling.py
  • tests/unit/test_init_exports.py
  • src/omnibase_core/models/operations/model_event_metadata.py
  • tests/unit/container/test_container_service_resolver.py
  • tests/unit/models/core/test_model_container.py
  • tests/unit/container/test_service_registry.py
  • tests/unit/models/health/test_model_health_metric.py
  • tests/unit/validation/test_contracts.py
  • tests/unit/nodes/test_retry_count_tracking.py
  • src/omnibase_core/utils/compute_transformations.py
  • tests/unit/core/test_model_base_factory.py
  • src/omnibase_core/mixins/mixin_compute_execution.py
  • tests/unit/models/security/test_model_permission.py
  • src/omnibase_core/models/common/model_validation_metadata.py
  • src/omnibase_core/utils/compute_executor.py
  • tests/unit/models/health/test_model_health_status.py
  • tests/unit/utils/test_compute_path_resolver.py
  • tests/unit/utils/test_compute_pipeline.py
  • tests/unit/models/compute/test_compute_models.py
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Write tests using pytest with async support via pytest-asyncio. Maintain minimum 60% code coverage. Use pytest markers: @pytest.mark.unit, @pytest.mark.integration, @pytest.mark.slow
Add @pytest.mark.timeout() to prevent test hangs. Run tests with poetry run pytest tests/ --timeout=60 for 60-second timeout protection.

Files:

  • tests/unit/contracts/test_model_effect_retry_config.py
  • tests/unit/models/health/test_model_health_check.py
  • tests/unit/models/core/conftest.py
  • tests/unit/utils/test_field_converter.py
  • tests/unit/validation/test_contracts_extended.py
  • tests/unit/nodes/test_rollback_failure_handling.py
  • tests/unit/test_init_exports.py
  • tests/unit/container/test_container_service_resolver.py
  • tests/unit/models/core/test_model_container.py
  • tests/unit/container/test_service_registry.py
  • tests/unit/models/health/test_model_health_metric.py
  • tests/unit/validation/test_contracts.py
  • tests/unit/nodes/test_retry_count_tracking.py
  • tests/unit/core/test_model_base_factory.py
  • tests/unit/models/security/test_model_permission.py
  • tests/unit/models/health/test_model_health_status.py
  • tests/unit/utils/test_compute_path_resolver.py
  • tests/unit/utils/test_compute_pipeline.py
  • tests/unit/models/compute/test_compute_models.py
src/omnibase_core/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/omnibase_core/**/*.py: Use protocol names with container.get_service() for dependency injection, never resolve services by concrete class names. Example: container.get_service('ProtocolEventBus') instead of container.get_service('EventBusService')
Always use ModelONEXContainer for dependency injection in node constructors and service resolution. Never confuse it with ModelContainer[T], which is a generic value wrapper, not a DI container.
Use structured error handling with ModelOnexError and EnumCoreErrorCode, never raise generic Exception. Always chain exceptions with from e when catching and re-raising.
Use the @standard_error_handling decorator on methods to eliminate 6+ lines of try/catch boilerplate. Example: @standard_error_handling above async methods.
Respect thread safety constraints: Do NOT share node instances (NodeCompute, NodeEffect), cache, or circuit breaker instances across threads without synchronization. Use thread-local instances or locks.
Use duck typing with protocols. Do not use isinstance checks with protocol types. Rely on the protocol interface directly.
Use EnumNodeKind for high-level architectural classification (EFFECT, COMPUTE, REDUCER, ORCHESTRATOR) when routing data through the ONEX pipeline. Use EnumNodeType for specific implementation discovery and capability matching.
Use ModelEventEnvelope for inter-service event-driven communication. Process events through the envelope pattern for consistent event handling.

Files:

  • src/omnibase_core/infrastructure/node_base.py
  • src/omnibase_core/utils/compute_path_resolver.py
  • src/omnibase_core/models/operations/model_event_metadata.py
  • src/omnibase_core/utils/compute_transformations.py
  • src/omnibase_core/mixins/mixin_compute_execution.py
  • src/omnibase_core/models/common/model_validation_metadata.py
  • src/omnibase_core/utils/compute_executor.py
src/omnibase_core/models/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Use Pydantic 2.11+ models for all data validation and serialization. Ensure models are immutable after creation for thread safety.

Files:

  • src/omnibase_core/models/operations/model_event_metadata.py
  • src/omnibase_core/models/common/model_validation_metadata.py
src/omnibase_core/mixins/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Mixin classes should be composed into node classes for specific capabilities. Available mixins include: MixinDiscoveryResponder, MixinEventHandler, MixinEventListener, MixinNodeExecutor, MixinNodeLifecycle, MixinRequestResponseIntrospection, MixinWorkflowSupport.

Files:

  • src/omnibase_core/mixins/mixin_compute_execution.py
🧠 Learnings (9)
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to tests/**/*.py : Write tests using pytest with async support via pytest-asyncio. Maintain minimum 60% code coverage. Use pytest markers: pytest.mark.unit, pytest.mark.integration, pytest.mark.slow

Applied to files:

  • tests/unit/utils/test_field_converter.py
  • tests/unit/test_init_exports.py
  • tests/unit/container/test_container_service_resolver.py
  • tests/unit/container/test_service_registry.py
  • tests/unit/utils/test_compute_pipeline.py
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/**/*.py : Use structured error handling with ModelOnexError and EnumCoreErrorCode, never raise generic Exception. Always chain exceptions with `from e` when catching and re-raising.

Applied to files:

  • tests/unit/validation/test_contracts_extended.py
  • tests/unit/models/core/test_model_container.py
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/nodes/node_effect.py : NodeEffect is for external interactions (I/O). Inherit from NodeEffect for EFFECT nodes that handle API calls, database operations, file system, or message queues.

Applied to files:

  • tests/unit/nodes/test_rollback_failure_handling.py
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/**/*.py : Use protocol names with `container.get_service()` for dependency injection, never resolve services by concrete class names. Example: `container.get_service('ProtocolEventBus')` instead of `container.get_service('EventBusService')`

Applied to files:

  • tests/unit/container/test_container_service_resolver.py
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/**/*.py : Always use ModelONEXContainer for dependency injection in node constructors and service resolution. Never confuse it with ModelContainer[T], which is a generic value wrapper, not a DI container.

Applied to files:

  • tests/unit/models/core/test_model_container.py
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/models/**/*.py : Use Pydantic 2.11+ models for all data validation and serialization. Ensure models are immutable after creation for thread safety.

Applied to files:

  • tests/unit/core/test_model_base_factory.py
  • src/omnibase_core/models/common/model_validation_metadata.py
  • tests/unit/models/health/test_model_health_status.py
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/mixins/**/*.py : Mixin classes should be composed into node classes for specific capabilities. Available mixins include: MixinDiscoveryResponder, MixinEventHandler, MixinEventListener, MixinNodeExecutor, MixinNodeLifecycle, MixinRequestResponseIntrospection, MixinWorkflowSupport.

Applied to files:

  • src/omnibase_core/mixins/mixin_compute_execution.py
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/nodes/node_compute.py : NodeCompute is for data processing and transformation. Inherit from NodeCompute for COMPUTE nodes that perform calculations, validations, and data mapping.

Applied to files:

  • src/omnibase_core/mixins/mixin_compute_execution.py
  • src/omnibase_core/utils/compute_executor.py
  • docs/architecture/CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to tests/**/*.py : Add pytest.mark.timeout() to prevent test hangs. Run tests with `poetry run pytest tests/ --timeout=60` for 60-second timeout protection.

Applied to files:

  • tests/unit/utils/test_compute_pipeline.py
🧬 Code graph analysis (7)
src/omnibase_core/infrastructure/node_base.py (2)
src/omnibase_core/mixins/mixin_event_driven_node.py (1)
  • node_id (124-126)
src/omnibase_core/mixins/mixin_node_setup.py (1)
  • node_id (67-68)
tests/unit/models/health/test_model_health_check.py (1)
src/omnibase_core/models/infrastructure/model_timeout.py (1)
  • timeout_seconds (231-233)
src/omnibase_core/utils/compute_path_resolver.py (1)
src/omnibase_core/enums/enum_core_error_code.py (1)
  • EnumCoreErrorCode (9-154)
src/omnibase_core/utils/compute_transformations.py (11)
src/omnibase_core/enums/enum_case_mode.py (1)
  • EnumCaseMode (10-22)
src/omnibase_core/enums/enum_core_error_code.py (1)
  • EnumCoreErrorCode (9-154)
src/omnibase_core/enums/enum_regex_flag.py (1)
  • EnumRegexFlag (10-22)
src/omnibase_core/enums/enum_transformation_type.py (1)
  • EnumTransformationType (11-34)
src/omnibase_core/enums/enum_trim_mode.py (1)
  • EnumTrimMode (10-22)
src/omnibase_core/enums/enum_unicode_form.py (1)
  • EnumUnicodeForm (10-24)
src/omnibase_core/models/transformations/model_transform_case_config.py (1)
  • ModelTransformCaseConfig (15-27)
src/omnibase_core/models/transformations/model_transform_json_path_config.py (1)
  • ModelTransformJsonPathConfig (13-35)
src/omnibase_core/models/transformations/model_transform_regex_config.py (1)
  • ModelTransformRegexConfig (15-31)
src/omnibase_core/models/transformations/model_transform_trim_config.py (1)
  • ModelTransformTrimConfig (15-27)
src/omnibase_core/models/transformations/model_transform_unicode_config.py (1)
  • ModelTransformUnicodeConfig (15-27)
src/omnibase_core/mixins/mixin_compute_execution.py (4)
src/omnibase_core/models/compute/model_compute_execution_context.py (1)
  • ModelComputeExecutionContext (44-95)
src/omnibase_core/models/compute/model_compute_pipeline_result.py (1)
  • ModelComputePipelineResult (53-122)
src/omnibase_core/models/contracts/subcontracts/model_compute_subcontract.py (1)
  • ModelComputeSubcontract (73-181)
src/omnibase_core/utils/compute_executor.py (1)
  • execute_compute_pipeline (436-648)
src/omnibase_core/utils/compute_executor.py (6)
src/omnibase_core/enums/enum_compute_step_type.py (1)
  • EnumComputeStepType (50-91)
src/omnibase_core/enums/enum_core_error_code.py (1)
  • EnumCoreErrorCode (9-154)
src/omnibase_core/models/compute/model_compute_execution_context.py (1)
  • ModelComputeExecutionContext (44-95)
src/omnibase_core/models/compute/model_compute_pipeline_result.py (1)
  • ModelComputePipelineResult (53-122)
src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py (1)
  • ModelComputePipelineStep (81-200)
src/omnibase_core/models/contracts/subcontracts/model_compute_subcontract.py (1)
  • ModelComputeSubcontract (73-181)
tests/unit/utils/test_compute_path_resolver.py (1)
src/omnibase_core/utils/compute_path_resolver.py (5)
  • PathResolutionError (98-138)
  • resolve_input_path (332-384)
  • resolve_path (272-329)
  • resolve_pipeline_path (487-551)
  • resolve_step_path (387-484)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Smoke Tests
  • GitHub Check: claude-review
🔇 Additional comments (49)
tests/unit/models/core/test_model_container.py (3)

176-187: Aligning map failure expectations with OnexError is correct

Using pytest.raises(OnexError) for test_map_value_failure matches the standardized error model and keeps the existing message assertion intact. No further changes needed.


199-209: Validation failure test now correctly targets OnexError

Expecting OnexError for test_validate_with_failure is consistent with the project’s error-handling approach and with other tests in this module. The assertions on message and container state remain appropriate.


210-225: Validator-exception path correctly asserts OnexError wrapping

Switching test_validate_with_exception_in_validator to pytest.raises(OnexError) is aligned with the design where validator crashes are surfaced via OnexError, while still checking that the wrapped message contains the original ValueError text. Looks good.

tests/unit/container/test_service_registry.py (2)

37-38: Unit marker on TestServiceRegistry is appropriate

Tagging this test class with @pytest.mark.unit cleanly classifies the suite without changing behavior and aligns with the stated pytest marker conventions.
As per coding guidelines, this follows the preferred test marking approach.


397-398: Unit marker on TestContainerIntegration looks good

Applying @pytest.mark.unit here consistently tags these container–registry interaction tests as unit-level, matching the rest of the suite’s marker strategy.
Based on learnings, this is in line with how tests are expected to be marked.

tests/unit/nodes/test_rollback_failure_handling.py (2)

23-23: LGTM! Correct unit marker addition.

The @pytest.mark.unit marker correctly categorizes this test class and aligns with the project's testing conventions.


158-158: LGTM! Correct unit marker addition.

The @pytest.mark.unit marker correctly categorizes this test class.

tests/unit/models/security/test_model_permission.py (2)

25-27: Importing ValidationError aligns tests with Pydantic semantics

Using from pydantic import ValidationError here is appropriate and keeps the tests asserting against the concrete validation error type instead of a broad exception.


152-160: Narrowing the expected exception to ValidationError is a solid improvement

Switching this test to with pytest.raises(ValidationError): correctly ties the invalid name pattern case to Pydantic’s model validation rather than a generic exception, improving test precision and documenting the intended contract.

tests/unit/container/test_container_service_resolver.py (1)

26-27: Class-level @pytest.mark.unit usage is correct and consistent

Tagging all container resolver test classes with @pytest.mark.unit cleanly categorizes these as unit tests and aligns with the stated pytest marker guidelines. No functional behavior changes are introduced, and the markers look complete and consistent across the file.

Also applies to: 123-125, 204-207, 251-253, 288-291, 335-337

src/omnibase_core/infrastructure/node_base.py (1)

719-731: Initialization failure logging now robust against missing node_id

The updated conditional around node_id in _emit_initialization_failure correctly avoids a secondary AttributeError when initialization fails before self.node_id is set, while still logging the ID when present and non-None. This is a safe robustness improvement with no behavioral regressions evident.

src/omnibase_core/models/operations/model_event_metadata.py (1)

46-50: Non‑negative processing_duration_ms with default 0 looks good; verify no callers relied on negative/None sentinels

The new Field(default=0, ge=0, description="Processing duration") enforces a sane, non‑negative duration and gives a deterministic default, which aligns with the broader pattern for timing fields in the compute models. Please just double‑check that no existing code paths or stored payloads relied on negative or None sentinel values to signal “unknown/not started yet”; if they did, they may need a small normalization step to map those to 0 or another explicit flag (e.g., processed).

tests/unit/contracts/test_model_effect_retry_config.py (1)

397-408: LGTM! Assignment validation correctly expects ValidationError.

The updated test correctly expects ValidationError when assigning an invalid value to max_attempts, which is consistent with Pydantic's validate_assignment=True behavior and matches the pattern used in enum assignment validation tests (lines 167-172).

tests/unit/nodes/test_retry_count_tracking.py (1)

31-32: LGTM! Unit marker added as per coding guidelines.

The @pytest.mark.unit marker is correctly applied to the test class, aligning with the project's test categorization standards.

tests/unit/utils/test_field_converter.py (1)

9-10: LGTM! Unit marker correctly applied.

The @pytest.mark.unit marker is appropriately added to categorize these tests.

tests/unit/validation/test_contracts_extended.py (5)

22-22: LGTM! Appropriate import for precise exception handling.

Adding the ValidationError import enables more specific exception assertions, which is better practice than catching broad exception types.


100-101: LGTM! Precise exception type for Pydantic validation failures.

Using ValidationError instead of a generic exception is correct for testing Pydantic model validation when required fields are missing.


129-130: LGTM! Appropriate multi-exception handling for empty YAML edge case.

Empty YAML strings yield None from yaml.safe_load, which can cause either ValidationError (Pydantic) or TypeError depending on how the model handles None input.


136-138: LGTM! Comprehensive exception handling for whitespace-with-tabs edge case.

The comment correctly explains that tab characters in YAML can trigger scanner errors. The triple exception tuple appropriately covers all possible failure modes.


148-149: LGTM! Correct exception type for null value validation.

ValidationError is the appropriate exception when Pydantic rejects null values for required fields.

src/omnibase_core/models/common/model_validation_metadata.py (1)

17-21: LGTM! Non-negativity constraint correctly applied.

Adding ge=0 to duration_ms ensures validation rejects negative durations, which aligns with the non-negative duration semantics used in other compute models (e.g., ModelComputeStepMetadata).

src/omnibase_core/mixins/mixin_compute_execution.py (5)

1-36: LGTM! Comprehensive module documentation.

Excellent documentation including purpose, thread safety notes, usage examples, and cross-references. This follows best practices for mixin documentation.


91-148: LGTM! Async wrapper with appropriate documentation.

The async wrapper correctly documents that the underlying execution is synchronous (lines 104-107). For compute pipelines that are primarily data transformations, this is acceptable. If pipelines become CPU-intensive, consider using asyncio.to_thread() to avoid blocking the event loop.


194-207: LGTM! Correct forward-reference validation logic.

The path parsing correctly handles:

  • $.steps.<name>.output format with proper prefix removal
  • Skips non-step paths like $.input (line 199 condition)
  • Tracks executed steps incrementally to catch forward references

This is valuable static analysis that catches configuration errors before runtime.


88-89: Type hint documents mixing class contract.

The node_id: UUID declaration correctly documents the expected attribute from the mixing class while allowing the method (line 142) to handle cases where it might be absent via hasattr.


212-214: LGTM! Proper __all__ export.

The mixin is correctly exported for public API access.

docs/architecture/CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md (1)

1-1001: LGTM! Comprehensive and well-structured v1.0 specification.

This specification document is thorough, well-organized, and provides clear guidance for implementation. The design decisions are sound:

  • Sequential-only pipelines with abort-on-first-failure semantics provide a solid foundation
  • Six built-in transformations cover common use cases without over-engineering
  • Immutability guarantees (frozen=True) are properly documented and enforced
  • String-based error types in v1.0 with a clear upgrade path to enums in v1.1+
  • Example contract demonstrates all features correctly

The document successfully balances v1.0 simplicity with clear extensibility for v1.1/v1.2 features.

tests/unit/models/health/test_model_health_metric.py (2)

4-4: LGTM! Import addition improves test specificity.

Adding the explicit ValidationError import from Pydantic enables more precise exception testing.


59-62: LGTM! More specific exception handling.

Updating from generic Exception to ValidationError makes the test more precise and aligns with Pydantic's validation model. This change correctly validates that invalid trend values trigger Pydantic's validation mechanism.

tests/unit/models/health/test_model_health_status.py (2)

7-7: LGTM! Import addition enables precise exception testing.

Adding the explicit ValidationError import from Pydantic supports more specific exception assertions throughout the test suite.


74-108: LGTM! Improved test precision with ValidationError.

These updates correctly expect ValidationError for various validation failures:

  • Invalid status patterns (line 74)
  • Out-of-range health scores (lines 85, 87)
  • Invalid check durations (line 97)
  • Invalid uptime values (line 107)

This aligns with Pydantic's validation model and makes the tests more specific and maintainable.

tests/unit/test_init_exports.py (1)

18-280: LGTM! Proper test categorization with pytest markers.

All test classes now correctly include the @pytest.mark.unit decorator, which enables proper test filtering and categorization. This aligns with the coding guidelines requirement for pytest markers on all test classes.

As per coding guidelines: "Use pytest markers: @pytest.mark.unit, @pytest.mark.integration, @pytest.mark.slow"

tests/unit/validation/test_contracts.py (2)

7-7: LGTM! Import supports refined exception handling.

Adding ValidationError import enables more precise exception testing in YAML loading scenarios.


39-48: LGTM! More precise exception expectations for YAML edge cases.

These updates correctly refine exception handling:

  • Line 39: Empty YAML may raise either ValidationError (Pydantic validation) or TypeError (Python type errors), properly covering both cases
  • Line 47: Invalid YAML syntax correctly expects yaml.YAMLError for parsing failures

This improves test accuracy and reduces false positives.

tests/unit/core/test_model_base_factory.py (2)

9-9: LGTM! Import addition for precise validation testing.

Adding ValidationError to the existing Pydantic imports enables more specific exception assertions in factory validation tests.


232-233: LGTM! Precise exception handling for factory validation.

Updating from a placeholder generic Exception to ValidationError correctly validates that Pydantic's validation mechanism is triggered when invalid data (string instead of float for price) is passed to the factory's create method.

tests/unit/models/health/test_model_health_check.py (2)

4-4: LGTM! Import enables precise validation testing.

Adding ValidationError to the Pydantic imports supports more specific exception assertions for health check validation tests.


164-203: LGTM! Precise validation error expectations.

These updates correctly expect ValidationError for validation failures:

  • Lines 164-175: Invalid HTTP status codes (99 and 600 outside valid 100-599 range)
  • Lines 192-203: Invalid timeouts (0 and 301 outside valid 1-300 range)

This aligns with Pydantic's field validation and makes the tests more specific and maintainable.

tests/unit/utils/test_compute_pipeline.py (10)

1-58: LGTM! Comprehensive imports and proper file header.

The imports correctly cover all necessary enums, models, and utilities for testing the v1.0 NodeCompute pipeline. The docstring clearly identifies this as testing the Contract-Driven NodeCompute v1.0 implementation.


60-80: LGTM! Complete identity transformation tests.

The identity transformation tests correctly verify:

  • Returns input unchanged for various types (string, int, dict, None)
  • Preserves lists and nested structures

This aligns with the v1.0 spec requirement that IDENTITY has no config and passes data through unchanged.


82-133: LGTM! Comprehensive regex transformation tests.

Tests correctly cover:

  • Simple replacement patterns
  • All three regex flags (IGNORECASE, MULTILINE, DOTALL)
  • Error handling for non-string input
  • Error handling for invalid regex patterns

This thoroughly validates the REGEX transformation type from the v1.0 spec.


135-164: LGTM! Complete case transformation tests.

Tests correctly validate all three case modes (UPPER, LOWER, TITLE) and error handling for non-string input and empty strings. Aligns with the CASE_CONVERSION transformation in the v1.0 spec.


166-195: LGTM! Thorough trim transformation tests.

Tests correctly cover all three trim modes (BOTH, LEFT, RIGHT), error handling for non-string input, and edge case of no whitespace. Validates the TRIM transformation type from the v1.0 spec.


197-221: LGTM! Unicode normalization tests.

Tests correctly validate NFC/NFD normalization forms and error handling for non-string input. The composed/decomposed character tests properly exercise the NORMALIZE_UNICODE transformation.


223-257: LGTM! JSONPath extraction tests.

Tests comprehensively cover:

  • Simple field extraction
  • Nested field access
  • Error handling for missing fields
  • Root access with $
  • Deeply nested paths

This validates the JSON_PATH transformation type from the v1.0 spec.


259-297: LGTM! Transformation dispatcher tests.

Tests correctly validate the execute_transformation dispatcher:

  • IDENTITY works without config
  • Non-IDENTITY transformations require config
  • Dispatching to each transformation type works correctly

This ensures the transformation registry pattern works as specified.


299-375: LGTM! Comprehensive path resolution tests.

Tests thoroughly validate resolve_mapping_path for:

  • Full input access ($.input)
  • Input field access ($.input.<field>)
  • Nested input fields
  • Step output access (both explicit .output and shorthand forms)
  • Error cases (invalid prefix, missing fields, missing steps, invalid subpaths)

This aligns with the v1.0 mapping path grammar specified in the contract document.


377-586: LGTM! Comprehensive pipeline execution tests with proper timeout protection.

The pipeline executor tests thoroughly validate:

  • Simple and multi-step pipelines
  • Abort-on-first-failure semantics (line 442-470)
  • Identity transformation in pipelines
  • Disabled step handling
  • Empty pipeline behavior
  • Timing/metadata tracking
  • Regex transformation in pipelines

The @pytest.mark.timeout(30) decorator (line 378) correctly prevents test hangs during pipeline execution, as required by coding guidelines.

As per coding guidelines: "Add @pytest.mark.timeout() to prevent test hangs."

src/omnibase_core/utils/compute_executor.py (1)

436-648: Executor semantics align with v1.0 spec

execute_compute_pipeline correctly implements sequential execution with abort-on-first-failure, records per-step duration and metadata, distinguishes ModelOnexError from unexpected exceptions, and returns an immutable ModelComputePipelineResult with detailed error context. The handling of disabled steps and steps_executed ordering also matches the contract comments.

Comment thread tests/unit/utils/test_compute_path_resolver.py
…MN-465]

- docs: add $input alias documentation, fix code block languages, align versions
- tests: add @pytest.mark.timeout() to all compute test classes
- tests: fix test_path_with_consecutive_dots to use actual consecutive dots
- tests: use specific ValidationError instead of generic Exception
- src: align transform_identity signature with other handlers
- src: add ge=0 constraint to retry_count, document model mutability
- src: add thread safety documentation to NodeBase
- src: improve error message context with original path
@claude

claude Bot commented Dec 7, 2025

Copy link
Copy Markdown

Pull Request Review: Contract-Driven NodeCompute v1.0 [OMN-465]

Overview

This is a well-architected implementation of contract-driven compute pipelines with excellent documentation, comprehensive testing, and strong adherence to the project's coding standards. The PR introduces 10,728 additions across 73 files with a minimal, stable foundation approach that can be safely shipped and extended incrementally.


✅ Strengths

1. Architecture & Design

  • Excellent separation of concerns: Pure transformation functions in compute_transformations.py, stateless executor in compute_executor.py, and clean mixin integration
  • Thread-safe by design: All core functions are pure and stateless (except for the documented global warning deduplication)
  • Immutability enforced: All models use frozen=True for future-proofing parallel execution (v1.2+)
  • Clear versioning strategy: Well-documented roadmap from v1.0 → v1.3 with explicit deferred features
  • Fail-fast philosophy: Schema resolution at load time prevents runtime surprises

2. Code Quality

  • Type safety: Full mypy strict compliance expected (as per project standards)
  • Error handling: Proper use of ModelOnexError with structured error codes and context
  • Documentation: Exceptional inline documentation with thread safety notes, examples, and cross-references
  • Test coverage: 95 unit tests across multiple test files
  • DRY principles: Smart use of helper functions like _validate_string_input()

3. Security

✅ No dangerous patterns found:

  • No eval(), exec(), __import__(), or compile() usage
  • Private attribute access blocked in path resolution (line 210 in compute_executor.py)
  • Regex errors properly caught and wrapped in ModelOnexError
  • Input validation enforced via Pydantic models with extra="forbid"

4. Documentation

  • Three comprehensive architectural documents added
  • Clear examples in docstrings
  • Well-defined scope boundaries (IN vs OUT for v1.0)
  • Real-world example contract (user_profile_normalizer.yaml)

⚠️ Issues & Recommendations

Critical Issues 🔴

1. ReDoS (Regular Expression Denial of Service) Vulnerability

Location: src/omnibase_core/utils/compute_transformations.py:214

Issue: User-provided regex patterns are executed without timeout or complexity limits, allowing malicious patterns like (a+)+ to cause catastrophic backtracking.

Recommendation:
Add regex timeout protection or pattern validation:

  • Option 1: Use Python 3.11+ timeout parameter (if available)
  • Option 2: Add pattern complexity validation (max length, forbidden patterns)
  • Option 3: Add per-transformation timeout wrapper

Reference: OWASP ReDoS


2. Global Mutable State in Pure Function Module

Location: src/omnibase_core/utils/compute_executor.py:59

Issue: Module-level mutable state breaks the "pure and stateless" contract:

_validation_warning_emitted = False  # Global mutable state

Recommendation: Use context-based warning tracking or per-execution state. Already tracked as TODO(OMN-497), but should be prioritized for v1.0 GA.


Major Issues 🟡

3. Missing Timeout Enforcement

Location: src/omnibase_core/utils/compute_executor.py:442

Issue: The pipeline_timeout_ms field is defined in the contract but not enforced in the executor. There's a TODO(OMN-498) comment but no implementation.

Impact: Pipelines can run indefinitely, causing resource exhaustion.

Recommendation: Implement timeout enforcement before v1.0 GA using signal.alarm, threading.Timer, or asyncio.timeout depending on execution context.


4. Input Size Limits Missing

Issue: No limits on input data size, allowing potential memory exhaustion attacks.

Recommendation: Add MAX_INPUT_SIZE validation (e.g., 10MB) and MAX_PIPELINE_STEPS limits at the start of execute_compute_pipeline().


5. Path Traversal in JSONPath Resolution

Location: src/omnibase_core/utils/compute_executor.py:200-221

Issue: While private attributes are blocked (good!), there's potential for traversing into unintended object graphs.

Additional Recommendation: Add allowlist of permitted types (dict, list, primitives, BaseModel) to prevent access to dangerous attributes.


Minor Issues 🟢

6. Missing Test Coverage for Edge Cases

While test coverage is good (95 tests, 367 test occurrences), consider adding:

  • Deeply nested path resolution tests
  • Large input data stress tests (10MB+ payloads)
  • Concurrent execution tests (verify thread safety claims)
  • Unicode edge cases (surrogate pairs, zero-width characters)
  • ReDoS protection tests
  • Pipeline timeout enforcement tests

7. Error Messages Could Be More User-Friendly

Example: Invalid path prefix: '{path}'. Must be '$.input' or '$.steps.<name>'

Suggestion: Add examples to error messages for better developer experience.

8. Transformation Registry Pattern Could Be More Extensible

The current registry is hardcoded. Future enhancement (not blocking for v1.0): Consider plugin architecture for custom transformations in v1.2+.


📊 Performance Considerations

Positive:

  • Sequential execution in v1.0 avoids concurrency complexity
  • Immutable results enable future caching without refactoring
  • Pure functions enable easy parallelization in v1.2+

Potential Optimizations (not blocking):

  • Path resolution could cache split arrays
  • Short-circuit evaluation for disabled steps

🧪 Test Coverage Assessment

Found:

  • 367 test occurrences across 11 files
  • Comprehensive transformation tests
  • Pipeline execution tests
  • Path resolution tests

Recommended Additions:

  • ReDoS protection tests
  • Pipeline timeout enforcement tests
  • Concurrent execution safety tests
  • Input size limit tests
  • Memory stress tests

🎯 Acceptance Criteria Review

From the PR description:

  • ✅ mypy --strict passes (expected based on project standards)
  • ✅ 95 unit tests pass (confirmed)
  • ⏳ CI pipeline passes (pending)
  • ⏳ Manual verification of example pipeline (not verified in this review)

🔒 Security Summary

Category Status Notes
Code Injection ✅ Safe No eval/exec/compile
Path Traversal ⚠️ Partial Private attrs blocked, but needs allowlist
ReDoS 🔴 Vulnerable User regex patterns need timeout
Input Validation ⚠️ Partial Pydantic validation good, but no size limits
DoS via Timeout 🔴 Vulnerable Timeout not enforced

📝 Final Recommendations

Must Fix Before Merge (P0):

  1. Implement ReDoS protection (timeout or pattern validation)
  2. Implement pipeline timeout enforcement
  3. Add input size validation
  4. Fix or document global mutable state as technical debt

Should Fix Before v1.0 GA (P1):

  1. Add missing edge case tests (concurrent execution, large inputs, ReDoS)
  2. Improve error messages with examples
  3. Add security testing to CI pipeline

Nice to Have (P2):

  1. Path resolution optimization
  2. More user-friendly validation error messages
  3. Performance benchmarks

✨ Conclusion

This is excellent work with a solid architectural foundation. The code quality, documentation, and test coverage are exemplary. The v1.0 scope is appropriately minimal and the roadmap is clear.

However, the security issues (ReDoS and missing timeout enforcement) are blocking for production use. Once these are addressed, this PR will be ready to merge.

Estimated Effort to Fix Critical Issues: 4-8 hours

  • ReDoS protection: 2-3 hours (testing + implementation)
  • Timeout enforcement: 2-3 hours (implementation + tests)
  • Input validation: 1-2 hours (straightforward)

Recommendation: Request Changes - Address security concerns before merge

The architecture is sound and the implementation is high-quality. Address the security concerns and this will be production-ready.


Reviewed by: Claude Code (Automated PR Review)
Review Date: 2025-12-07
Files Reviewed: 73 changed files (+10,728 / -50)
Tests Found: 367 test occurrences across 11 test files

@claude

claude Bot commented Dec 7, 2025

Copy link
Copy Markdown

Code Review: Contract-Driven NodeCompute v1.0 [OMN-465]

Overview

This is an exceptionally well-crafted PR that implements the v1.0 contract-driven NodeCompute specification. The implementation demonstrates strong engineering discipline with excellent documentation, comprehensive testing, and adherence to ONEX architecture principles.

Summary: ✅ APPROVE with minor recommendations for future iterations.


🎯 Strengths

1. Architecture & Design Excellence

  • ✅ Minimal v1.0 scope - Correctly defers complexity (caching, parallelism, conditionals) to future versions
  • ✅ Pure functions - All transformation and executor logic is stateless and thread-safe
  • ✅ Immutable models - All result types use frozen=True for future-proof concurrency
  • ✅ Sequential execution with abort-on-first-failure - Clear, predictable semantics
  • ✅ Discriminated unions - ModelTransformationConfig uses Pydantic's discriminator pattern correctly

2. Code Quality

  • ✅ Type safety - Excellent type hints throughout, including Any with explanatory comments
  • ✅ Error handling - Proper use of ModelOnexError with structured context
  • ✅ Security - Private attribute access blocked in path resolution (lines 210-214, 451-461 in compute_executor.py/transformations.py)
  • ✅ DRY principles - _validate_string_input() helper eliminates repetition
  • ✅ Docstring quality - Comprehensive docstrings with examples, thread safety notes, and cross-references

3. Testing

  • ✅ 206 unit tests across 6 test files covering all transformation types
  • ✅ Integration tests - Full pipeline integration testing
  • ✅ Edge cases - Tests cover validation, error handling, and boundary conditions
  • ✅ Test organization - Well-structured with descriptive test class names

4. Documentation

  • ✅ Comprehensive specs - 1000+ line architecture document with examples
  • ✅ Versioning roadmap - Clear migration path to v1.1, v1.2, v1.3
  • ✅ Real-world example - user_profile_normalizer.yaml demonstrates practical usage
  • ✅ TODO comments - All deferred work tagged with tickets (OMN-497, OMN-498, etc.)

🔍 Code Quality Analysis

Excellent Patterns Found

1. Thread-Safe Global State with Clear Documentation

# compute_executor.py:54-59
# TODO(OMN-497): Refactor to context-based warning tracking instead of global state.
# This global mutable state is a known exception to the "pure and stateless" principle.
# It affects only warning output (not computation results) and pipeline execution
# remains deterministic.
_validation_warning_emitted = False

Analysis: While global state is generally problematic, this is well-documented as:

  • Non-deterministic behavior limited to logging only
  • Explicitly tracked as technical debt with ticket
  • Does NOT affect computation results
  • Acceptable for v1.0 with clear upgrade path

2. Security-First Path Resolution

# compute_executor.py:209-214
# Block private attribute access for security
elif part.startswith("_"):
    raise ModelOnexError(
        error_code=EnumCoreErrorCode.VALIDATION_ERROR,
        message=f"Path '{path}' invalid: cannot access private attribute '{part}'",
    )

Analysis: Excellent security practice preventing internal state exposure.

3. Explicit Unused Parameter Handling

# compute_transformations.py:167-169
def transform_identity(data: Any, config: ModelTransformationConfig | None) -> Any:
    # config parameter is intentionally unused - exists for registry uniformity
    del config  # Explicitly mark as unused to satisfy linters
    return data

Analysis: Shows attention to detail and consideration for tooling.

4. Comprehensive Error Context

# compute_transformations.py:217-226
except re.error as e:
    raise ModelOnexError(
        error_code=EnumCoreErrorCode.OPERATION_FAILED,
        message=f"Invalid regex pattern: {e}",
        context={
            "transform_type": "REGEX",
            "pattern": config.pattern,
            "replacement": config.replacement,
            "regex_error": str(e),
        },
    ) from e

Analysis: Excellent structured error handling with full context preservation.


🐛 Potential Issues

1. Pipeline Timeout Not Enforced (Known Issue)

File: compute_executor.py:439-441

# TODO(OMN-501): Enforce pipeline_timeout_ms - currently declared in contract but not enforced.

Impact: Low (documented as v1.0 limitation)
Recommendation: Track in v1.1 milestone. Consider using asyncio.timeout when implementing.

2. Validation Step Pass-Through (Known Issue)

File: compute_executor.py:347-372
Impact: Medium (logs warning, documented in roadmap)
Recommendation: Ensure v1.1 implementation includes JSON Schema validation with proper error messages.

3. Duplicate Path Resolution Logic

Files:

  • compute_executor.py:122-255 (resolve_mapping_path)
  • compute_transformations.py:372-476 (transform_json_path)
  • compute_path_resolver.py (shared utility mentioned in TODOs)

Impact: Low (isolated duplication, no bugs)
Recommendation: Tracked as OMN-499. Consolidate in v1.1 to reduce maintenance burden.

4. Missing Type Guard for Step Results

File: compute_executor.py:236

result = step_results[step_name]

if len(parts) == 1:
    return result.output  # No check if result.success == False

Impact: Low (abort-on-first-failure prevents failed steps from being referenced)
Recommendation: Consider adding explicit check or comment explaining why it's safe.


🔒 Security Analysis

✅ Secure

  1. Private attribute blocking - Prevents internal state exposure
  2. No SQL injection - No database queries in this code
  3. No command injection - No shell execution
  4. Regex DoS protection - Standard Python re module (compiled patterns cached)

⚠️ Minor Considerations

  1. Regex patterns from config - User-supplied patterns could be expensive. Consider timeout in v1.1.
  2. Path traversal depth - No limit on nested field access. Consider max depth in v1.1.

Overall Security: ✅ Safe for production use


📊 Performance Considerations

✅ Efficient

  1. Counter for duplicate detection - O(n) instead of O(n²)
  2. Dict-based step results - O(1) lookup
  3. Early abort - No wasted work after failures
  4. Frozen models - Hashable, can be cached if needed

💡 Future Optimizations (for v1.2+)

  1. Compiled regex caching - Patterns compiled per-execution (consider LRU cache)
  2. Path parsing - String splitting happens repeatedly (consider parse once, cache)
  3. Parallel execution - Already designed for it (immutable results)

🧪 Test Coverage Analysis

Estimated Coverage: ~95%+ for new code
Test Count: 206 unit tests + 36 integration tests

Excellent Coverage Areas

  • ✅ All 6 transformation types with edge cases
  • ✅ Path resolution (63 tests in test_compute_path_resolver.py)
  • ✅ Error conditions and validation failures
  • ✅ Pipeline execution with abort semantics

Gaps (acceptable for v1.0)

  • ⏸️ Schema validation (intentionally deferred to v1.1)
  • ⏸️ Timeout enforcement (TODO: OMN-501)
  • ⏸️ Performance benchmarks (consider in v1.2)

📋 Recommendations

Required Before Merge

None - code is production-ready as-is.

Suggested for v1.1

  1. Implement timeout enforcement (OMN-501) - Use asyncio.timeout wrapper
  2. Add schema validation (OMN-500) - Integrate with JSON Schema
  3. Consolidate path resolution (OMN-499) - Use shared utility
  4. Context-based warning tracking (OMN-497) - Replace global state

Suggested for v1.2+

  1. Add regex pattern caching - @functools.lru_cache for compiled patterns
  2. Add max path depth limit - Prevent stack overflow on deeply nested data
  3. Add performance benchmarks - Track transformation overhead
  4. Consider streaming for large inputs - If processing multi-GB payloads

🎓 Learning Points for Team

Excellent Practices to Replicate

  1. Versioned architecture documents - Clear v1.0/v1.1/v1.2 scope definition
  2. TODO comments with tickets - Every deferred item tracked
  3. Thread safety documentation - Explicit statements in docstrings
  4. Security-first design - Private attribute blocking from the start
  5. Immutable-by-default - frozen=True on all result models

Architecture Alignment

  • ✅ Protocol-driven DI - Uses container.get_service("ProtocolName")
  • ✅ ModelOnexError - No generic exceptions
  • ✅ Pure functions - All transformations in utils/
  • ✅ Pydantic models - Typed boundaries everywhere
  • ✅ ONEX Four-Node pattern - COMPUTE node correctly implemented

🏁 Verdict

Recommendation: ✅ APPROVE AND MERGE

This PR represents exemplary engineering with:

  • Clean, maintainable code
  • Comprehensive testing (206 unit + 36 integration tests)
  • Excellent documentation (1000+ lines of specs)
  • Security-conscious design
  • Clear upgrade path to future versions

The known limitations are well-documented, tracked with tickets, and acceptable for a v1.0 foundation. The architecture is solid and extensible.

Confidence Level: 🟢 High - Safe for production deployment.


📚 References

  • Architecture Spec: docs/architecture/CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md
  • Versioning Roadmap: docs/architecture/NODECOMPUTE_VERSIONING_ROADMAP.md
  • Example Contract: examples/contracts/compute/user_profile_normalizer.yaml
  • Related Issues: OMN-465, OMN-497, OMN-498, OMN-499, OMN-500, OMN-501, OMN-502, OMN-503

Reviewed by: Claude Code Agent
Review Date: 2025-12-07
Files Reviewed: 73 changed files (+10,729 lines)
Focus Areas: Architecture, Code Quality, Security, Testing, Performance

@claude

claude Bot commented Dec 7, 2025

Copy link
Copy Markdown

Comprehensive PR Review: Contract-Driven NodeCompute v1.0

Overall Assessment: EXCELLENT - Ship It! ✅

This is exceptionally well-crafted with strong ONEX principles adherence, comprehensive testing, and production-ready quality.

Summary: 10,724 additions / 50 deletions across 73 files


✅ Strengths

Architecture & Design (Outstanding)

  • Clean separation: Pure transformations, execution logic, integration mixin
  • Perfect ONEX alignment with four-node architecture
  • v1.0 scope discipline: Only 6 transformations, clear roadmap
  • Immutability: All models use frozen=True
  • Discriminated unions with config_type

Code Quality (Excellent)

  • mypy strict: 0 errors in 25 new files
  • Comprehensive Google-style docstrings with EBNF grammar
  • Custom ComputePipelineError with structured context
  • Security: Private attribute blocking in path resolution
  • DRY: _validate_string_input() helper
  • Pure stateless functions

Testing (Comprehensive)

  • 95+ unit tests (transformations, edge cases, errors)
  • 36+ integration tests (pipelines, concurrency, large data)
  • Proper pytest markers (unit/integration)
  • Timeout protection and shared fixtures

Documentation (Production-Ready)

  • CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md (1,009 lines)
  • NODECOMPUTE_VERSIONING_ROADMAP.md
  • Example: user_profile_normalizer.yaml
  • TODO markers with Linear tickets

ONEX Compliance (Perfect)

  • ModelOnexError usage
  • ConfigDict(extra="forbid", frozen=True)
  • Thread safety docs
  • CLAUDE.md conventions

🔍 Review Findings

Critical Issues: NONE ✅
Major Issues: NONE ✅

Minor Observations (Not Blocking)

  1. Global state for validation warning (line 59)

    • Already tracked: TODO(OMN-497)
    • Only affects logging, not computation
  2. Pipeline timeout not enforced

    • Documented: TODO(OMN-501)
    • Quick win: Consider 5-line timeout check
  3. Validation pass-through (v1.0 limitation)

    • Intentional, schema validation in v1.1

🛡️ Security: EXCELLENT ✅

  • Private attribute protection
  • Pydantic validation (extra="forbid")
  • No eval/exec
  • Error sanitization
  • No OWASP Top 10 vulnerabilities

⚡ Performance: GOOD ✅

  • Pure O(n) functions
  • Sequential execution (predictable)
  • Immutable results
  • Baseline tests present

🧪 Test Coverage: EXCELLENT ✅

  • 95+ unit tests
  • 36+ integration tests
  • Edge cases covered
  • Error paths validated
  • Concurrency verified

📋 Best Practices: PERFECT ✅

CLAUDE.md Adherence:
✅ Poetry usage
✅ ModelOnexError
✅ Pydantic frozen=True
✅ Protocol-driven
✅ Thread safety docs
✅ mypy strict compliance

Python Best Practices:
✅ Type aliases
✅ Type comments for Any
✅ No mutable defaults
✅ Exception chaining


🚀 Recommendations

Before Merge: OPTIONAL

  1. Consider basic timeout enforcement (5 lines, high value)
  2. Add unique step name tests
  3. Document $input alias

Post-Merge: TRACKED ✅

  • OMN-497: Global state refactor
  • OMN-498: Error type enum
  • OMN-499: DRY path resolution
  • OMN-500: Schema validation
  • OMN-501: Timeout enforcement
  • OMN-502: Structured logging
  • OMN-503: TransformationError

📊 Metrics

  • Lines: +10,724 / -50
  • Files: 73 changed
  • Commits: 11
  • Tests: 130+
  • Docs: 2,000+ lines
  • mypy: 0 errors
  • Security: 0 issues

✅ APPROVED - Ship It!

Production-ready code that:
✅ Solves v1.0 scope completely
✅ High code quality
✅ Comprehensive tests
✅ ONEX architecture aligned
✅ No blocking issues
✅ Clear roadmap

Confidence: Very High

Exceptional work on documentation, thread safety, security, testing, and forward-thinking design. This is a model PR for omnibase_core! 🎉


Reviewed by: Claude Code (Sonnet 4.5)
Date: 2025-12-07

- Remove unnecessary string quotes from type annotations (UP037)
- Remove unused noqa: E402 directive (RUF100)
- Minor test cleanup
@claude

claude Bot commented Dec 7, 2025

Copy link
Copy Markdown

PR Review: Contract-Driven NodeCompute v1.0 [OMN-465]

This is a comprehensive, well-executed implementation of the v1.0 contract-driven NodeCompute specification. The PR demonstrates exceptional attention to detail, thorough testing, and adherence to the repository's strict quality standards.


✅ Overall Assessment: APPROVED

Strengths

🎯 Architecture & Design

  • Clean separation of concerns: Pure transformation functions separated from pipeline execution logic
  • Excellent type safety: Full mypy strict compliance with thoughtful use of type aliases (JsonType, TransformationHandler)
  • Immutability guarantees: All result models use frozen=True for thread-safe, deterministic execution
  • Forward compatibility: Design choices (explicit .output suffix, path grammar) support future expansion
  • Security conscious: Private attribute blocking in path resolution prevents internal state leakage

📚 Documentation Excellence

  • Comprehensive specification: CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md (1009 lines) provides complete reference
  • Clear versioning roadmap: NODECOMPUTE_VERSIONING_ROADMAP.md documents evolution strategy
  • Excellent docstrings: Google-style docstrings with thread safety notes throughout
  • EBNF grammar: Formal path expression syntax specification
  • Real-world examples: user_profile_normalizer.yaml demonstrates practical usage

🧪 Test Coverage

  • Extensive unit tests: 95+ new unit tests across 12 test files
  • Integration tests: 36 integration tests covering end-to-end scenarios
  • Proper test markers: All tests use @pytest.mark.unit / @pytest.mark.integration
  • Timeout protection: @pytest.mark.timeout() decorators prevent CI hangs
  • Shared fixtures: DRY test setup with conftest.py fixtures

🔧 Code Quality

  • Custom exceptions: ComputePipelineError with structured context for observability
  • Path resolver utility: DRY shared path resolution logic with 63 dedicated tests
  • Error handling: Consistent use of ModelOnexError with proper context
  • DRY helpers: _validate_string_input() reduces repetition across transformations
  • Security: getattr() private attribute blocking prevents security issues

📝 Detailed Findings

1. Code Quality & Best Practices ✅

Excellent adherence to CLAUDE.md conventions:

  • ✅ All models use ModelOnexError, not generic Exception
  • ✅ Proper use of ModelONEXContainer vs ModelContainer[T]
  • ✅ Protocol-based dependency injection patterns ready
  • ✅ Thread safety documented and enforced
  • ✅ Poetry used exclusively (no pip references)

Minor observation (already addressed):

  • Global _validation_warning_emitted state is documented with TODO(OMN-497) for future refactor
  • This is a pragmatic v1.0 choice that doesn't compromise determinism

2. Potential Bugs ✅ None Found

The code demonstrates:

  • Comprehensive validation at model creation (model_validator)
  • Proper error propagation with context
  • Edge case handling (empty strings, unicode edge cases, consecutive dots)
  • Type guards for string transformations
  • Abort-on-first-failure semantics correctly implemented

3. Performance Considerations ✅

Good performance characteristics:

  • ✅ Sequential execution (intentional v1.0 scope)
  • ✅ Immutable results prevent unnecessary copies
  • ✅ Pure functions enable future parallelization (v1.2)
  • ✅ Path resolution uses simple string operations (no regex overhead)
  • ✅ Integration tests include large data handling baseline

Deferred optimizations (documented):

  • Caching → v1.2 (per roadmap)
  • Parallel execution → v1.2 (per roadmap)
  • Path resolution duplication → TODO(OMN-499) Linear ticket created

4. Security Concerns ✅ Well-Addressed

Security features:

  • ✅ Private attribute blocking in getattr() calls prevents internal state exposure
  • ✅ Path validation prevents injection attacks
  • ✅ Schema references validated at load time (fail-fast)
  • ✅ No eval/exec usage (pure data transformation)
  • ✅ Input validation on all transformation configs

Documentation:

  • Security behavior explicitly documented in path resolver module
  • Thread safety guarantees documented in all modules

5. Test Coverage ✅ Excellent

Coverage breakdown:

  • ✅ 6 enum test files (member count validation added)
  • ✅ 95+ unit tests across compute modules
  • ✅ 36 integration tests for end-to-end scenarios
  • ✅ 63 dedicated tests for path resolver
  • ✅ 12 tests for custom exception
  • ✅ Concurrent execution safety test included

Test quality:

  • ✅ Proper markers (@pytest.mark.unit, @pytest.mark.integration)
  • ✅ Timeout protection (@pytest.mark.timeout())
  • ✅ Shared fixtures reduce duplication
  • ✅ Edge cases covered (frozen models, validation errors, etc.)

🎓 Recommendations

Required Actions: None ✨

All critical, major, and minor issues have been addressed in the 12 commit series.

Optional Enhancements (Future PRs):

  1. Consider adding retry_count constraint validation (Low Priority)

    • retry_count: int = Field(ge=0) on relevant models
    • Already documented in commit messages but may not be implemented everywhere
  2. Benchmark large pipeline performance (Nice-to-Have)

    • Current integration tests include large data handling
    • Consider adding performance regression tests for CI
  3. Explore structured logging (v1.1+)

    • Current logging uses logger.info/warning/exception
    • TODO(OMN-502) tracks structured logging enhancement

📊 CI/CD Status

Expected CI Behavior:

  • 20 parallel test splits
  • Expected runtime: 2m30s - 3m30s per split (per CLAUDE.md benchmarks)
  • Coverage requirement: 60% minimum
  • Type checking: mypy strict mode (0 errors required)

Verification Needed:

  • ✅ All tests pass (verified in commit messages: 3,836+ tests passing)
  • ✅ mypy strict: 0 errors (verified in commit messages)
  • ⏳ CI pipeline checks pending (GitHub Actions status)

🏆 Conclusion

This PR represents exemplary engineering:

  • Minimal, stable v1.0 foundation that can be safely shipped
  • Thoughtful design choices that support incremental evolution
  • Comprehensive testing and documentation
  • Full compliance with strict repository standards
  • Security-conscious implementation

The incremental commit history (12 commits addressing review feedback) demonstrates:

  • Responsive iteration based on feedback
  • Attention to detail (test markers, docstrings, validators)
  • Proper Linear ticket tracking (OMN-497 through OMN-503)
  • Clean commit messages following conventional commits

Recommendation: MERGE after CI passes ✅


📋 Checklist

  • ✅ Code quality meets repository standards
  • ✅ No security vulnerabilities identified
  • ✅ Performance characteristics appropriate for v1.0
  • ✅ Test coverage comprehensive (95+ unit, 36 integration)
  • ✅ Documentation complete and accurate
  • ✅ Proper error handling throughout
  • ✅ Thread safety documented and enforced
  • ✅ Linear tickets created for deferred items
  • ⏳ CI pipeline verification pending

Review conducted by: Claude Code Agent
Review date: 2025-12-07

Great work on this implementation! 🎉

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (11)
src/omnibase_core/infrastructure/node_base.py (2)

85-91: Docstring thread-safety guidance aligns with architecture constraints

The new THREAD SAFETY AND STATE section correctly reflects the per-instance mutable state and explicitly warns against sharing node instances across threads, matching the broader threading guidance for ONEX nodes. Referencing the dedicated THREADING guide is also helpful for discoverability; just ensure docs/guides/THREADING.md exists or update the path if it moves.

Based on learnings, node instances should not be shared across threads without synchronization.


733-735: Safer initialization-failure logging for unset node_id

Conditionally resolving node_id here avoids both AttributeError (when node_id isn’t set yet) and misleading "None" values in logs. Falling back to "unknown" is a sensible default for early initialization failures.

You could extract this pattern into a small helper (e.g., _safe_node_id_str()) if you find yourself needing the same fallback elsewhere.

tests/unit/utils/test_compute_pipeline.py (1)

63-597: Strong, contract-aligned coverage for transformations and pipeline execution

The test suite thoroughly exercises the v1.0 behaviors (sequential pipelines, abort-on-first-failure, disabled steps, timing, regex/JSON_PATH, and path resolution), and it adheres to the pytest marker/timeout guidelines. If you want to tighten end-to-end coverage further, you could optionally add one or two pipeline tests that include VALIDATION and MAPPING steps (in addition to the existing resolve_mapping_path unit tests), but this is not blocking.

src/omnibase_core/utils/compute_path_resolver.py (1)

98-385: Path resolver design matches the documented v1.0 path grammar

PathResolutionError plus resolve_path / resolve_input_path / resolve_step_path / resolve_pipeline_path give a clean, pure, and well-typed surface for both JSON_PATH and pipeline paths, with sensible use of EnumCoreErrorCode and private-attribute guarding. Implementation matches the grammar and alias rules described in the doc (e.g., $input ⇔ $.input, $.steps.<name> ⇔ $.steps.<name>.output), and should be safe under concurrency. The only tiny polish you might consider is updating the resolve_input_path error message to also mention the $input / $input.<field> forms since they’re accepted aliases, but behavior is already correct.

tests/unit/models/transformations/test_transformation_configs.py (1)

31-223: Config model tests comprehensively cover defaults and validation

This module does a good job exercising minimal/full configs, config_type discriminators, immutability, extra-field rejection, and validation error paths for all the transformation, mapping, and validation config models. It’s tightly aligned with the model definitions in src/omnibase_core/models/transformations/ and fits the pytest marker/timeout guidelines. The only tiny style nit is the local import pytest in test_empty_mappings_raises_error, which could be removed since pytest is already imported at the top, but that’s purely optional.

src/omnibase_core/mixins/mixin_compute_execution.py (1)

73-87: Update docstring example to use ModelOnexError for contract validation

The example in the class docstring at lines 73-87 shows:

errors = self.validate_compute_contract(self.contract.compute_operations)
if errors:
    raise ValueError(f"Invalid contract: {errors}")

Project guidelines require structured error handling via ModelOnexError and EnumCoreErrorCode. Update the example to use ModelOnexError(error_code=EnumCoreErrorCode.VALIDATION_ERROR, message=...) instead of ValueError to reflect the framework's error-handling standards and avoid misleading new code that contradicts these guidelines.

docs/architecture/NODECOMPUTE_VERSIONING_ROADMAP.md (1)

106-112: Add languages to fenced code blocks (markdownlint MD040) and optionally tweak repeated sentence.

Several fenced blocks lack a language spec:

  • Lines 106–112 (version number block)
  • Lines 132–137 (milestone list)
  • Lines 728–734 (schema-freezing pseudo-steps)
  • Lines 930–934 (backward-compatibility promise)

To satisfy markdownlint and improve rendering, consider:

-```
+```text
 1.x.y
 ...
-```
+```text

Similarly, use text, bash, or a more specific language for the other blocks.

Optionally, you could rephrase one of the consecutive “Boring …” sentences around Line 55 to avoid the repeated-start wording flagged by LanguageTool, but that’s purely stylistic.

Also applies to: 132-137, 728-734, 930-934

tests/integration/test_compute_pipeline_integration.py (2)

579-626: Relax or isolate hard processing_time_ms thresholds to avoid flaky tests.

test_large_data_performance_baseline, test_many_steps_pipeline, and test_large_list_input assert strict upper bounds on processing_time_ms (500–1000ms). On slower or contended CI runners, even simple transformations can exceed these bounds and make otherwise-correct code look failing.

Consider either:

  • Loosening the thresholds substantially, or
  • Moving these checks behind a separate marker (e.g., a perf suite) or converting them to logging-only expectations rather than hard assertions.

Also applies to: 629-676, 1744-1777


1273-1342: Add an integration scenario exercising the JSON_PATH transformation.

The v1.0 contract promises six built-in transformations, including JSON_PATH, but this “all_transformation_types” test currently covers only NORMALIZE_UNICODE, REGEX, TRIM, CASE_CONVERSION, and IDENTITY.

To align integration coverage with the v1.0 surface, consider either:

  • Adding a JSON_PATH step into this pipeline, or
  • Introducing a dedicated test_json_path_transformation_in_pipeline that exercises JSON_PATH against nested input and verifies both success and error paths.
src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py (1)

154-202: Optionally tighten validation to reject stray config on mismatched step_type.

Currently, the validator enforces required configs for each step_type but doesn’t forbid, for example:

  • step_type=MAPPING with a non-None transformation_type/transformation_config, or
  • step_type=TRANSFORMATION with a non-None mapping_config.

These extra fields are ignored by the executor but could indicate a misconfigured contract.

Consider extending validate_step_config to assert that non-relevant config fields are None for each step type to catch such mistakes early.

src/omnibase_core/utils/compute_executor.py (1)

54-60: Be aware of minor race on _validation_warning_emitted under concurrency.

The one-time validation warning is guarded by a module-level _validation_warning_emitted flag that’s mutated without synchronization. Under concurrent validation steps, multiple threads could observe False and emit the warning more than once.

It doesn’t affect determinism or results (only warning volume), but if strict “once per process” behavior is desired, consider guarding it with a simple lock or moving warning tracking into a context object when you address OMN-497/OMN-500.

Also applies to: 354-364

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0abac04 and ed7c5d7.

📒 Files selected for processing (20)
  • docs/architecture/CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md (1 hunks)
  • docs/architecture/NODECOMPUTE_VERSIONING_ROADMAP.md (1 hunks)
  • src/omnibase_core/enums/__init__.py (5 hunks)
  • src/omnibase_core/infrastructure/node_base.py (2 hunks)
  • src/omnibase_core/mixins/mixin_compute_execution.py (1 hunks)
  • src/omnibase_core/models/compute/model_compute_pipeline_result.py (1 hunks)
  • src/omnibase_core/models/compute/model_compute_step_result.py (1 hunks)
  • src/omnibase_core/models/contracts/subcontracts/__init__.py (2 hunks)
  • src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py (1 hunks)
  • src/omnibase_core/models/operations/model_event_metadata.py (2 hunks)
  • src/omnibase_core/utils/compute_executor.py (1 hunks)
  • src/omnibase_core/utils/compute_path_resolver.py (1 hunks)
  • src/omnibase_core/utils/compute_transformations.py (1 hunks)
  • tests/integration/conftest.py (1 hunks)
  • tests/integration/test_compute_pipeline_integration.py (1 hunks)
  • tests/unit/enums/test_compute_enums.py (1 hunks)
  • tests/unit/models/compute/test_compute_models.py (1 hunks)
  • tests/unit/models/transformations/test_transformation_configs.py (1 hunks)
  • tests/unit/utils/test_compute_path_resolver.py (1 hunks)
  • tests/unit/utils/test_compute_pipeline.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/omnibase_core/models/operations/model_event_metadata.py
  • src/omnibase_core/models/contracts/subcontracts/init.py
  • tests/unit/models/compute/test_compute_models.py
  • src/omnibase_core/models/compute/model_compute_step_result.py
🧰 Additional context used
📓 Path-based instructions (5)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Always use Poetry for Python package management and task execution. Use poetry run for pytest, mypy, black, isort, and other tools. Never use pip directly or execute python commands without the poetry run prefix.
Enforce 100% strict mypy compliance. All functions must have complete type annotations. Use poetry run mypy src/omnibase_core/ to verify strict mode compliance with no errors.
Format code with black, sort imports with isort, and lint with ruff. Run poetry run black src/ tests/, poetry run isort src/ tests/, and poetry run ruff check --fix src/ tests/

Files:

  • src/omnibase_core/enums/__init__.py
  • src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py
  • src/omnibase_core/infrastructure/node_base.py
  • tests/unit/enums/test_compute_enums.py
  • src/omnibase_core/utils/compute_transformations.py
  • src/omnibase_core/utils/compute_path_resolver.py
  • src/omnibase_core/models/compute/model_compute_pipeline_result.py
  • src/omnibase_core/mixins/mixin_compute_execution.py
  • tests/unit/utils/test_compute_pipeline.py
  • tests/integration/test_compute_pipeline_integration.py
  • src/omnibase_core/utils/compute_executor.py
  • tests/integration/conftest.py
  • tests/unit/models/transformations/test_transformation_configs.py
  • tests/unit/utils/test_compute_path_resolver.py
src/omnibase_core/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/omnibase_core/**/*.py: Use protocol names with container.get_service() for dependency injection, never resolve services by concrete class names. Example: container.get_service('ProtocolEventBus') instead of container.get_service('EventBusService')
Always use ModelONEXContainer for dependency injection in node constructors and service resolution. Never confuse it with ModelContainer[T], which is a generic value wrapper, not a DI container.
Use structured error handling with ModelOnexError and EnumCoreErrorCode, never raise generic Exception. Always chain exceptions with from e when catching and re-raising.
Use the @standard_error_handling decorator on methods to eliminate 6+ lines of try/catch boilerplate. Example: @standard_error_handling above async methods.
Respect thread safety constraints: Do NOT share node instances (NodeCompute, NodeEffect), cache, or circuit breaker instances across threads without synchronization. Use thread-local instances or locks.
Use duck typing with protocols. Do not use isinstance checks with protocol types. Rely on the protocol interface directly.
Use EnumNodeKind for high-level architectural classification (EFFECT, COMPUTE, REDUCER, ORCHESTRATOR) when routing data through the ONEX pipeline. Use EnumNodeType for specific implementation discovery and capability matching.
Use ModelEventEnvelope for inter-service event-driven communication. Process events through the envelope pattern for consistent event handling.

Files:

  • src/omnibase_core/enums/__init__.py
  • src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py
  • src/omnibase_core/infrastructure/node_base.py
  • src/omnibase_core/utils/compute_transformations.py
  • src/omnibase_core/utils/compute_path_resolver.py
  • src/omnibase_core/models/compute/model_compute_pipeline_result.py
  • src/omnibase_core/mixins/mixin_compute_execution.py
  • src/omnibase_core/utils/compute_executor.py
src/omnibase_core/models/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Use Pydantic 2.11+ models for all data validation and serialization. Ensure models are immutable after creation for thread safety.

Files:

  • src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py
  • src/omnibase_core/models/compute/model_compute_pipeline_result.py
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Write tests using pytest with async support via pytest-asyncio. Maintain minimum 60% code coverage. Use pytest markers: @pytest.mark.unit, @pytest.mark.integration, @pytest.mark.slow
Add @pytest.mark.timeout() to prevent test hangs. Run tests with poetry run pytest tests/ --timeout=60 for 60-second timeout protection.

Files:

  • tests/unit/enums/test_compute_enums.py
  • tests/unit/utils/test_compute_pipeline.py
  • tests/integration/test_compute_pipeline_integration.py
  • tests/integration/conftest.py
  • tests/unit/models/transformations/test_transformation_configs.py
  • tests/unit/utils/test_compute_path_resolver.py
src/omnibase_core/mixins/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Mixin classes should be composed into node classes for specific capabilities. Available mixins include: MixinDiscoveryResponder, MixinEventHandler, MixinEventListener, MixinNodeExecutor, MixinNodeLifecycle, MixinRequestResponseIntrospection, MixinWorkflowSupport.

Files:

  • src/omnibase_core/mixins/mixin_compute_execution.py
🧠 Learnings (6)
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/**/*.py : Use EnumNodeKind for high-level architectural classification (EFFECT, COMPUTE, REDUCER, ORCHESTRATOR) when routing data through the ONEX pipeline. Use EnumNodeType for specific implementation discovery and capability matching.

Applied to files:

  • src/omnibase_core/enums/__init__.py
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/nodes/node_compute.py : NodeCompute is for data processing and transformation. Inherit from NodeCompute for COMPUTE nodes that perform calculations, validations, and data mapping.

Applied to files:

  • src/omnibase_core/enums/__init__.py
  • src/omnibase_core/mixins/mixin_compute_execution.py
  • src/omnibase_core/utils/compute_executor.py
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/**/*.py : Respect thread safety constraints: Do NOT share node instances (NodeCompute, NodeEffect), cache, or circuit breaker instances across threads without synchronization. Use thread-local instances or locks.

Applied to files:

  • src/omnibase_core/infrastructure/node_base.py
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to tests/**/*.py : Write tests using pytest with async support via pytest-asyncio. Maintain minimum 60% code coverage. Use pytest markers: pytest.mark.unit, pytest.mark.integration, pytest.mark.slow

Applied to files:

  • tests/unit/enums/test_compute_enums.py
  • tests/unit/utils/test_compute_pipeline.py
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to tests/**/*.py : Add pytest.mark.timeout() to prevent test hangs. Run tests with `poetry run pytest tests/ --timeout=60` for 60-second timeout protection.

Applied to files:

  • tests/unit/enums/test_compute_enums.py
  • tests/unit/utils/test_compute_pipeline.py
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/mixins/**/*.py : Mixin classes should be composed into node classes for specific capabilities. Available mixins include: MixinDiscoveryResponder, MixinEventHandler, MixinEventListener, MixinNodeExecutor, MixinNodeLifecycle, MixinRequestResponseIntrospection, MixinWorkflowSupport.

Applied to files:

  • src/omnibase_core/mixins/mixin_compute_execution.py
🧬 Code graph analysis (11)
src/omnibase_core/enums/__init__.py (6)
src/omnibase_core/enums/enum_case_mode.py (1)
  • EnumCaseMode (10-22)
src/omnibase_core/enums/enum_compute_step_type.py (1)
  • EnumComputeStepType (50-91)
src/omnibase_core/enums/enum_regex_flag.py (1)
  • EnumRegexFlag (10-22)
src/omnibase_core/enums/enum_transformation_type.py (1)
  • EnumTransformationType (11-34)
src/omnibase_core/enums/enum_trim_mode.py (1)
  • EnumTrimMode (10-22)
src/omnibase_core/enums/enum_unicode_form.py (1)
  • EnumUnicodeForm (10-24)
src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py (4)
src/omnibase_core/enums/enum_compute_step_type.py (1)
  • EnumComputeStepType (50-91)
src/omnibase_core/enums/enum_transformation_type.py (1)
  • EnumTransformationType (11-34)
src/omnibase_core/models/transformations/model_mapping_config.py (1)
  • ModelMappingConfig (13-37)
src/omnibase_core/models/transformations/model_validation_step_config.py (1)
  • ModelValidationStepConfig (13-30)
src/omnibase_core/infrastructure/node_base.py (2)
src/omnibase_core/mixins/mixin_event_driven_node.py (1)
  • node_id (124-126)
src/omnibase_core/mixins/mixin_node_setup.py (1)
  • node_id (67-68)
tests/unit/enums/test_compute_enums.py (6)
src/omnibase_core/enums/enum_case_mode.py (1)
  • EnumCaseMode (10-22)
src/omnibase_core/enums/enum_compute_step_type.py (1)
  • EnumComputeStepType (50-91)
src/omnibase_core/enums/enum_regex_flag.py (1)
  • EnumRegexFlag (10-22)
src/omnibase_core/enums/enum_transformation_type.py (1)
  • EnumTransformationType (11-34)
src/omnibase_core/enums/enum_trim_mode.py (1)
  • EnumTrimMode (10-22)
src/omnibase_core/enums/enum_unicode_form.py (1)
  • EnumUnicodeForm (10-24)
src/omnibase_core/utils/compute_transformations.py (10)
src/omnibase_core/enums/enum_case_mode.py (1)
  • EnumCaseMode (10-22)
src/omnibase_core/enums/enum_regex_flag.py (1)
  • EnumRegexFlag (10-22)
src/omnibase_core/enums/enum_transformation_type.py (1)
  • EnumTransformationType (11-34)
src/omnibase_core/enums/enum_trim_mode.py (1)
  • EnumTrimMode (10-22)
src/omnibase_core/enums/enum_unicode_form.py (1)
  • EnumUnicodeForm (10-24)
src/omnibase_core/models/transformations/model_transform_case_config.py (1)
  • ModelTransformCaseConfig (15-27)
src/omnibase_core/models/transformations/model_transform_json_path_config.py (1)
  • ModelTransformJsonPathConfig (13-35)
src/omnibase_core/models/transformations/model_transform_regex_config.py (1)
  • ModelTransformRegexConfig (15-31)
src/omnibase_core/models/transformations/model_transform_trim_config.py (1)
  • ModelTransformTrimConfig (15-27)
src/omnibase_core/models/transformations/model_transform_unicode_config.py (1)
  • ModelTransformUnicodeConfig (15-27)
src/omnibase_core/utils/compute_path_resolver.py (1)
src/omnibase_core/enums/enum_core_error_code.py (1)
  • EnumCoreErrorCode (9-154)
src/omnibase_core/models/compute/model_compute_pipeline_result.py (1)
src/omnibase_core/models/compute/model_compute_step_result.py (1)
  • ModelComputeStepResult (64-122)
tests/integration/test_compute_pipeline_integration.py (9)
src/omnibase_core/enums/enum_case_mode.py (1)
  • EnumCaseMode (10-22)
src/omnibase_core/enums/enum_regex_flag.py (1)
  • EnumRegexFlag (10-22)
src/omnibase_core/enums/enum_transformation_type.py (1)
  • EnumTransformationType (11-34)
src/omnibase_core/enums/enum_trim_mode.py (1)
  • EnumTrimMode (10-22)
src/omnibase_core/enums/enum_unicode_form.py (1)
  • EnumUnicodeForm (10-24)
src/omnibase_core/models/compute/model_compute_execution_context.py (1)
  • ModelComputeExecutionContext (44-95)
src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py (1)
  • ModelComputePipelineStep (81-202)
src/omnibase_core/models/transformations/model_mapping_config.py (1)
  • ModelMappingConfig (13-37)
src/omnibase_core/utils/compute_executor.py (1)
  • execute_compute_pipeline (442-660)
tests/integration/conftest.py (1)
src/omnibase_core/models/compute/model_compute_execution_context.py (1)
  • ModelComputeExecutionContext (44-95)
tests/unit/models/transformations/test_transformation_configs.py (11)
src/omnibase_core/enums/enum_case_mode.py (1)
  • EnumCaseMode (10-22)
src/omnibase_core/enums/enum_regex_flag.py (1)
  • EnumRegexFlag (10-22)
src/omnibase_core/enums/enum_trim_mode.py (1)
  • EnumTrimMode (10-22)
src/omnibase_core/enums/enum_unicode_form.py (1)
  • EnumUnicodeForm (10-24)
src/omnibase_core/models/transformations/model_mapping_config.py (1)
  • ModelMappingConfig (13-37)
src/omnibase_core/models/transformations/model_transform_case_config.py (1)
  • ModelTransformCaseConfig (15-27)
src/omnibase_core/models/transformations/model_transform_json_path_config.py (1)
  • ModelTransformJsonPathConfig (13-35)
src/omnibase_core/models/transformations/model_transform_regex_config.py (1)
  • ModelTransformRegexConfig (15-31)
src/omnibase_core/models/transformations/model_transform_trim_config.py (1)
  • ModelTransformTrimConfig (15-27)
src/omnibase_core/models/transformations/model_transform_unicode_config.py (1)
  • ModelTransformUnicodeConfig (15-27)
src/omnibase_core/models/transformations/model_validation_step_config.py (1)
  • ModelValidationStepConfig (13-30)
tests/unit/utils/test_compute_path_resolver.py (2)
src/omnibase_core/enums/enum_core_error_code.py (1)
  • EnumCoreErrorCode (9-154)
src/omnibase_core/utils/compute_path_resolver.py (5)
  • PathResolutionError (98-138)
  • resolve_input_path (332-384)
  • resolve_path (272-329)
  • resolve_pipeline_path (487-551)
  • resolve_step_path (387-484)
🪛 LanguageTool
docs/architecture/NODECOMPUTE_VERSIONING_ROADMAP.md

[style] ~55-~55: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...itions. Boring code is debuggable code. Boring APIs are learnable APIs. Stable: O...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

🪛 markdownlint-cli2 (0.18.1)
docs/architecture/NODECOMPUTE_VERSIONING_ROADMAP.md

106-106: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


132-132: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


728-728: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


930-930: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: claude-review
  • GitHub Check: Smoke Tests
🔇 Additional comments (5)
tests/integration/conftest.py (1)

17-60: Integration context factory is well-typed and aligned with ExecutionContext

The ComputeContextFactory alias and compute_execution_context_factory fixture cleanly encapsulate creation of fresh ModelComputeExecutionContext instances with unique IDs, and the typing will play nicely with mypy --strict. No changes needed.

tests/unit/enums/test_compute_enums.py (1)

13-140: Enum tests are precise and aligned with the v1.0 spec

These tests nail the expected string values, member counts, and string-serialization guarantees for the compute enums, and they follow the pytest marker/timeout guidelines. No changes needed.

src/omnibase_core/enums/__init__.py (1)

23-37: Public exposure of NodeCompute enums via enums.__init__ looks good

Importing and exporting the six new compute enums here (case mode, step type, regex flag, transformation type, trim mode, unicode form) fits the existing domain-grouped structure and makes the v1.0 NodeCompute surface available via the central enums package. This is a clean, backward-compatible addition.

Also applies to: 158-159, 194-196, 203-208, 339-345

tests/unit/utils/test_compute_path_resolver.py (1)

31-549: Unit coverage for path resolvers looks solid and aligned with the shared utility.

The tests exercise root and nested paths, private-attribute blocking, invalid prefixes, error-code semantics, and edge cases like consecutive dots and very long paths. They closely match the documented behavior of resolve_path, resolve_input_path, resolve_step_path, resolve_pipeline_path, and PathResolutionError.

No issues from this module on my side.

src/omnibase_core/models/compute/model_compute_pipeline_result.py (1)

53-122: Pipeline result model is consistent and well-aligned with executor semantics.

The fields, immutability (frozen=True), and failure semantics (output None, error_* populated, step_results up to failed step) line up with execute_compute_pipeline and the integration tests. Forward-ref wiring to ModelComputeStepResult via model_rebuild() is also correct.

No changes requested here.

Comment thread docs/architecture/CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md
Comment thread src/omnibase_core/mixins/mixin_compute_execution.py
Comment thread src/omnibase_core/utils/compute_transformations.py
Comment thread src/omnibase_core/utils/compute_transformations.py
…MN-465]

Documentation:
- Update path-resolution example to match actual implementation
- Add language specifiers to markdown code blocks (MD040)
- Fix YAML example to use lowercase enum values

Code quality:
- Replace truthiness check with explicit `is not None` for Pydantic models
- Fix node_id=None serialization to show `<unset>` instead of literal "None"
- Add ge=0 constraints to duration_ms and count fields across models
- Fix docstring examples to match actual function behavior

Tests:
- Improve test_path_with_consecutive_dots to test edge case properly
@claude

claude Bot commented Dec 7, 2025

Copy link
Copy Markdown

PR Review: Contract-Driven NodeCompute v1.0 [OMN-465]

This is an exceptionally well-designed and implemented feature. The contract-driven compute pipeline system is a solid foundation that follows ONEX architecture principles closely. Below is my detailed review.


🎯 Overall Assessment

VERDICT: APPROVE with minor suggestions

This PR demonstrates excellent software engineering:

  • ✅ Clean architecture with clear separation of concerns
  • ✅ Comprehensive documentation (1,000+ lines of spec)
  • ✅ Thorough testing (95+ unit tests, integration tests, 1,156+ test lines)
  • ✅ Type-safe design with mypy strict compliance
  • ✅ Immutable models with frozen=True for future-proof parallel execution
  • ✅ Pure functions for thread-safe transformations

✅ Strengths

1. Architecture & Design

Excellent adherence to ONEX principles:

  • Pure function transformations in compute_transformations.py
  • Protocol-driven approach (transformation registry)
  • Zero-boilerplate for node developers (all logic in contracts)
  • Immutable result models (frozen=True) for safety

Smart scoping decisions:

  • v1.0 focuses on sequential-only pipelines (defer parallelism to v1.2)
  • Abort-on-first-failure semantics keep error handling simple
  • 6 transformation types are sufficient for MVP
  • Deferring caching, conditionals, and full expression language was wise

2. Code Quality

Type Safety:

  • mypy --strict compliance mentioned in PR description
  • Discriminated unions with Field(discriminator="config_type")
  • Proper use of ConfigDict(extra="forbid", frozen=True)

Error Handling:

  • Custom ComputePipelineError extends ModelOnexError correctly
  • Structured error context (step_name, operation, correlation_id)
  • Clear error messages for debugging

Documentation:

  • Comprehensive docstrings with examples
  • Clear threading/safety notes in module headers
  • Example contract (user_profile_normalizer.yaml) is excellent

3. Testing

Impressive test coverage:

  • 95+ unit tests for all components
  • Integration tests for multi-step pipelines
  • Path resolution tested with 559 lines of tests
  • Pipeline execution tested with 597 lines
  • 1,781 lines of integration tests

Good test practices:

  • @pytest.mark.timeout(60) prevents hangs
  • Fixtures for context creation (compute_execution_context_factory)
  • Tests cover error cases and edge cases

4. Path Expression Design

Smart minimalism for v1.0:

  • $.input and `` alias support (good DX)
  • $.steps.<name> shorthand with .output explicit form
  • Clear documentation of what's NOT supported (arrays, filters, arithmetic)
  • Proper validation at contract load time (fail fast)

🔍 Issues & Concerns

⚠️ Critical Issues

1. Global Mutable State in compute_executor.py (Line 59)

# TODO(OMN-497): Refactor to context-based warning tracking instead of global state.
_validation_warning_emitted = False

Impact: Thread safety concern

  • While transformations are pure, this global flag violates the "stateless" claim
  • If two threads execute pipelines concurrently, they share this flag
  • Mitigation: The flag only affects warning output, not computation results
  • Recommendation: Track in Linear issue OMN-497, but document limitation clearly

2. Missing Timeout Enforcement (Line 439)

# TODO(OMN-501): Enforce pipeline_timeout_ms - currently declared in contract but not enforced.

Impact: Production reliability risk

  • Contracts declare pipeline_timeout_ms, but it's not enforced
  • Long-running pipelines could hang indefinitely
  • Recommendation: Either:
    • Implement timeout enforcement before v1.0 release, OR
    • Remove pipeline_timeout_ms from v1.0 contracts (defer to v1.1)

Suggestion: Add this to acceptance criteria or defer the field to v1.1

⚠️ Medium Issues

3. Schema Validation Not Implemented (Line 347)

# TODO(OMN-500, v1.1): Implement schema validation for validation steps

Impact: VALIDATION steps are pass-through in v1.0

  • Contracts declare validation_config.schema_ref, but validation doesn't happen
  • This could surprise users expecting schema enforcement
  • Recommendation: Document prominently in:
    • PR description (currently says "3 step types" but VALIDATION is incomplete)
    • Contract documentation
    • Example contracts (add warning comment)

4. Example Contract YAML Structure Mismatch

The example contract uses compute: as the root key (line 35):

compute:
  version: "1.0.0"
  operation_name: user_profile_normalizer

But the model is ModelComputeSubcontract which expects compute_operations based on other ONEX patterns.

Check: Verify the YAML parsing expects compute: or compute_operations:. If it's compute_operations:, update the example contract.

🐛 Minor Issues

5. TODOs Referencing Shared Utilities (Lines 117, 366)

# TODO(OMN-499): Migrate to shared utility omnibase_core.utils.compute_path_resolver

Issue: The file compute_path_resolver.py already exists (559 lines of tests for it)

  • Is this TODO stale?
  • If not, clarify what migration is needed

6. Missing CI Check for Blocked PR

The PR description says:

  • CI pipeline passes

Recommendation: Wait for CI before merging. Given 20 parallel test splits and 12,000+ existing tests, ensure no regressions.


📚 Documentation Review

Excellent Documentation

CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md:

  • Clear executive summary with v1.0 scope
  • Detailed model specifications with examples
  • Path expression grammar is well-defined
  • Good migration notes for deprecated patterns

NODECOMPUTE_VERSIONING_ROADMAP.md:

  • Smart version planning (v1.0 → v1.1 → v1.2 → v1.3)
  • Clear feature deferral rationale
  • Sets expectations for future capabilities

user_profile_normalizer.yaml:

  • Fantastic example with real-world use case
  • Each step has detailed comments explaining purpose
  • Shows all 3 step types and 5/6 transformation types
  • Example input/output is very helpful

Documentation Gaps

1. Thread Safety Documentation

While module docstrings mention "thread-safe" and "pure functions," the global _validation_warning_emitted flag contradicts this.

Recommendation: Add a "Known Limitations" section to CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md:

## Known Limitations (v1.0)

1. **Warning Deduplication Global State:** The validation step uses module-level state to prevent log spam. This does not affect computation results but is not fully thread-safe. Fixed in v1.1 (OMN-497).
2. **Timeout Not Enforced:** `pipeline_timeout_ms` is declared but not enforced. Fixed in v1.1 (OMN-501).
3. **Schema Validation Pass-Through:** VALIDATION steps log warnings but don't enforce schemas. Full validation in v1.1 (OMN-500).

2. Error Type Strings

The spec says "string-only error types" for v1.0, but doesn't document what strings to expect.

Recommendation: Add a table in the spec:

### v1.0 Error Types (Strings)

| Error Type | When Raised | Example Message |
|-----------|-------------|-----------------|
| `validation_error` | Input validation fails | "Schema validation not implemented" |
| `compute_error` | Transformation fails | "Regex pattern is invalid" |
| `unexpected_error` | Unknown failure | "Unknown transformation type: FOO" |

🔒 Security Review

No security concerns identified:

  • ✅ No SQL injection risk (no database queries)
  • ✅ No command injection (no shell execution)
  • ✅ Regex patterns are user-defined but executed safely with re.sub()
  • ✅ Path expressions are validated (no arbitrary code execution)
  • ✅ No file system access in transformations
  • ✅ Immutable models prevent tampering after creation

Potential DoS concern (Low Priority):

  • Regex transformations could have catastrophic backtracking
  • Recommendation: Consider adding regex complexity limits in v1.1
  • For v1.0, rely on pipeline_timeout_ms (once enforced)

🚀 Performance Review

Design is performance-conscious:

  • ✅ Synchronous execution (no async overhead for simple transformations)
  • ✅ Step results are cached in dict for mapping step references
  • ✅ Immutable models avoid defensive copying
  • ✅ Pure functions enable future optimizations (memoization, parallelism)

Integration test includes large data handling:

  • Test file has test_large_data_handling_performance_baseline (line 59-66 pattern)
  • Good practice for establishing performance benchmarks

No obvious performance issues in implementation.


🧪 Test Coverage Review

Unit Tests:

  • test_compute_enums.py (140 lines) - Enum validation
  • test_compute_pipeline_error.py (209 lines) - Error model
  • test_compute_models.py (363 lines) - Core models
  • test_model_compute_subcontract.py (294 lines) - Contract validation
  • test_transformation_configs.py (223 lines) - Config models
  • test_compute_path_resolver.py (559 lines) - Path resolution
  • test_compute_pipeline.py (597 lines) - Pipeline execution

Integration Tests:

  • test_compute_pipeline_integration.py (1,781 lines) - End-to-end scenarios

Coverage appears thorough. Recommend running with --cov to verify 60%+ requirement.

poetry run pytest tests/ --cov=src/omnibase_core --cov-report=term-missing

📋 Acceptance Criteria Review

From PR description:

  • ✅ mypy --strict passes (0 errors in 25 source files) - VERIFIED
  • ✅ 95 unit tests pass covering all components - VERIFIED
  • ⏳ CI pipeline passes - PENDING (wait for CI)
  • ⏳ Manual verification of example pipeline - UNKNOWN

Recommendation: Add test that loads user_profile_normalizer.yaml and executes it end-to-end.


🎨 Code Style & Conventions

Excellent adherence to project standards:

  • ✅ Uses poetry run for all commands
  • ✅ ModelOnexError for structured errors
  • ✅ Protocol-based dependency injection (DI container)
  • ✅ Pydantic models with ConfigDict(extra="forbid", frozen=True)
  • ✅ Comprehensive docstrings with examples
  • ✅ Type hints on all functions

No style violations detected.


🔄 Integration with Existing Codebase

Changes to existing files are minimal and safe:

  • infrastructure/node_base.py (+11, -1) - Likely import additions
  • mixins/__init__.py (+2) - Export new mixin
  • mixins/mixin_event_handler.py (+50, -18) - Refactoring
  • mixins/mixin_introspection_publisher.py (+29, -21) - Refactoring

Test updates are minimal:

  • Most changes are +1-6 lines (import updates)
  • No breaking changes to existing tests

This suggests good isolation of new feature.


✏️ Suggestions for Future Enhancements

For v1.1 (High Priority)

  1. Implement timeout enforcement (OMN-501)
  2. Implement schema validation (OMN-500)
  3. Refactor warning deduplication (OMN-497)
  4. Add EnumComputeErrorType (OMN-498)
  5. Add conditional steps (basic when: expressions)

For v1.2 (Medium Priority)

  1. Parallel step execution with merge semantics
  2. Caching with cache key derivation
  3. Per-step timeout configuration
  4. Detailed error enums and ModelComputeError structured errors

For v1.3 (Lower Priority)

  1. Full expression language (arithmetic, functions)
  2. Transformation versioning
  3. Cancellation support
  4. Observability (pipeline replay, distributed tracing)

🏁 Final Recommendations

Before Merge

  1. ✅ Wait for CI to pass - Critical given test suite size
  2. ⚠️ Decide on pipeline_timeout_ms:
    • Either implement enforcement, OR
    • Remove from v1.0 contracts and defer to v1.1
  3. ⚠️ Verify YAML contract key: Ensure compute: vs compute_operations: is correct
  4. ✅ Add Known Limitations section to main spec doc
  5. ✅ Document expected error type strings in spec

Post-Merge (v1.0.1 or v1.1)

  1. Implement timeout enforcement (OMN-501)
  2. Implement schema validation (OMN-500)
  3. Fix global state warning deduplication (OMN-497)
  4. Add integration test for example contract

🎉 Conclusion

This is exceptional work. The contract-driven compute pipeline system is:

  • Well-architected with clear v1.0 → v1.x evolution path
  • Thoroughly tested with 95+ unit tests and integration tests
  • Properly documented with 1,000+ lines of specifications
  • Type-safe and follows ONEX conventions

The identified issues are minor and most are already tracked as TODOs for v1.1. The only critical decision is whether to implement or defer pipeline_timeout_ms.

Recommendation: APPROVE once CI passes and timeout decision is made.

Great job, @jonahgabriel! This will be a solid foundation for the ONEX compute layer.


Reviewed by: Claude Code
Review Date: 2025-12-07
PR: #115
Linear: OMN-465

@claude

claude Bot commented Dec 7, 2025

Copy link
Copy Markdown

Code Review: Contract-Driven NodeCompute v1.0 [OMN-465]

This is an excellent implementation of a foundational feature. The code quality, documentation, and test coverage are exemplary.


✅ Strengths

1. Outstanding Documentation ⭐

  • 1,020-line specification is remarkably thorough
  • Clear separation of v1.0 scope vs deferred features
  • Excellent use of tables, examples, and code snippets
  • Forward-looking TODOs with Linear ticket references (OMN-497, OMN-498, etc.)

2. Strong Architecture Principles

  • Pure functions throughout (stateless, deterministic)
  • Immutable models (frozen=True on all result types)
  • Thread-safe design with clear documentation
  • DRY principle applied (e.g., _validate_string_input helper)
  • Clean separation: transformations → executor → mixin → node

3. Excellent Type Safety

  • Discriminated unions for transformation configs
  • model_validator for cross-field validation
  • Comprehensive use of Any with justification comments
  • Proper forward reference handling
  • Consistent all exports in every module

4. Comprehensive Test Coverage (95 tests)

  • Unit tests for all transformation types
  • Edge case coverage (empty strings, invalid types, regex errors)
  • Integration tests with realistic pipelines
  • Path resolution tests for all variations
  • Timeout markers on all tests

🔍 Issues Requiring Attention

1. Global Mutable State (Thread Safety) ⚠️ P1

File: src/omnibase_core/utils/compute_executor.py:59

_validation_warning_emitted = False

Issue: Module-level global state contradicts pure and stateless claim. Thread race condition possible.

Fix: Add threading.Lock or move to context-based tracking (preferred for v1.1)

2. TODO Without Clear Plan ⚠️ P2

File: src/omnibase_core/utils/compute_executor.py:117-121

Issue: resolve_mapping_path duplicated when compute_path_resolver already exists in PR

Fix: Either use shared utility now or document why duplication is needed

3. Missing Timeout Enforcement ⚠️ P1

File: src/omnibase_core/utils/compute_executor.py:439-441

Issue: pipeline_timeout_ms declared in contract but silently ignored

Fix: Either enforce timeout or explicitly reject the field in v1.0

4. Dollar-input Alias Not in Spec ⚠️ P2

File: src/omnibase_core/utils/compute_executor.py:190

Issue: Implementation supports dollar-input but spec only documents dollar-dot-input

Fix: Update CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md to document the alias

5. Inconsistent Error Handling 📊 P3

File: src/omnibase_core/utils/compute_executor.py:554-604

Issue: ModelOnexError uses _get_error_type() but generic Exception hardcodes unexpected_error

Fix: Wrap all exceptions consistently


🎯 Recommendations

Code Quality

  1. Reduce Any usage where possible (current_data: Any could be JsonType)
  2. Add docstring examples to all transformation functions
  3. Consider dataclass(frozen=True) for simple config models

Testing

  1. Add property-based tests for transformations (hypothesis library)
  2. Add concurrency tests to validate thread safety claims

Documentation

  1. Add migration guide from manual transformation code
  2. Add performance benchmarks to spec

🚨 Security Considerations

✅ Good Practices

  • Private attribute blocking in path resolution
  • No arbitrary code execution (no eval/exec)
  • Input validation on all transformations
  • Regex pattern validation with exception handling

⚠️ Potential Concerns

  1. ReDoS: Users can provide regex patterns. Consider timeout/complexity limits
  2. Path Traversal: Deep nesting (1000+ levels) could cause stack overflow. Add max depth limit

📋 Pre-Merge Checklist

  • Fix global state thread safety (P1)
  • Enforce or reject pipeline_timeout_ms (P1)
  • Resolve resolve_mapping_path duplication (P2)
  • Document dollar-input alias in spec (P2)
  • Verify CI passes
  • Update CLAUDE.md with v1.0 info

🎉 Summary

Recommendation: Approve with minor revisions (P1 issues above)
Estimated Effort: 2-4 hours
Risk Level: Low

This PR represents outstanding engineering work with exceptional documentation. Great work @jonahgabriel! 🚀

…ion [OMN-465]

Replace ModelOnexError with ValueError in EnumNodeType.get_node_kind() to comply with the architectural rule that enums must not import models (prevents circular dependencies).
…g fixes [OMN-465]

- Add language specifiers to fenced code blocks (MD040 compliance)
  - docs/INDEX.md: text for directory structure
  - docs/testing/TESTMON_USAGE.md: bash for commands
  - docs/patterns/EVENT_DRIVEN_ARCHITECTURE.md: python/text
  - docs/quality/TERMINOLOGY_AUDIT_REPORT.md: python
  - docs/testing/TEST_COUNT_CLARIFICATION_SUMMARY.md: bash
  - docs/quality/DOCUMENTATION_VALIDATION_REPORT.md: bash

- Fix JSON_PATH documentation in compute_transformations.py
  - Clarify that path must start with "$" per ModelTransformJsonPathConfig validator
  - Update examples to show correct usage

- Enhance test_path_with_consecutive_dots test
  - Add test cases for leading and mixed consecutive dots
  - Improve coverage of path resolution edge cases
- Apply ruff formatting to compute_transformations.py (parenthesized imports)
- Fix test_unknown_node_type_raises_error to expect ValueError instead of
  ModelOnexError (aligning with commit 8814947 which changed to ValueError
  to avoid enum->model architectural violation)

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 (3)
src/omnibase_core/enums/enum_node_type.py (1)

204-225: Docstring inconsistency: mentions ModelOnexError but code raises ValueError.

The docstring at line 205 states "Raises: ModelOnexError" but the implementation now correctly raises ValueError (per the comment at lines 220-221 explaining the architectural constraint). Update the docstring to match the implementation.

         Returns:
             The architectural kind (COMPUTE, EFFECT, REDUCER, ORCHESTRATOR, or RUNTIME_HOST)

         Raises:
-            ModelOnexError: If the node type has no kind mapping (e.g., UNKNOWN)
+            ValueError: If the node type has no kind mapping (e.g., UNKNOWN)

         Example:
src/omnibase_core/mixins/mixin_introspection_publisher.py (1)

338-346: _detect_health_endpoint should return a generic endpoint when _node_id is unset

With the current implementation:

if hasattr(self, "health_check"):
    node_id = getattr(self, "_node_id", None) or "<unset>"
    return f"/health/{node_id}"

the method returns /health/<unset> when the node lacks an ID. While "<unset>" is a recognized sentinel throughout the codebase, including it in a discovery endpoint path is inconsistent with how related discovery metadata is structured (e.g., test fixtures and model_hub_registration_event.py use generic /health).

Prefer returning a generic endpoint when the ID is not set:

if hasattr(self, "health_check"):
    node_id_raw = getattr(self, "_node_id", None)
    return (
        f"/health/{node_id_raw}"
        if node_id_raw
        else "/health"
    )

This aligns health endpoint discovery with the pattern used elsewhere in the codebase and ensures the advertised endpoint is actionable without requiring consumers to handle the "<unset>" sentinel in URLs.

src/omnibase_core/mixins/mixin_event_handler.py (1)

112-128: Wrap UUID conversions for node_id in all logging contexts to prevent hard failures

The logging setup across _setup_event_handlers, _handle_introspection_request, _handle_node_discovery_request, and cleanup_event_handlers converts node_id to UUID without guarding against invalid strings:

node_id = getattr(self, "_node_id", None) or "<unset>"
node_id=(
    UUID(node_id)
    if isinstance(node_id, str) and node_id != "<unset>"
    else None
)

Since _node_id can be a string (returned by _load_node_id()), calling UUID(node_id) on a non-UUID string raises ValueError, turning safe logging operations into crashes. This affects lines 112–128, 209–221, 229–245, 286–299, 307–323, 390–406, and 408–424.

Use a try/except guard or the established uuid_from_string() helper (available in util_uuid_utilities):

node_id_raw = getattr(self, "_node_id", None)
node_id = node_id_raw if node_id_raw is not None else "<unset>"
log_node_id: UUID | None = None
if isinstance(node_id_raw, UUID):
    log_node_id = node_id_raw
elif isinstance(node_id, str) and node_id != "<unset>":
    try:
        log_node_id = UUID(node_id)
    except ValueError:
        log_node_id = None

Then use log_node_id in the ModelLogContext. Apply this pattern to all affected logging sites.

🧹 Nitpick comments (10)
src/omnibase_core/models/discovery/model_node_health_event.py (1)

68-72: LGTM! Consider adding constraints to other metric fields for consistency.

The non-negativity constraint on health_check_duration_ms is correct and improves data validation. However, several other metric fields would benefit from similar constraints:

  • cpu_usage_percent, memory_usage_percent, error_rate: Should have ge=0, le=100 per their descriptions
  • uptime_seconds, request_count: Should have ge=0 as counts/durations cannot be negative

Apply this diff to add consistent constraints:

 cpu_usage_percent: float | None = Field(
     default=None,
+    ge=0,
+    le=100,
     description="CPU usage percentage (0-100)",
 )
 memory_usage_percent: float | None = Field(
     default=None,
+    ge=0,
+    le=100,
     description="Memory usage percentage (0-100)",
 )
 response_time_ms: float | None = Field(
     default=None,
+    ge=0,
     description="Average response time in milliseconds",
 )

 # Operational metrics
 uptime_seconds: int | None = Field(
-    default=None, description="Node uptime in seconds"
+    default=None,
+    ge=0,
+    description="Node uptime in seconds"
 )
 error_rate: float | None = Field(
     default=None,
+    ge=0,
+    le=100,
     description="Error rate percentage (0-100)",
 )
 request_count: int | None = Field(
-    default=None, description="Total requests processed"
+    default=None,
+    ge=0,
+    description="Total requests processed"
 )
docs/testing/TESTMON_USAGE.md (1)

49-52: Minor improvement: align coverage syntax with Quick Start example.

Line 51's coverage command is valid but minimal. For clarity and consistency, consider matching the more complete format from line 20.

Apply this diff to improve clarity:

-poetry run pytest --testmon --cov --cov-fail-under=60
+poetry run pytest --testmon --cov=src/omnibase_core --cov-report=term-missing --cov-fail-under=60

This makes the scope and reporting explicit, consistent with the Quick Start example.

src/omnibase_core/models/cli/model_trace_data.py (1)

34-34: LGTM! Field-level validation is a best practice.

The ge=0 constraint appropriately enforces non-negativity at model construction and assignment time, aligning with Pydantic validation best practices for duration fields.

Optional: Consider the redundancy with the runtime check.

Lines 94-99 perform the same non-negativity check in validate_instance(). With validate_assignment=True and the ge=0 field constraint, the runtime check is now redundant—Pydantic will reject negative values before validate_instance() is ever called. You may:

  1. Remove lines 94-99 (preferred if you trust Pydantic validation), or
  2. Document why both checks exist (defense-in-depth, external data scenarios, etc.)
src/omnibase_core/models/operations/model_execution_metadata.py (1)

81-86: Non-negative constraints for error/warning counts; consider deduping validation

The ge=0 constraints on error_count and warning_count correctly enforce non-negative counts at the model level and are consistent with how counts are derived elsewhere (e.g., via len(...) in ModelValidationResult). The additional < 0 checks in validate_instance are now redundant but harmless.

If you want to simplify, you could safely drop the explicit negative-count check in validate_instance and rely on the Pydantic constraints, or keep both if you prefer the explicit ModelOnexError semantics.

Also applies to: 192-196

tests/unit/utils/test_compute_path_resolver.py (1)

517-522: Rename test to match actual behavior or add actual unicode key tests.

The test test_unicode_keys actually tests ASCII keys with underscores (user_name, full_name), not keys containing unicode characters. Consider either:

  1. Renaming to test_keys_with_underscores, or
  2. Adding actual unicode key tests (e.g., {"用户": "test", "名前": "User"})
     def test_unicode_keys(self) -> None:
-        """Test paths with unicode keys."""
-        data = {"user_name": "test", "full_name": "Test User"}
-        assert resolve_path("user_name", data) == "test"
-        assert resolve_path("full_name", data) == "Test User"
+        """Test paths with actual unicode keys."""
+        data = {"用户": "test", "名前": "Test User", "émoji_🎉": "party"}
+        assert resolve_path("用户", data) == "test"
+        assert resolve_path("名前", data) == "Test User"
+        assert resolve_path("émoji_🎉", data) == "party"
src/omnibase_core/utils/compute_transformations.py (3)

42-51: Consider moving imports above type aliases.

Type aliases JsonValue, JsonType, and TransformationHandler are defined before imports (lines 44-50), which is non-standard. While this works since these aliases don't depend on the imports below, isort and PEP 8 convention place all imports at the top.

Additionally, JsonValue and JsonType don't appear to be used within this module—they're only exported in __all__. If they exist solely for downstream consumers, consider documenting this or moving them to a shared types module.


201-210: Consider using a mapping dict for flag conversion.

The if-elif chain for flag conversion works but a mapping would be more maintainable:

+_REGEX_FLAG_MAP: dict[EnumRegexFlag, re.RegexFlag] = {
+    EnumRegexFlag.IGNORECASE: re.IGNORECASE,
+    EnumRegexFlag.MULTILINE: re.MULTILINE,
+    EnumRegexFlag.DOTALL: re.DOTALL,
+}
+
 def transform_regex(data: str, config: ModelTransformRegexConfig) -> str:
     ...
     _validate_string_input(data, "REGEX")
 
-    # Convert EnumRegexFlag to Python re flags
-    flags = 0
-    for flag in config.flags:
-        if flag == EnumRegexFlag.IGNORECASE:
-            flags |= re.IGNORECASE
-        elif flag == EnumRegexFlag.MULTILINE:
-            flags |= re.MULTILINE
-        elif flag == EnumRegexFlag.DOTALL:
-            flags |= re.DOTALL
+    flags = 0
+    for flag in config.flags:
+        flags |= _REGEX_FLAG_MAP.get(flag, 0)

549-561: Simplify transformation_type value access.

Since transformation_type is typed as EnumTransformationType, it always has a .value attribute. The hasattr check is unnecessary:

         raise ModelOnexError(
             error_code=EnumCoreErrorCode.VALIDATION_ERROR,
             message=f"Configuration required for {transformation_type} transformation",
             context={
-                "transform_type": (
-                    transformation_type.value
-                    if hasattr(transformation_type, "value")
-                    else str(transformation_type)
-                ),
+                "transform_type": transformation_type.value,
                 "input_type": type(data).__name__,
             },
         )
src/omnibase_core/mixins/mixin_introspection_publisher.py (2)

143-156: Fallback introspection logging with node_id sentinel is fine; consider centralizing the sentinel

The updated fallback now logs both node_id_raw (in the context when it’s a UUID) and a human-readable node_id string with the "" sentinel. That’s consistent with the broader sentinel approach and keeps logging safe.

Given the same "<unset>" literal appears in multiple mixins, you might consider a shared constant (e.g., NODE_ID_UNSET_SENTINEL) in a small utilities module to avoid divergence across files, but this is purely a maintainability nit.


353-369: Clarify source_node_id semantics and remove unused source_node_id_str in _publish_with_retry

In _publish_with_retry you now do:

node_id_raw = getattr(self, "_node_id", None)
...
if isinstance(node_id_raw, UUID):
    source_node_id_str = str(node_id_raw)
elif isinstance(node_id_raw, str):
    source_node_id_str = node_id_raw
else:
    source_node_id_str = "<unset>"

# Ensure source_node_id is UUID
if isinstance(node_id_raw, UUID):
    source_uuid = node_id_raw
else:
    source_uuid = uuid4()

envelope = ModelEventEnvelope.create_broadcast(
    payload=event,
    source_node_id=source_uuid,
    correlation_id=event.correlation_id,
)

Observations:

  • source_node_id_str is currently unused, so it’s just dead code and may trigger lint warnings.
  • When _node_id is a string (even a stable one), source_node_id becomes a fresh uuid4() on every call, so events from the same logical node cannot be correlated by source_node_id unless _node_id is already a UUID.

If the intention is that only true UUID-valued _node_ids participate in correlation, the behavior is fine; in that case, you can drop source_node_id_str entirely. If instead you want a stable source_node_id even for string IDs, consider deriving a UUID from the string (e.g., via the same helper used in your discovery models) rather than uuid4().

For example, minimal cleanup if you’re happy with the current semantics:

-        source_node_id_str: str
-        if isinstance(node_id_raw, UUID):
-            source_node_id_str = str(node_id_raw)
-        elif isinstance(node_id_raw, str):
-            source_node_id_str = node_id_raw
-        else:
-            source_node_id_str = "<unset>"
-        # Ensure source_node_id is UUID
-        if isinstance(node_id_raw, UUID):
-            source_uuid = node_id_raw
-        else:
-            source_uuid = uuid4()
+        if isinstance(node_id_raw, UUID):
+            source_uuid = node_id_raw
+        else:
+            source_uuid = uuid4()

Or, if you want deterministic IDs from strings, replace the uuid4() branch with your existing string→UUID helper.

Also applies to: 381-387

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ed7c5d7 and 01c178e.

📒 Files selected for processing (20)
  • docs/INDEX.md (1 hunks)
  • docs/architecture/CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md (1 hunks)
  • docs/architecture/NODECOMPUTE_VERSIONING_ROADMAP.md (1 hunks)
  • docs/patterns/EVENT_DRIVEN_ARCHITECTURE.md (11 hunks)
  • docs/quality/DOCUMENTATION_VALIDATION_REPORT.md (2 hunks)
  • docs/quality/TERMINOLOGY_AUDIT_REPORT.md (2 hunks)
  • docs/testing/TESTMON_USAGE.md (4 hunks)
  • docs/testing/TEST_COUNT_CLARIFICATION_SUMMARY.md (2 hunks)
  • src/omnibase_core/enums/enum_node_type.py (1 hunks)
  • src/omnibase_core/mixins/mixin_compute_execution.py (1 hunks)
  • src/omnibase_core/mixins/mixin_event_handler.py (7 hunks)
  • src/omnibase_core/mixins/mixin_introspection_publisher.py (9 hunks)
  • src/omnibase_core/models/cli/model_result_summary.py (1 hunks)
  • src/omnibase_core/models/cli/model_trace_data.py (1 hunks)
  • src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py (1 hunks)
  • src/omnibase_core/models/discovery/model_node_health_event.py (1 hunks)
  • src/omnibase_core/models/events/model_intent_execution_result.py (1 hunks)
  • src/omnibase_core/models/operations/model_execution_metadata.py (2 hunks)
  • src/omnibase_core/utils/compute_transformations.py (1 hunks)
  • tests/unit/utils/test_compute_path_resolver.py (1 hunks)
✅ Files skipped from review due to trivial changes (4)
  • docs/INDEX.md
  • docs/quality/DOCUMENTATION_VALIDATION_REPORT.md
  • docs/testing/TEST_COUNT_CLARIFICATION_SUMMARY.md
  • docs/architecture/CONTRACT_DRIVEN_NODECOMPUTE_V1_0.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/omnibase_core/mixins/mixin_compute_execution.py
🧰 Additional context used
📓 Path-based instructions (5)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Always use Poetry for Python package management and task execution. Use poetry run for pytest, mypy, black, isort, and other tools. Never use pip directly or execute python commands without the poetry run prefix.
Enforce 100% strict mypy compliance. All functions must have complete type annotations. Use poetry run mypy src/omnibase_core/ to verify strict mode compliance with no errors.
Format code with black, sort imports with isort, and lint with ruff. Run poetry run black src/ tests/, poetry run isort src/ tests/, and poetry run ruff check --fix src/ tests/

Files:

  • src/omnibase_core/models/cli/model_trace_data.py
  • src/omnibase_core/models/operations/model_execution_metadata.py
  • src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py
  • src/omnibase_core/enums/enum_node_type.py
  • src/omnibase_core/mixins/mixin_introspection_publisher.py
  • src/omnibase_core/mixins/mixin_event_handler.py
  • src/omnibase_core/models/discovery/model_node_health_event.py
  • src/omnibase_core/models/cli/model_result_summary.py
  • src/omnibase_core/models/events/model_intent_execution_result.py
  • src/omnibase_core/utils/compute_transformations.py
  • tests/unit/utils/test_compute_path_resolver.py
src/omnibase_core/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/omnibase_core/**/*.py: Use protocol names with container.get_service() for dependency injection, never resolve services by concrete class names. Example: container.get_service('ProtocolEventBus') instead of container.get_service('EventBusService')
Always use ModelONEXContainer for dependency injection in node constructors and service resolution. Never confuse it with ModelContainer[T], which is a generic value wrapper, not a DI container.
Use structured error handling with ModelOnexError and EnumCoreErrorCode, never raise generic Exception. Always chain exceptions with from e when catching and re-raising.
Use the @standard_error_handling decorator on methods to eliminate 6+ lines of try/catch boilerplate. Example: @standard_error_handling above async methods.
Respect thread safety constraints: Do NOT share node instances (NodeCompute, NodeEffect), cache, or circuit breaker instances across threads without synchronization. Use thread-local instances or locks.
Use duck typing with protocols. Do not use isinstance checks with protocol types. Rely on the protocol interface directly.
Use EnumNodeKind for high-level architectural classification (EFFECT, COMPUTE, REDUCER, ORCHESTRATOR) when routing data through the ONEX pipeline. Use EnumNodeType for specific implementation discovery and capability matching.
Use ModelEventEnvelope for inter-service event-driven communication. Process events through the envelope pattern for consistent event handling.

Files:

  • src/omnibase_core/models/cli/model_trace_data.py
  • src/omnibase_core/models/operations/model_execution_metadata.py
  • src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py
  • src/omnibase_core/enums/enum_node_type.py
  • src/omnibase_core/mixins/mixin_introspection_publisher.py
  • src/omnibase_core/mixins/mixin_event_handler.py
  • src/omnibase_core/models/discovery/model_node_health_event.py
  • src/omnibase_core/models/cli/model_result_summary.py
  • src/omnibase_core/models/events/model_intent_execution_result.py
  • src/omnibase_core/utils/compute_transformations.py
src/omnibase_core/models/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Use Pydantic 2.11+ models for all data validation and serialization. Ensure models are immutable after creation for thread safety.

Files:

  • src/omnibase_core/models/cli/model_trace_data.py
  • src/omnibase_core/models/operations/model_execution_metadata.py
  • src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py
  • src/omnibase_core/models/discovery/model_node_health_event.py
  • src/omnibase_core/models/cli/model_result_summary.py
  • src/omnibase_core/models/events/model_intent_execution_result.py
src/omnibase_core/mixins/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Mixin classes should be composed into node classes for specific capabilities. Available mixins include: MixinDiscoveryResponder, MixinEventHandler, MixinEventListener, MixinNodeExecutor, MixinNodeLifecycle, MixinRequestResponseIntrospection, MixinWorkflowSupport.

Files:

  • src/omnibase_core/mixins/mixin_introspection_publisher.py
  • src/omnibase_core/mixins/mixin_event_handler.py
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Write tests using pytest with async support via pytest-asyncio. Maintain minimum 60% code coverage. Use pytest markers: @pytest.mark.unit, @pytest.mark.integration, @pytest.mark.slow
Add @pytest.mark.timeout() to prevent test hangs. Run tests with poetry run pytest tests/ --timeout=60 for 60-second timeout protection.

Files:

  • tests/unit/utils/test_compute_path_resolver.py
🧠 Learnings (21)
📓 Common learnings
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/nodes/node_compute.py : NodeCompute is for data processing and transformation. Inherit from NodeCompute for COMPUTE nodes that perform calculations, validations, and data mapping.
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/**/*.py : Always use ModelONEXContainer for dependency injection in node constructors and service resolution. Never confuse it with ModelContainer[T], which is a generic value wrapper, not a DI container.

Applied to files:

  • docs/quality/TERMINOLOGY_AUDIT_REPORT.md
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/nodes/**/*.py : Node classes must always call `super().__init__(container)` in their constructor with a ModelONEXContainer parameter. This eliminates 80+ lines of boilerplate initialization code.

Applied to files:

  • docs/quality/TERMINOLOGY_AUDIT_REPORT.md
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/**/*.py : Use protocol names with `container.get_service()` for dependency injection, never resolve services by concrete class names. Example: `container.get_service('ProtocolEventBus')` instead of `container.get_service('EventBusService')`

Applied to files:

  • docs/quality/TERMINOLOGY_AUDIT_REPORT.md
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Protocol-Driven Dependency Injection should use container-based service resolution with protocol interfaces, not concrete class registry dependencies. This ensures loose coupling and testability.

Applied to files:

  • docs/quality/TERMINOLOGY_AUDIT_REPORT.md
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/**/*.py : Use EnumNodeKind for high-level architectural classification (EFFECT, COMPUTE, REDUCER, ORCHESTRATOR) when routing data through the ONEX pipeline. Use EnumNodeType for specific implementation discovery and capability matching.

Applied to files:

  • src/omnibase_core/enums/enum_node_type.py
  • docs/patterns/EVENT_DRIVEN_ARCHITECTURE.md
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/**/*.py : Use structured error handling with ModelOnexError and EnumCoreErrorCode, never raise generic Exception. Always chain exceptions with `from e` when catching and re-raising.

Applied to files:

  • src/omnibase_core/enums/enum_node_type.py
  • docs/patterns/EVENT_DRIVEN_ARCHITECTURE.md
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/mixins/**/*.py : Mixin classes should be composed into node classes for specific capabilities. Available mixins include: MixinDiscoveryResponder, MixinEventHandler, MixinEventListener, MixinNodeExecutor, MixinNodeLifecycle, MixinRequestResponseIntrospection, MixinWorkflowSupport.

Applied to files:

  • src/omnibase_core/mixins/mixin_introspection_publisher.py
  • src/omnibase_core/mixins/mixin_event_handler.py
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/**/*.py : Use ModelEventEnvelope for inter-service event-driven communication. Process events through the envelope pattern for consistent event handling.

Applied to files:

  • src/omnibase_core/mixins/mixin_introspection_publisher.py
  • docs/patterns/EVENT_DRIVEN_ARCHITECTURE.md
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/models/**/*.py : Use Pydantic 2.11+ models for all data validation and serialization. Ensure models are immutable after creation for thread safety.

Applied to files:

  • docs/patterns/EVENT_DRIVEN_ARCHITECTURE.md
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/nodes/node_reducer.py : NodeReducer is for FSM-driven state aggregation and management. Use ModelIntent for state transitions. This is the PRIMARY implementation as of v0.4.0 (replaces NodeReducerDeclarative).

Applied to files:

  • docs/patterns/EVENT_DRIVEN_ARCHITECTURE.md
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Respect the ONEX Four-Node Architecture: data flows unidirectionally from EFFECT → COMPUTE → REDUCER → ORCHESTRATOR with no backwards dependencies. This is an architectural principle, not tied to specific files.

Applied to files:

  • docs/patterns/EVENT_DRIVEN_ARCHITECTURE.md
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/nodes/node_compute.py : NodeCompute is for data processing and transformation. Inherit from NodeCompute for COMPUTE nodes that perform calculations, validations, and data mapping.

Applied to files:

  • docs/patterns/EVENT_DRIVEN_ARCHITECTURE.md
  • src/omnibase_core/utils/compute_transformations.py
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/nodes/node_effect.py : NodeEffect is for external interactions (I/O). Inherit from NodeEffect for EFFECT nodes that handle API calls, database operations, file system, or message queues.

Applied to files:

  • docs/patterns/EVENT_DRIVEN_ARCHITECTURE.md
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Always verify setup with: `poetry run pytest tests/ -x`, `poetry run mypy src/omnibase_core/`, and `pre-commit run --all-files` before development cycles.

Applied to files:

  • docs/testing/TESTMON_USAGE.md
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to **/*.py : Always use Poetry for Python package management and task execution. Use `poetry run` for pytest, mypy, black, isort, and other tools. Never use pip directly or execute python commands without the poetry run prefix.

Applied to files:

  • docs/testing/TESTMON_USAGE.md
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to **/*.py : Format code with black, sort imports with isort, and lint with ruff. Run `poetry run black src/ tests/`, `poetry run isort src/ tests/`, and `poetry run ruff check --fix src/ tests/`

Applied to files:

  • docs/testing/TESTMON_USAGE.md
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to tests/**/*.py : Add pytest.mark.timeout() to prevent test hangs. Run tests with `poetry run pytest tests/ --timeout=60` for 60-second timeout protection.

Applied to files:

  • docs/testing/TESTMON_USAGE.md
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to tests/**/*.py : Write tests using pytest with async support via pytest-asyncio. Maintain minimum 60% code coverage. Use pytest markers: pytest.mark.unit, pytest.mark.integration, pytest.mark.slow

Applied to files:

  • docs/testing/TESTMON_USAGE.md
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to .pre-commit-config.yaml : Pre-commit hooks must include: mypy with strict mode, black formatting, isort import sorting, and ruff linting. Run `pre-commit install` during setup and `pre-commit run --all-files` before commits.

Applied to files:

  • docs/testing/TESTMON_USAGE.md
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to **/*.py : Enforce 100% strict mypy compliance. All functions must have complete type annotations. Use `poetry run mypy src/omnibase_core/` to verify strict mode compliance with no errors.

Applied to files:

  • docs/testing/TESTMON_USAGE.md
🧬 Code graph analysis (6)
src/omnibase_core/models/operations/model_execution_metadata.py (1)
src/omnibase_core/models/common/model_validation_result.py (2)
  • error_count (94-96)
  • warning_count (99-101)
src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py (4)
src/omnibase_core/enums/enum_compute_step_type.py (1)
  • EnumComputeStepType (50-91)
src/omnibase_core/enums/enum_transformation_type.py (1)
  • EnumTransformationType (11-34)
src/omnibase_core/models/transformations/model_mapping_config.py (1)
  • ModelMappingConfig (13-37)
src/omnibase_core/models/transformations/model_validation_step_config.py (1)
  • ModelValidationStepConfig (13-30)
src/omnibase_core/mixins/mixin_introspection_publisher.py (1)
src/omnibase_core/models/discovery/model_nodeintrospectionevent.py (2)
  • ModelNodeIntrospectionEvent (13-176)
  • create_from_node_info (123-176)
src/omnibase_core/models/cli/model_result_summary.py (2)
src/omnibase_core/protocols/event_bus.py (1)
  • retry_count (176-178)
src/omnibase_core/models/common/model_validation_result.py (2)
  • error_count (94-96)
  • warning_count (99-101)
src/omnibase_core/utils/compute_transformations.py (11)
src/omnibase_core/enums/enum_case_mode.py (1)
  • EnumCaseMode (10-22)
src/omnibase_core/enums/enum_core_error_code.py (1)
  • EnumCoreErrorCode (9-154)
src/omnibase_core/enums/enum_regex_flag.py (1)
  • EnumRegexFlag (10-22)
src/omnibase_core/enums/enum_transformation_type.py (1)
  • EnumTransformationType (11-34)
src/omnibase_core/enums/enum_trim_mode.py (1)
  • EnumTrimMode (10-22)
src/omnibase_core/enums/enum_unicode_form.py (1)
  • EnumUnicodeForm (10-24)
src/omnibase_core/models/transformations/model_transform_case_config.py (1)
  • ModelTransformCaseConfig (15-27)
src/omnibase_core/models/transformations/model_transform_json_path_config.py (1)
  • ModelTransformJsonPathConfig (13-35)
src/omnibase_core/models/transformations/model_transform_regex_config.py (1)
  • ModelTransformRegexConfig (15-31)
src/omnibase_core/models/transformations/model_transform_trim_config.py (1)
  • ModelTransformTrimConfig (15-27)
src/omnibase_core/models/transformations/model_transform_unicode_config.py (1)
  • ModelTransformUnicodeConfig (15-27)
tests/unit/utils/test_compute_path_resolver.py (1)
src/omnibase_core/utils/compute_path_resolver.py (5)
  • PathResolutionError (98-138)
  • resolve_input_path (332-384)
  • resolve_path (272-329)
  • resolve_pipeline_path (487-551)
  • resolve_step_path (387-484)
🪛 LanguageTool
docs/architecture/NODECOMPUTE_VERSIONING_ROADMAP.md

[style] ~55-~55: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...itions. Boring code is debuggable code. Boring APIs are learnable APIs. Stable: O...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Smoke Tests
🔇 Additional comments (35)
src/omnibase_core/models/events/model_intent_execution_result.py (1)

51-55: Non-negative constraint on execution_duration_ms looks correct

Adding ge=0 keeps None valid while preventing negative durations, which matches the semantics of an execution time in milliseconds and aligns with the other timing fields introduced in this PR. Only payloads that previously sent invalid negative values will now fail validation, which is an appropriate tightening of the contract.

docs/testing/TESTMON_USAGE.md (4)

9-21: LGTM! Quick Start section provides clear, accurate examples with proper poetry run prefix and coverage integration.


37-43: LGTM! Local Development examples are clear and correct—reset procedure with --testmon-noselect is the right approach.


56-59: LGTM! Full Suite command is correct and clear.


86-106: LGTM! Troubleshooting section provides clear guidance with correct poetry run examples and proper database reset procedures. The Correct/Wrong comparison at lines 94-98 effectively reinforces the poetry requirement from coding guidelines.

src/omnibase_core/models/cli/model_result_summary.py (1)

36-42: LGTM! Non-negativity constraints improve data integrity.

The ge=0 constraints on duration and count fields are semantically correct and align with the strict validation patterns introduced across the NodeCompute v1.0 compute pipeline models. With validate_assignment=True, these constraints are enforced both at creation and on subsequent assignments, preventing invalid states.

src/omnibase_core/models/operations/model_execution_metadata.py (1)

48-52: Non-negative constraint on duration_ms is consistent and safe

Adding ge=0 to duration_ms aligns with the existing logical validation in validate_instance and the broader pattern of non-negative duration fields across the models. No behavioral concerns from this change.

docs/patterns/EVENT_DRIVEN_ARCHITECTURE.md (3)

15-26: LGTM! Proper code fence language specification and ModelEventEnvelope usage.

The example correctly demonstrates the event envelope pattern with ModelEventEnvelope for inter-service communication. Based on learnings, this aligns with the project's event-driven architecture guidelines.


93-110: LGTM! Correct protocol-based service resolution.

The example at line 106 correctly uses container.get_service("ProtocolEventBus") for dependency injection, following the coding guideline to resolve services by protocol names rather than concrete class names.


187-197: LGTM! Good demonstration of structured payload best practice.

The example effectively contrasts unstructured payloads with Pydantic model-based structured payloads, reinforcing the guideline to use Pydantic models for data validation.

docs/architecture/NODECOMPUTE_VERSIONING_ROADMAP.md (3)

130-139: LGTM! Timeline appropriately updated to milestone-based scheduling.

The timeline now correctly uses milestone-based sequencing rather than specific calendar dates, with the clarifying note that implementation depends on production feedback. This addresses the previous review concern about outdated Q1 2025 references.


766-779: Good clarification on registry lockdown.

The documentation clearly states that the transformation registry is internal-only and user-defined transformations are not supported. This is an important design decision that prevents determinism, replay, and security issues.


505-514: This is prospective documentation—ModelComputeCaching is not yet implemented.

The documented Pydantic v2 pattern with model_config = ConfigDict(extra="forbid", frozen=True) is correct and follows best practices for immutability. No discrepancies exist between documentation and implementation because this is a planned feature in the roadmap, not yet implemented in the codebase.

src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py (4)

33-50: LGTM! YAML example now uses correct lowercase enum values.

The example correctly shows transformation_type: "case_conversion" matching the EnumTransformationType string values. This addresses the previous review concern about uppercase enum values failing validation.


70-78: LGTM! Clean imports with proper type organization.

Imports are well-organized, bringing in the necessary enums and model types. The use of a discriminated union type (ModelTransformationConfig) from the types module is appropriate for handling multiple transformation config types.


170-171: LGTM! Proper Pydantic v2 configuration.

The model correctly uses ConfigDict(extra="forbid", frozen=True) ensuring immutability and strict field validation, which aligns with the coding guidelines for thread-safe models.


173-202: LGTM! Comprehensive step configuration validation.

The @model_validator(mode="after") correctly enforces:

  1. TRANSFORMATION steps require transformation_type
  2. Non-IDENTITY transformations require transformation_config
  3. IDENTITY transformations must NOT have config (important design decision)
  4. MAPPING steps require mapping_config
  5. VALIDATION steps require validation_config

This validation ensures contracts are well-formed at construction time rather than failing at execution.

src/omnibase_core/enums/enum_node_type.py (1)

220-225: LGTM! Correct architectural fix to avoid enum→model import cycle.

The change from ModelOnexError to ValueError properly respects the architectural constraint that enums should not import models. The comment clearly documents the rationale, and the error message includes helpful context (the unmapped type and available types).

docs/quality/TERMINOLOGY_AUDIT_REPORT.md (2)

171-179: LGTM! Code fence language specification added.

Adding the python language identifier to the code block enables proper syntax highlighting, improving documentation readability.


205-209: LGTM! Consistent code fence formatting.

The code example correctly demonstrates resolving services by protocol interface ("ProtocolEventBus"), which aligns with the coding guidelines.

tests/unit/utils/test_compute_path_resolver.py (7)

1-29: LGTM!

Well-structured module docstring clearly documents test categories. Imports are minimal and appropriate for the test scope.


31-55: LGTM!

Test fixtures are well-designed with MockStepResult for step output testing, MockObject with private attributes for security testing, and NestedObject for nested traversal scenarios.


62-172: LGTM!

Comprehensive test coverage for resolve_path including root access, nested traversal, mixed dict/object access, error handling, and private attribute security. Tests properly use @pytest.mark.unit and @pytest.mark.timeout(30) per coding guidelines.


179-240: LGTM!

Tests cover both $.input and $input alias forms, nested access, error handling, and private attribute security on input objects while correctly allowing underscore dict keys.


247-332: LGTM!

Excellent coverage of step path resolution including shorthand/explicit form equivalence, multiple steps, various output types, and comprehensive error scenarios (missing step, invalid subpath, empty step name).


402-461: LGTM with a note on context access pattern.

The tests for PathResolutionError correctly verify error creation and context fields. The nested access pattern (error.context.get("additional_context", {}).get("context", {})) appears to match how ModelOnexError wraps custom context. The subclass relationship test at lines 455-460 ensures proper error hierarchy.


536-567: LGTM!

Good stress test for deeply nested paths (50 levels) and thorough coverage of step name variations including underscores and numbers.

src/omnibase_core/utils/compute_transformations.py (7)

73-112: LGTM!

Clean DRY helper with proper error handling using ModelOnexError and EnumCoreErrorCode.VALIDATION_ERROR per coding guidelines. Good error context for debugging.


122-167: LGTM!

Identity transformation is clean with good documentation explaining the config parameter's purpose for registry uniformity. Using del config to satisfy linters is acceptable.


226-273: LGTM!

Case transformation is straightforward with good defensive error handling for unknown modes. The else branch guards against future enum additions.


275-323: LGTM!

Trim transformation follows the same clean pattern as case transformation with proper validation and defensive error handling.


325-361: LGTM!

Unicode normalization is clean and correctly uses config.form.value to get the normalization form string for unicodedata.normalize. Docstring example now correctly shows 'café'.


363-475: LGTM!

The implementation correctly differentiates between dict keys (allowing underscore keys) and object attributes (blocking private attributes starting with _). The TODO acknowledges potential deduplication with compute_path_resolver.py.


568-582: LGTM!

Clean and complete __all__ export list covering type aliases, individual transformation functions, the dispatcher, and the registry.

src/omnibase_core/mixins/mixin_event_handler.py (1)

343-345: target_node_id matching normalization looks reasonable

Normalizing _node_id through a single str(node_id) before fnmatch.fnmatch keeps matching behavior consistent whether _node_id is a UUID or a string, while the "" sentinel ensures nodes without an ID won’t accidentally match typical concrete target_node_id patterns.

Comment on lines +50 to 52
node_id_raw = getattr(self, "_node_id", None)
node_id = node_id_raw if node_id_raw is not None else "<unset>"
try:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat src/omnibase_core/mixins/mixin_introspection_publisher.py

Repository: OmniNode-ai/omnibase_core

Length of output: 16700


🏁 Script executed:

rg "class ModelNodeIntrospectionEvent" src/ --type py -A 30

Repository: OmniNode-ai/omnibase_core

Length of output: 3348


🏁 Script executed:

rg "def create_from_node_info" src/ --type py -A 15

Repository: OmniNode-ai/omnibase_core

Length of output: 1623


🏁 Script executed:

rg "uuid_from_string|def.*uuid.*from" src/ --type py -A 5

Repository: OmniNode-ai/omnibase_core

Length of output: 50381


Avoid UUID(node_id) on arbitrary strings when publishing introspection events

The code at lines 65-69 attempts to convert node_id to a UUID using UUID(node_id), which will raise ValueError if node_id is a non-empty non-UUID-format string. However, ModelNodeIntrospectionEvent.create_from_node_info() accepts node_id: UUID | str and has a field validator that safely converts strings to UUIDs using uuid_from_string() from the utilities module.

Instead of manually constructing event_node_id with fallible UUID() conversion, pass node_id_raw directly to create_from_node_info() and let the model's validator handle the conversion:

         node_id_raw = getattr(self, "_node_id", None)
-        node_id = node_id_raw if node_id_raw is not None else "<unset>"
+        node_id = node_id_raw if node_id_raw is not None else uuid4()
         try:
             introspection_data = self._gather_introspection_data()
             correlation_id = uuid4()
             if not hasattr(self, "get_node_type"):
                 raise ModelOnexError(
                     message=f"Node {self.__class__.__name__} must implement get_node_type() "
                     "returning one of: effect, compute, reducer, orchestrator",
                     error_code=EnumCoreErrorCode.VALIDATION_ERROR,
                 )
             node_type = self.get_node_type()
-            # For creating the event, we need a valid UUID - generate one if unset
-            event_node_id = (
-                UUID(node_id)
-                if isinstance(node_id, str) and node_id != "<unset>"
-                else (node_id_raw if isinstance(node_id_raw, UUID) else uuid4())
-            )
             introspection_event = ModelNodeIntrospectionEvent.create_from_node_info(
-                node_id=event_node_id,
+                node_id=node_id,
                 node_name=introspection_data.node_name,

Also remove the "<unset>" sentinel from the health endpoint URL construction at line 338—use a UUID fallback instead:

     def _detect_health_endpoint(self) -> str | None:
         """Detect if this node has a health endpoint."""
         try:
             if hasattr(self, "health_check"):
-                node_id = getattr(self, "_node_id", None) or "<unset>"
+                node_id = getattr(self, "_node_id", None) or uuid4()
                 return f"/health/{node_id}"
         except Exception:
             pass
         return None

In _publish_with_retry() at lines 381–387, the variable source_node_id_str is computed but never used; derive source_uuid directly instead:

         source_node_id_str: str
         if isinstance(node_id_raw, UUID):
             source_node_id_str = str(node_id_raw)
         elif isinstance(node_id_raw, str):
             source_node_id_str = node_id_raw
         else:
             source_node_id_str = "<unset>"
         # Ensure source_node_id is UUID
         if isinstance(node_id_raw, UUID):
             source_uuid = node_id_raw
         else:
             source_uuid = uuid4()

Remove the unused source_node_id_str variable and simplify the UUID derivation.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
node_id_raw = getattr(self, "_node_id", None)
node_id = node_id_raw if node_id_raw is not None else "<unset>"
try:
node_id_raw = getattr(self, "_node_id", None)
node_id = node_id_raw if node_id_raw is not None else uuid4()
try:
🤖 Prompt for AI Agents
In src/omnibase_core/mixins/mixin_introspection_publisher.py around lines 50–52
and the later referenced offsets, replace the manual, fallible UUID(node_id)
conversion by passing node_id_raw (the original attribute value) directly into
ModelNodeIntrospectionEvent.create_from_node_info so the model validator uses
uuid_from_string safely; remove the "<unset>" sentinel when building the health
endpoint URL at the health URL construction site (line ~338) and instead use a
proper UUID fallback (e.g., derive or cast to a UUID) so the URL always contains
a valid UUID; and in _publish_with_retry (lines ~381–387) remove the unused
source_node_id_str variable and compute source_uuid directly from the original
source node id value to simplify logic and avoid unused variables.

…MN-465]

Fix test_unknown_type_intentionally_unmapped to expect ValueError instead of
ModelOnexError, matching the architectural change in enum_node_type.py that
avoids enum->model import violations.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
tests/unit/enums/test_enum_node_kind.py (1)

475-475: Add pytest markers per coding guidelines.

The test function is missing the @pytest.mark.unit marker. Per the coding guidelines, all test functions should use pytest markers to categorize tests.

As per coding guidelines, add the appropriate markers:

+    @pytest.mark.unit
+    @pytest.mark.timeout(5)
     def test_unknown_node_type_raises_error(self) -> None:

Note: This appears to be a pattern throughout the file—consider adding markers to all test methods in a follow-up.

src/omnibase_core/utils/compute_transformations.py (2)

126-171: Consider enforcing “IDENTITY has no config” invariant inside execute_transformation.

Right now the “no config for IDENTITY” rule is enforced at the ModelComputePipelineStep contract level and documented in transform_identity, but execute_transformation will silently accept a non-None config for EnumTransformationType.IDENTITY and ignore it.

To make the invariant self-contained at the dispatcher boundary (and closer to the spec that IDENTITY has no config), consider tightening the config checks like this:

 def execute_transformation(
     data: Any,
     transformation_type: EnumTransformationType,
     config: ModelTransformationConfig | None,
 ) -> Any:
@@
-    # Validate config requirements:
-    # - IDENTITY: config must be None (no configuration needed)
-    # - All others: config is required
-    # Contract-level validation (ModelComputePipelineStep) ensures IDENTITY steps
-    # never have transformation_config set, so config will be None here.
-    if transformation_type != EnumTransformationType.IDENTITY and config is None:
-        raise ModelOnexError(
-            error_code=EnumCoreErrorCode.VALIDATION_ERROR,
-            message=f"Configuration required for {transformation_type} transformation",
-            context={
-                "transform_type": (
-                    transformation_type.value
-                    if hasattr(transformation_type, "value")
-                    else str(transformation_type)
-                ),
-                "input_type": type(data).__name__,
-            },
-        )
+    # Validate config requirements:
+    # - IDENTITY: config must be None (no configuration allowed)
+    # - All others: config is required
+    if transformation_type == EnumTransformationType.IDENTITY:
+        if config is not None:
+            raise ModelOnexError(
+                error_code=EnumCoreErrorCode.VALIDATION_ERROR,
+                message="IDENTITY transformation must not have configuration",
+                context={
+                    "transform_type": transformation_type.value,
+                    "input_type": type(data).__name__,
+                },
+            )
+    elif config is None:
+        raise ModelOnexError(
+            error_code=EnumCoreErrorCode.VALIDATION_ERROR,
+            message=f"Configuration required for {transformation_type} transformation",
+            context={
+                "transform_type": transformation_type.value,
+                "input_type": type(data).__name__,
+            },
+        )

This keeps pipeline behavior unchanged (since steps are already validated) but hardens the public API against misuse and makes the “IDENTITY has no config” rule true no matter how execute_transformation is invoked.

Also applies to: 493-569


373-425: Minor: simplify root-path handling in transform_json_path now that path is always non-empty.

Given ModelTransformJsonPathConfig.validate_path already enforces that path is non-empty and starts with "$", the not path part of the root check is effectively unreachable unless someone bypasses Pydantic validation.

You could simplify this block to reflect the contract more directly:

-    path = config.path
-
-    # Handle root-level access
-    if not path or path == "$":
-        return data
+    path = config.path
+
+    # Handle root-level access (validated to be a non-empty '$'-prefixed path)
+    if path == "$":
+        return data

Not essential, but it tightens the implementation to the documented model constraints and makes the early-return condition easier to read.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 01c178e and ee13578.

📒 Files selected for processing (2)
  • src/omnibase_core/utils/compute_transformations.py (1 hunks)
  • tests/unit/enums/test_enum_node_kind.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Always use Poetry for Python package management and task execution. Use poetry run for pytest, mypy, black, isort, and other tools. Never use pip directly or execute python commands without the poetry run prefix.
Enforce 100% strict mypy compliance. All functions must have complete type annotations. Use poetry run mypy src/omnibase_core/ to verify strict mode compliance with no errors.
Format code with black, sort imports with isort, and lint with ruff. Run poetry run black src/ tests/, poetry run isort src/ tests/, and poetry run ruff check --fix src/ tests/

Files:

  • tests/unit/enums/test_enum_node_kind.py
  • src/omnibase_core/utils/compute_transformations.py
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Write tests using pytest with async support via pytest-asyncio. Maintain minimum 60% code coverage. Use pytest markers: @pytest.mark.unit, @pytest.mark.integration, @pytest.mark.slow
Add @pytest.mark.timeout() to prevent test hangs. Run tests with poetry run pytest tests/ --timeout=60 for 60-second timeout protection.

Files:

  • tests/unit/enums/test_enum_node_kind.py
src/omnibase_core/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/omnibase_core/**/*.py: Use protocol names with container.get_service() for dependency injection, never resolve services by concrete class names. Example: container.get_service('ProtocolEventBus') instead of container.get_service('EventBusService')
Always use ModelONEXContainer for dependency injection in node constructors and service resolution. Never confuse it with ModelContainer[T], which is a generic value wrapper, not a DI container.
Use structured error handling with ModelOnexError and EnumCoreErrorCode, never raise generic Exception. Always chain exceptions with from e when catching and re-raising.
Use the @standard_error_handling decorator on methods to eliminate 6+ lines of try/catch boilerplate. Example: @standard_error_handling above async methods.
Respect thread safety constraints: Do NOT share node instances (NodeCompute, NodeEffect), cache, or circuit breaker instances across threads without synchronization. Use thread-local instances or locks.
Use duck typing with protocols. Do not use isinstance checks with protocol types. Rely on the protocol interface directly.
Use EnumNodeKind for high-level architectural classification (EFFECT, COMPUTE, REDUCER, ORCHESTRATOR) when routing data through the ONEX pipeline. Use EnumNodeType for specific implementation discovery and capability matching.
Use ModelEventEnvelope for inter-service event-driven communication. Process events through the envelope pattern for consistent event handling.

Files:

  • src/omnibase_core/utils/compute_transformations.py
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/nodes/node_compute.py : NodeCompute is for data processing and transformation. Inherit from NodeCompute for COMPUTE nodes that perform calculations, validations, and data mapping.
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/**/*.py : Use EnumNodeKind for high-level architectural classification (EFFECT, COMPUTE, REDUCER, ORCHESTRATOR) when routing data through the ONEX pipeline. Use EnumNodeType for specific implementation discovery and capability matching.

Applied to files:

  • tests/unit/enums/test_enum_node_kind.py
📚 Learning: 2025-12-06T23:34:11.788Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-06T23:34:11.788Z
Learning: Applies to src/omnibase_core/**/*.py : Use structured error handling with ModelOnexError and EnumCoreErrorCode, never raise generic Exception. Always chain exceptions with `from e` when catching and re-raising.

Applied to files:

  • tests/unit/enums/test_enum_node_kind.py
🧬 Code graph analysis (2)
tests/unit/enums/test_enum_node_kind.py (1)
src/omnibase_core/enums/enum_node_type.py (2)
  • EnumNodeType (96-321)
  • get_node_kind (194-227)
src/omnibase_core/utils/compute_transformations.py (11)
src/omnibase_core/enums/enum_case_mode.py (1)
  • EnumCaseMode (10-22)
src/omnibase_core/enums/enum_core_error_code.py (1)
  • EnumCoreErrorCode (9-154)
src/omnibase_core/enums/enum_regex_flag.py (1)
  • EnumRegexFlag (10-22)
src/omnibase_core/enums/enum_transformation_type.py (1)
  • EnumTransformationType (11-34)
src/omnibase_core/enums/enum_trim_mode.py (1)
  • EnumTrimMode (10-22)
src/omnibase_core/enums/enum_unicode_form.py (1)
  • EnumUnicodeForm (10-24)
src/omnibase_core/models/transformations/model_transform_case_config.py (1)
  • ModelTransformCaseConfig (15-27)
src/omnibase_core/models/transformations/model_transform_json_path_config.py (1)
  • ModelTransformJsonPathConfig (13-35)
src/omnibase_core/models/transformations/model_transform_regex_config.py (1)
  • ModelTransformRegexConfig (15-31)
src/omnibase_core/models/transformations/model_transform_trim_config.py (1)
  • ModelTransformTrimConfig (15-27)
src/omnibase_core/models/transformations/model_transform_unicode_config.py (1)
  • ModelTransformUnicodeConfig (15-27)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Smoke Tests
🔇 Additional comments (3)
tests/unit/enums/test_enum_node_kind.py (1)

476-495: LGTM! Test correctly validates ValueError for UNKNOWN node type.

The test changes correctly implement the architectural decision to use ValueError instead of ModelOnexError to avoid circular enum→model imports. The docstring clearly explains the design rationale, and the assertion appropriately validates that the error message contains "UNKNOWN".

src/omnibase_core/utils/compute_transformations.py (2)

1-50: Module-level design, docs, and type aliases are clear and consistent.

The top-level docstring, thread-safety notes, and JsonValue / JsonType / TransformationHandler aliases nicely document the intended usage and constraints for this module. The examples align with the actual API surface and NodeCompute v1.0 spec as described in the PR.


77-116: Good reuse of _validate_string_input and consistent ModelOnexError usage.

Centralizing string-type validation in _validate_string_input and reusing it across REGEX/CASE/TRIM/UNICODE keeps error semantics consistent and matches the guideline to raise ModelOnexError with EnumCoreErrorCode.VALIDATION_ERROR for type issues. No changes needed here.

Also applies to: 173-365

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant