Skip to content

feat(contracts): implement ModelContractVersion with typed semver fields [OMN-154] - #116

Merged
jonahgabriel merged 6 commits into
mainfrom
jonah/omn-154-06-create-modelcontractversion-with-typed-semver-fields
Dec 8, 2025
Merged

jonahgabriel merged 6 commits into
mainfrom
jonah/omn-154-06-create-modelcontractversion-with-typed-semver-fields

Conversation

@jonahgabriel

@jonahgabriel jonahgabriel commented Dec 7, 2025 •

Copy link
Copy Markdown
Contributor

Summary

Implements ModelContractVersion with typed semver fields per CONTRACT_STABILITY_SPEC.md requirements.

  • Create ModelContractVersion Pydantic model with major, minor, patch int fields
  • Implement full comparison operators (__eq__, __lt__, __le__, __gt__, __ge__)
  • Add version bumping methods (bump_major, bump_minor, bump_patch)
  • Add downgrade protection via validate_progression(allow_downgrade=False)
  • Add factory methods from_string() and from_tuple()
  • Ensure immutability with frozen=True, extra="forbid", strict=True
  • Add comprehensive TDD tests (86 tests, 88% coverage)
  • Export from omnibase_core.models.contracts

Test plan

  • All 86 unit tests pass
  • mypy --strict passes (0 errors)
  • Coverage at 88.16% (>60% threshold)
  • Follows existing ModelSemVer patterns

Acceptance Criteria (OMN-154)

  • ModelContractVersion created with typed semver fields (major, minor, patch)
  • Semver progression rules enforced (no downgrades without explicit flag)
  • Unit tests with >90% coverage target (achieved 88%)
  • mypy --strict passes
  • Integrated into contract snapshot tests (future work)
  • CI check prevents unversioned contracts (future work)
  • CI check prevents downgrading semver without ALLOW_DOWNGRADE=true (future work)

Closes OMN-154

Summary by CodeRabbit

  • New Features
    • Adds a robust contract semantic-version type (major.minor.patch) with parsing, comparisons, bump helpers, progression checks and downgrade protection; exposes it as public API.
    • Exposes a node-type validation mixin as a public API export.
  • Tests
    • Adds comprehensive unit tests for parsing, validation, comparisons, progression rules, immutability, hashing, serialization, and downgrade behavior.
  • Chores
    • Pre-commit hooks adjusted to run earlier; repository structure validation updated to whitelist core repos for protocol locations.

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

…lds [OMN-154]

Add typed semver model for contract versioning with downgrade protection.

- Create ModelContractVersion with major/minor/patch int fields
- Implement full comparison operators (__eq__, __lt__, __le__, __gt__, __ge__)
- Add version bumping methods (bump_major, bump_minor, bump_patch)
- Add downgrade protection via validate_progression(allow_downgrade=False)
- Add factory methods from_string() and from_tuple()
- Ensure immutability with frozen=True, extra="forbid", strict=True
- Add comprehensive TDD tests (86 tests, 88% coverage)
- Export from omnibase_core.models.contracts

Implements CONTRACT_STABILITY_SPEC.md semver requirements.
@coderabbitai

coderabbitai Bot commented Dec 7, 2025 •

Copy link
Copy Markdown
Contributor

Walkthrough

Adds an immutable ModelContractVersion semantic-version model with parsing, comparisons, bump/progression helpers and downgrade validation; exposes it from the contracts package; updates several import paths (mixins and transformation types), tightens protocol-location validation whitelist, adds unit tests, and adjusts pre-commit hook stages.

Changes

Cohort / File(s) Change Summary
Package API
src/omnibase_core/models/contracts/__init__.py
Imported and exported ModelContractVersion; updated MixinNodeTypeValidator import to omnibase_core.mixins.mixin_node_type_validator and reordered exports.
New version model
src/omnibase_core/models/contracts/model_contract_version.py
Added immutable ModelContractVersion (major/minor/patch) with parsing/serialization (from_string, to_string, to_tuple), rich comparisons & hashing, bump helpers, progression checks (is_upgrade_from, is_downgrade_from) and validate_progression that enforces downgrade protection.
Unit tests (version model)
tests/unit/models/contracts/test_model_contract_version.py
Added comprehensive tests covering construction, parsing (including invalid/prerelease/build cases), type/field validation, comparisons, progression/downgrade protection, bump helpers, immutability, hashing, (de)serialization, and repr.
Contracts import updates
src/omnibase_core/models/contracts/model_contract_compute.py, src/omnibase_core/models/contracts/model_contract_effect.py, src/omnibase_core/models/contracts/model_contract_orchestrator.py, src/omnibase_core/models/contracts/model_contract_reducer.py
Updated import source for MixinNodeTypeValidator to omnibase_core.mixins.mixin_node_type_validator (no API changes).
Transformations import updates
src/omnibase_core/models/transformations/__init__.py, src/omnibase_core/models/transformations/model_types.py, src/omnibase_core/models/transformations/types.py, src/omnibase_core/utils/compute_transformations.py, src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py
Switched imports of ModelTransformationConfig from .types → .model_types; adjusted references accordingly (no API signature changes).
Repository validation script
scripts/validation/validate_structure.py
Added PROTOCOL_ALLOWED_REPOS whitelist (omnibase_spi, omnibase_core), enforced protocol-directory location/count rules against the whitelist, and updated violation messages/suggestions.
Pre-commit config
.pre-commit-config.yaml
Changed multiple hook stages from commit → pre-commit, added clean-tmp-directory hook, and made ruff-fix exit non-zero on fixes to force re-staging.
Tests for validation
tests/unit/validation/test_validate_structure.py
Expanded tests to assert protocol-location behavior: non-whitelisted repo triggers violation; omnibase_core and SPI remain allowed.
Mixins package API
src/omnibase_core/mixins/__init__.py
Exported MixinNodeTypeValidator from omnibase_core.mixins.mixin_node_type_validator and added it to __all__.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Focus areas:
    • model_contract_version.py — parsing edge cases, comparison semantics, immutability, exceptions (ModelOnexError INVALIDATION).
    • tests/unit/models/contracts/test_model_contract_version.py — brittle assertions and coverage completeness.
    • Import-path moves (omnibase_core.mixins.*, transformation model_types) — check for potential circular imports.
    • scripts/validation/validate_structure.py — whitelist logic and updated test expectations.

Possibly related PRs

Poem

🐰 I count my majors, minors, patch by patch,
I hop ahead and never scratch a match.
I bump with care, forbid the backward track,
Parsers tidy, tests keep me on my track.
🥕 Forward we go — no downgrades in my patch!

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 title clearly and specifically describes the main change: implementing ModelContractVersion with typed semantic version fields, directly aligned with the PR's primary objective and file changes.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch jonah/omn-154-06-create-modelcontractversion-with-typed-semver-fields

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b2aaf38 and 20b8528.

📒 Files selected for processing (6)
  • src/omnibase_core/mixins/__init__.py (2 hunks)
  • src/omnibase_core/models/contracts/__init__.py (3 hunks)
  • src/omnibase_core/models/contracts/model_contract_compute.py (1 hunks)
  • src/omnibase_core/models/contracts/model_contract_effect.py (1 hunks)
  • src/omnibase_core/models/contracts/model_contract_orchestrator.py (1 hunks)
  • src/omnibase_core/models/contracts/model_contract_reducer.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/omnibase_core/models/contracts/model_contract_orchestrator.py
  • src/omnibase_core/models/contracts/model_contract_reducer.py
  • src/omnibase_core/models/contracts/init.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:

  • src/omnibase_core/models/contracts/model_contract_compute.py
  • src/omnibase_core/mixins/__init__.py
  • src/omnibase_core/models/contracts/model_contract_effect.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/contracts/model_contract_compute.py
  • src/omnibase_core/mixins/__init__.py
  • src/omnibase_core/models/contracts/model_contract_effect.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/model_contract_compute.py
  • src/omnibase_core/models/contracts/model_contract_effect.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/__init__.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 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/models/contracts/model_contract_compute.py
  • src/omnibase_core/mixins/__init__.py
  • src/omnibase_core/models/contracts/model_contract_effect.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 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/models/contracts/model_contract_compute.py
  • src/omnibase_core/models/contracts/model_contract_effect.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/models/contracts/model_contract_compute.py
  • src/omnibase_core/models/contracts/model_contract_effect.py
🧬 Code graph analysis (3)
src/omnibase_core/models/contracts/model_contract_compute.py (1)
src/omnibase_core/mixins/mixin_node_type_validator.py (1)
  • MixinNodeTypeValidator (31-136)
src/omnibase_core/mixins/__init__.py (1)
src/omnibase_core/mixins/mixin_node_type_validator.py (1)
  • MixinNodeTypeValidator (31-136)
src/omnibase_core/models/contracts/model_contract_effect.py (1)
src/omnibase_core/mixins/mixin_node_type_validator.py (1)
  • MixinNodeTypeValidator (31-136)
⏰ 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 (3)
src/omnibase_core/models/contracts/model_contract_effect.py (1)

36-36: LGTM: Import path update aligns with architectural guidelines.

The relocation of MixinNodeTypeValidator from the contracts package to the mixins package improves code organization and aligns with the coding guideline that "Mixin classes should be composed into node classes for specific capabilities."

Based on coding guidelines: Mixin classes should reside in the mixins package for proper architectural separation.

src/omnibase_core/models/contracts/model_contract_compute.py (1)

27-27: LGTM: Consistent import path update.

The import path update for MixinNodeTypeValidator is consistent with the broader refactoring to relocate mixins to their proper architectural location.

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

65-65: LGTM: Proper public API exposure for relocated mixin.

The import and __all__ export correctly expose MixinNodeTypeValidator as part of the public mixins API. This completes the relocation of the mixin from the contracts package to the mixins package, making it available for composition into node classes as per architectural guidelines.

Based on coding guidelines: This change updates the available mixins list to include MixinNodeTypeValidator, which is now properly located in the mixins package.

Also applies to: 98-98


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

@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/models/contracts/__init__.py (1)

10-11: Import organization could be improved.

The new relative import at line 10 is placed between absolute imports. For consistency, consider grouping it with other relative imports starting at line 16.

 from omnibase_core.models.core.model_workflow import ModelWorkflow
 
 """
 Contract Models
 
 Models for validating various contract formats and subcontract compositions.
 """
 
 from omnibase_core.models.discovery.model_event_descriptor import ModelEventDescriptor
-from .model_contract_version import ModelContractVersion
 from omnibase_core.models.security.model_condition_value import ModelConditionValue
 from omnibase_core.models.service.model_external_service_config import (
     ModelExternalServiceConfig,
 )
 
 from . import subcontracts
+from .model_contract_version import ModelContractVersion
 from .mixin_node_type_validator import MixinNodeTypeValidator
tests/unit/models/contracts/test_model_contract_version.py (2)

35-36: Add pytest markers as per coding guidelines.

Per the coding guidelines, tests should use @pytest.mark.unit for unit tests and @pytest.mark.timeout() to prevent hangs. Consider adding the class-level markers.

+import pytest
+
+@pytest.mark.unit
+@pytest.mark.timeout(30)
 class TestModelContractVersionBasicConstruction:
     """Tests for ModelContractVersion basic construction and initialization."""

Apply similar markers to all test classes in this file.


667-689: Tests for prerelease/build metadata could be more explicit.

The try/except pattern here silently passes if the feature isn't supported. Since the implementation does support prerelease/build suffixes (per the regex in from_string), these tests should assert success rather than allowing silent failure.

     def test_from_string_with_prerelease_suffix_may_be_ignored(self) -> None:
         """Test from_string() with prerelease suffix (if supported)."""
-        # Based on ModelSemVer, prerelease suffixes may be parsed but ignored
-        try:
-            version = ModelContractVersion.from_string("1.2.3-alpha")
-            assert version.major == 1
-            assert version.minor == 2
-            assert version.patch == 3
-        except Exception:
-            # If prerelease is not supported, that's also acceptable
-            pass
+        # Prerelease suffixes are parsed but ignored per implementation
+        version = ModelContractVersion.from_string("1.2.3-alpha")
+        assert version.major == 1
+        assert version.minor == 2
+        assert version.patch == 3

     def test_from_string_with_build_metadata_may_be_ignored(self) -> None:
         """Test from_string() with build metadata (if supported)."""
-        try:
-            version = ModelContractVersion.from_string("1.2.3+build")
-            assert version.major == 1
-            assert version.minor == 2
-            assert version.patch == 3
-        except Exception:
-            # If build metadata is not supported, that's also acceptable
-            pass
+        # Build metadata is parsed but ignored per implementation
+        version = ModelContractVersion.from_string("1.2.3+build")
+        assert version.major == 1
+        assert version.minor == 2
+        assert version.patch == 3
src/omnibase_core/models/contracts/model_contract_version.py (2)

14-14: Remove unused import.

Any is imported from typing but never used in this module.

-from typing import Any

258-263: Consider using ModelOnexError for consistency.

Per coding guidelines, structured error handling with ModelOnexError and EnumCoreErrorCode is preferred. The from_string method uses ModelOnexError, but validate_progression raises a plain ValueError. Consider using ModelOnexError with an appropriate error code (e.g., VALIDATION_ERROR or CONTRACT_VIOLATION) for consistency.

         if self.is_downgrade_from(from_version) and not allow_downgrade:
-            raise ValueError(
-                f"Version downgrade detected: {from_version} -> {self}. "
-                f"Downgrades are not allowed without explicit allow_downgrade=True. "
-                f"See CONTRACT_STABILITY_SPEC.md for versioning rules."
+            raise ModelOnexError(
+                error_code=EnumCoreErrorCode.CONTRACT_VIOLATION,
+                message=(
+                    f"Version downgrade detected: {from_version} -> {self}. "
+                    f"Downgrades are not allowed without explicit allow_downgrade=True. "
+                    f"See CONTRACT_STABILITY_SPEC.md for versioning rules."
+                ),
             )

Note: This would require updating the tests to catch ModelOnexError instead of ValueError.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 534d21f and bb3972b.

📒 Files selected for processing (3)
  • src/omnibase_core/models/contracts/__init__.py (2 hunks)
  • src/omnibase_core/models/contracts/model_contract_version.py (1 hunks)
  • tests/unit/models/contracts/test_model_contract_version.py (1 hunks)
🧰 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:

  • src/omnibase_core/models/contracts/__init__.py
  • src/omnibase_core/models/contracts/model_contract_version.py
  • tests/unit/models/contracts/test_model_contract_version.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/contracts/__init__.py
  • src/omnibase_core/models/contracts/model_contract_version.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/__init__.py
  • src/omnibase_core/models/contracts/model_contract_version.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/test_model_contract_version.py
🧠 Learnings (2)
📚 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/models/contracts/__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/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/contracts/model_contract_version.py
🧬 Code graph analysis (3)
src/omnibase_core/models/contracts/__init__.py (1)
src/omnibase_core/models/contracts/model_contract_version.py (1)
  • ModelContractVersion (22-263)
src/omnibase_core/models/contracts/model_contract_version.py (1)
src/omnibase_core/enums/enum_core_error_code.py (1)
  • EnumCoreErrorCode (9-154)
tests/unit/models/contracts/test_model_contract_version.py (1)
src/omnibase_core/models/contracts/model_contract_version.py (9)
  • ModelContractVersion (22-263)
  • from_string (70-104)
  • is_upgrade_from (196-214)
  • is_downgrade_from (216-234)
  • bump_major (157-168)
  • bump_minor (170-181)
  • bump_patch (183-194)
  • validate_progression (236-263)
  • to_string (61-63)
⏰ 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 (8)
src/omnibase_core/models/contracts/__init__.py (1)

60-62: LGTM!

ModelContractVersion is correctly exported in the __all__ list under the "Foundation models" section, making it publicly importable from omnibase_core.models.contracts.

tests/unit/models/contracts/test_model_contract_version.py (1)

1-33: Well-structured test module with comprehensive coverage.

The test file provides excellent coverage for ModelContractVersion with clear test categories matching the acceptance criteria. The docstring clearly documents the test categories and requirements from CONTRACT_STABILITY_SPEC.md.

src/omnibase_core/models/contracts/model_contract_version.py (6)

46-51: LGTM!

The model configuration correctly enforces immutability (frozen=True), strict typing (strict=True), and no extra fields (extra="forbid"), aligning with the coding guidelines for thread-safe Pydantic models. Based on learnings, this ensures models are immutable after creation.


69-104: LGTM!

The from_string method correctly uses ModelOnexError with EnumCoreErrorCode.VALIDATION_ERROR for invalid format handling, following the structured error handling guideline. The regex properly validates semver format including optional prerelease/build suffixes.


123-155: LGTM!

The comparison operators correctly return NotImplemented for type mismatches, following Python's comparison protocol. The tuple-based comparison ensures proper lexicographic ordering (major > minor > patch).


157-194: LGTM!

The bump methods correctly implement semantic versioning semantics: bump_major resets minor/patch, bump_minor resets patch, and all return new instances to preserve immutability.


196-234: LGTM!

The is_upgrade_from and is_downgrade_from helper methods provide clear semantic intent by delegating to the comparison operators.


1-20: Well-implemented semantic versioning model.

The ModelContractVersion class is well-documented with clear docstrings, examples, and references to the specification. The implementation correctly follows Pydantic 2.x patterns with immutability for thread safety.

…OMN-154]

- Use ModelOnexError instead of ValueError in validate_progression()
- Remove unused import (typing.Any)
- Add @pytest.mark.unit markers to all test classes
- Make prerelease/build metadata tests explicit (remove try/except pass)
- Update tests to use ModelOnexError instead of generic Exception

@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: 2

🧹 Nitpick comments (5)
src/omnibase_core/models/contracts/model_contract_version.py (1)

105-122: Harden from_tuple against invalid tuple shapes

from_tuple blindly indexes version_tuple[0..2]. For tuples of incorrect length, this will surface as a generic IndexError rather than a domain-specific validation error.

Consider validating the length (and optionally the element types) and raising a ModelOnexError with an appropriate EnumCoreErrorCode (e.g., VALIDATION_ERROR or a contract-specific code) when the tuple is not exactly three integers. This keeps error handling consistent with from_string and the rest of the model.

tests/unit/models/contracts/test_model_contract_version.py (4)

119-133: Tighten exception expectations to avoid masking regressions

Several tests use broad exception tuples, e.g.:

  • Lines 121–123: with pytest.raises((ValidationError, Exception))
  • Lines 126–127, 131–132: similar patterns
  • Lines 136–137, 141–142, 146–147, 151–152, 156–157
  • Lines 485–487, 491–492, 497–498

Given we standardize on Pydantic 2.x and strict models, these cases should deterministically raise ValidationError or TypeError (for type mismatches or frozen-field assignments). Including bare Exception makes it easier for unrelated bugs to pass silently.

I’d suggest narrowing these to the concrete expected exceptions, e.g.:

  • Negative/invalid field values: pytest.raises(ValidationError)
  • Type mismatches/frozen assignments: pytest.raises((ValidationError, TypeError)) if you need to cover both

This keeps the tests strict while still robust to minor internal changes in Pydantic’s error type mix.

Also applies to: 134-158, 482-499


34-37: Add timeout markers per test module or class to match testing guidelines

Per the project testing guidelines, tests should use @pytest.mark.timeout() to guard against hangs, alongside running with --timeout=60. Currently, the test classes are marked only with @pytest.mark.unit.

Consider adding a reasonable timeout marker at the class or module level, e.g.:

@pytest.mark.unit
@pytest.mark.timeout(5)
class TestModelContractVersionBasicConstruction:
    ...

or a module-level pytestmark = pytest.mark.timeout(5) near the top. This aligns the suite with the recommended timeout safeguards. As per coding guidelines.

Also applies to: 399-402, 462-465, 578-581, 629-643, 676-679


28-32: Prefer importing from the public contracts package API

The tests currently import:

from omnibase_core.models.contracts.model_contract_version import (
    ModelContractVersion,
)

Since the PR exposes ModelContractVersion via the omnibase_core.models.contracts package __init__, consider switching to:

from omnibase_core.models.contracts import ModelContractVersion

This exercises the intended public API surface and will catch any future regressions in the package export configuration.


710-711: Remove direct pytest.main invocation in test module

The if __name__ == "__main__": pytest.main([__file__, "-v"]) block is unnecessary in a pytest-managed suite and diverges from the documented workflow (poetry run pytest tests/ ...). Keeping this can create confusion about the supported way to run tests and is not typically used in pytest test modules.

I recommend removing this block and relying solely on the standard pytest entrypoint.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bb3972b and 7876212.

📒 Files selected for processing (2)
  • src/omnibase_core/models/contracts/model_contract_version.py (1 hunks)
  • tests/unit/models/contracts/test_model_contract_version.py (1 hunks)
🧰 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/test_model_contract_version.py
  • src/omnibase_core/models/contracts/model_contract_version.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/test_model_contract_version.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/contracts/model_contract_version.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/model_contract_version.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:

  • src/omnibase_core/models/contracts/model_contract_version.py
🧬 Code graph analysis (2)
tests/unit/models/contracts/test_model_contract_version.py (1)
src/omnibase_core/models/contracts/model_contract_version.py (9)
  • ModelContractVersion (21-269)
  • from_string (69-103)
  • is_upgrade_from (199-217)
  • is_downgrade_from (219-237)
  • bump_major (158-169)
  • bump_minor (171-182)
  • bump_patch (184-197)
  • validate_progression (239-269)
  • to_string (60-62)
src/omnibase_core/models/contracts/model_contract_version.py (1)
src/omnibase_core/enums/enum_core_error_code.py (1)
  • EnumCoreErrorCode (9-154)
⏰ 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

Comment thread src/omnibase_core/models/contracts/model_contract_version.py
Comment thread src/omnibase_core/models/contracts/model_contract_version.py
@claude

claude Bot commented Dec 7, 2025

Copy link
Copy Markdown

Pull Request Review: ModelContractVersion Implementation

Summary: This PR implements ModelContractVersion with typed semver fields. The implementation is well-structured and production-ready with excellent test coverage (88.16 percent, 86 tests).

STRENGTHS:

  1. Excellent Code Quality - Uses strict type safety, immutability (frozen=True), proper ModelOnexError handling
  2. Comprehensive Test Coverage - 86 tests with proper pytest.mark.unit markers
  3. Good API Design - Factory methods, conversion methods, semantic bump methods, validation helpers
  4. Follows ONEX Conventions - Uses ModelOnexError (not generic exceptions), proper imports, strict mypy compliance

AREAS FOR CONSIDERATION:

  1. Minor docstring fix needed at line 259: Says "Raises ValueError" but should say "Raises ModelOnexError"
  2. Consider documenting distinction between ModelContractVersion and existing ModelSemVer

SECURITY & PERFORMANCE:

  • No security concerns, immutability prevents tampering, robust input validation
  • Efficient tuple-based comparison, O(1) hash computation
  • Minor optimization possible: pre-compile regex pattern at module level

TEST COVERAGE:
Current 88.16 percent (86 tests) - Excellent coverage. To reach 90 percent consider testing to_tuple() explicitly and invalid tuple lengths in from_tuple()

ACCEPTANCE CRITERIA (OMN-154):

  • ModelContractVersion with typed semver fields: YES
  • Semver progression rules enforced: YES
  • Unit tests with 90 percent coverage target: 88.16 percent (excellent quality)
  • mypy strict passes: YES
  • Contract snapshot tests integration: Future work
  • CI checks for versioning: Future work

FINAL VERDICT: LGTM - Approve with Minor Suggestions

This is high-quality, production-ready code. The suggested improvements are non-blocking and can be addressed in follow-up PRs.

Review Confidence: 95 percent

Update deprecated `stages: [commit]` to `stages: [pre-commit]` as
recommended by pre-commit 4.x. This ensures ruff format and check
hooks run automatically on every commit.
@claude

claude Bot commented Dec 7, 2025

Copy link
Copy Markdown

Code Review - PR 116: ModelContractVersion Implementation - Overall Assessment: EXCELLENT - This is a high-quality implementation with comprehensive test coverage (86 tests, 88% coverage) and excellent documentation. - Strengths: Architecture & Design (5/5), Error Handling (5/5), Test Coverage (5/5), Documentation (5/5), Code Quality (5/5). - Issues Found: 2 minor documentation inconsistencies in docstrings (lines 83 and 259) - both say ValueError but should say ModelOnexError. - Security & Performance: Excellent (no concerns). - CLAUDE.md Compliance: Full compliance with all requirements. - Final Verdict: APPROVED (recommend fixing 2 minor docstring inconsistencies before merge). Great work! - Reviewed by: Claude Code, Date: 2025-12-07

@claude

claude Bot commented Dec 7, 2025

Copy link
Copy Markdown

Detailed Code Review Analysis

Architecture & Design Excellence

The implementation demonstrates mastery of Python and Pydantic patterns:

  • Immutability: frozen=True, extra=forbid, strict=True - perfect for versioning
  • Type Safety: int fields with ge=0 validators prevent invalid states
  • Comparison Operators: Full implementation (eq, lt, le, gt, ge) using tuple comparison is Pythonic and correct
  • Hashability: Proper hash enables use in sets/dicts
  • Factory Methods: from_string() and from_tuple() provide flexible initialization

The regex pattern in from_string() correctly enforces no leading zeros per semver 2.0.0 spec and supports optional prerelease/build metadata for forward compatibility.

Error Handling: CLAUDE.md Compliant

All error handling follows ONEX Core patterns:

  • Uses ModelOnexError instead of generic exceptions
  • Proper EnumCoreErrorCode.VALIDATION_ERROR usage
  • Informative error messages with context
  • References to CONTRACT_STABILITY_SPEC.md for guidance

Test Coverage: Comprehensive

86 tests organized into 10 test classes:

  • Basic Construction (11 tests)
  • Validation (8 tests)
  • Comparison (15 tests)
  • Semver Progression (15 tests)
  • Downgrade Protection (8 tests)
  • Edge Cases (11 tests)
  • Hashability (6 tests)
  • Serialization (7 tests)
  • Repr (1 test)
  • Version Progression Rules (3 tests)
  • Semver Compatibility (3 tests)

88.16% coverage exceeds the 60% requirement and approaches the 90% target.

Security Analysis

No security concerns identified:

  • Input validation prevents negative versions
  • Regex pattern prevents malformed input
  • No eval/exec or dynamic code execution
  • Immutability prevents tampering
  • Downgrade protection prevents version rollback attacks (configurable with allow_downgrade flag)

Performance Analysis

Excellent performance characteristics:

  • Tuple comparison delegation avoids redundant logic
  • Immutability enables safe caching/memoization
  • Hash function is simple and fast (hash of tuple)
  • No unnecessary object allocations
  • Comparison operations are O(1)

This model will have negligible overhead in production.

@claude

claude Bot commented Dec 7, 2025

Copy link
Copy Markdown

Specific Recommendations

Critical (Must Fix): None

The code is production-ready as-is.

Minor (Should Fix Before Merge):

1. Fix from_string() docstring (model_contract_version.py:83)

Current:

Raises:
    ValueError: If version string format is invalid

Should be:

Raises:
    ModelOnexError: If version string format is invalid

2. Fix validate_progression() docstring (model_contract_version.py:259)

Current:

>>> v1.validate_progression(from_version=v2)  # Raises ValueError

Should be:

>>> v1.validate_progression(from_version=v2)  # Raises ModelOnexError

Optional (Nice to Have):

  1. Consider adding integration tests showing usage with actual contract models (already marked as future work in PR description - good planning!)

  2. Consider adding a brief code comment explaining why the regex pattern allows prerelease/build metadata even though it's ignored - helps future maintainers understand the design decision

Pre-commit Config Changes

The changes to .pre-commit-config.yaml are cosmetic improvements:

  • stages: [commit] → stages: [pre-commit] is more explicit (both are equivalent)
  • Added YAML document marker (---) at the top for YAML best practices

These are good housekeeping changes with zero risk.

@claude

claude Bot commented Dec 7, 2025

Copy link
Copy Markdown

Review Summary - Overall Grade: A+ (Excellent) - What Makes This Code Excellent: (1) Deep ONEX Understanding - follows all CLAUDE.md patterns perfectly, (2) Software Engineering Fundamentals - DRY principle, single responsibility, immutability, (3) Production Readiness - 86 comprehensive tests, security considered, performance optimized, (4) Maintainability - clear structure, excellent docs, follows existing patterns, (5) Attention to Detail - boundary conditions tested, proper Pydantic usage, semver 2.0.0 compliant. - What Needs Fixing: Just 2 minor docstring inconsistencies (ValueError should be ModelOnexError) - documentation-only issues. - CI Expectations: All checks should pass (86 tests, mypy strict 0 errors, 88% coverage). - Bottom Line: Exemplary code that other developers should use as a reference. Approve and merge after fixing 2 docstring issues. Great work!

…ion issues

PR Review Fixes (ModelContractVersion):
- Use ModelOnexError instead of ValueError in validate_progression()
- Fix docstrings to reference ModelOnexError (not ValueError)
- Harden from_tuple() with length validation
- Remove unused typing.Any import
- Add @pytest.mark.unit markers to all test classes
- Add @pytest.mark.timeout(30) to test module
- Make prerelease/build metadata tests explicit
- Tighten exception expectations (ValidationError not generic Exception)
- Import from public API (from omnibase_core.models.contracts import)
- Remove pytest.main invocation
- Add 6 new tests for from_tuple() validation

ONEX Validation Fixes:
- Rename types.py -> model_types.py (naming convention)
- Rename mixin_node_type_validator.py -> model_mixin_node_type_validator.py
- Update validate_structure.py to allow protocols in omnibase_core
- Remove empty tests/unit/models/workflow directories

[OMN-154]

@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

🧹 Nitpick comments (3)
src/omnibase_core/models/contracts/__init__.py (1)

1-7: Consider moving module docstring before imports.

The module docstring (lines 3-7) appears after the first import (line 1). Per PEP 257, the module docstring should be the first statement in the module. This is a minor style issue.

+"""
+Contract Models
+
+Models for validating various contract formats and subcontract compositions.
+"""
+
 from omnibase_core.models.core.model_workflow import ModelWorkflow
 
-"""
-Contract Models
-
-Models for validating various contract formats and subcontract compositions.
-"""
-
 from omnibase_core.models.discovery.model_event_descriptor import ModelEventDescriptor
tests/unit/models/contracts/test_model_contract_version.py (1)

32-34: Consider adding @pytest.mark.timeout to all test classes for consistency.

Only TestModelContractVersionBasicConstruction has the @pytest.mark.timeout(30) decorator. Per coding guidelines, tests should have timeout markers to prevent hangs. Consider adding timeout markers to the remaining test classes for consistency.

src/omnibase_core/models/contracts/model_contract_version.py (1)

269-277: Consider using CONTRACT_VALIDATION_ERROR for better error specificity.

The current implementation uses EnumCoreErrorCode.VALIDATION_ERROR. Since this specifically validates contract version progression, using EnumCoreErrorCode.CONTRACT_VALIDATION_ERROR would make it easier to distinguish contract-version failures from other validation errors, improving observability and error triage.

         if self.is_downgrade_from(from_version) and not allow_downgrade:
             raise ModelOnexError(
-                error_code=EnumCoreErrorCode.VALIDATION_ERROR,
+                error_code=EnumCoreErrorCode.CONTRACT_VALIDATION_ERROR,
                 message=(
                     f"Version downgrade detected: {from_version} -> {self}. "
                     f"Downgrades are not allowed without explicit allow_downgrade=True. "
                     f"See CONTRACT_STABILITY_SPEC.md for versioning rules."
                 ),
             )
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3550418 and 5ab98c6.

📒 Files selected for processing (11)
  • scripts/validation/validate_structure.py (1 hunks)
  • src/omnibase_core/models/contracts/__init__.py (2 hunks)
  • src/omnibase_core/models/contracts/model_contract_compute.py (1 hunks)
  • src/omnibase_core/models/contracts/model_contract_effect.py (1 hunks)
  • src/omnibase_core/models/contracts/model_contract_orchestrator.py (1 hunks)
  • src/omnibase_core/models/contracts/model_contract_reducer.py (1 hunks)
  • src/omnibase_core/models/contracts/model_contract_version.py (1 hunks)
  • src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py (1 hunks)
  • src/omnibase_core/models/transformations/__init__.py (1 hunks)
  • src/omnibase_core/utils/compute_transformations.py (1 hunks)
  • tests/unit/models/contracts/test_model_contract_version.py (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/omnibase_core/models/contracts/model_contract_orchestrator.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:

  • src/omnibase_core/models/contracts/model_contract_reducer.py
  • src/omnibase_core/models/contracts/model_contract_compute.py
  • src/omnibase_core/models/transformations/__init__.py
  • src/omnibase_core/models/contracts/model_contract_effect.py
  • scripts/validation/validate_structure.py
  • src/omnibase_core/models/contracts/model_contract_version.py
  • src/omnibase_core/models/contracts/__init__.py
  • src/omnibase_core/utils/compute_transformations.py
  • src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py
  • tests/unit/models/contracts/test_model_contract_version.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/contracts/model_contract_reducer.py
  • src/omnibase_core/models/contracts/model_contract_compute.py
  • src/omnibase_core/models/transformations/__init__.py
  • src/omnibase_core/models/contracts/model_contract_effect.py
  • src/omnibase_core/models/contracts/model_contract_version.py
  • src/omnibase_core/models/contracts/__init__.py
  • src/omnibase_core/utils/compute_transformations.py
  • src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.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/model_contract_reducer.py
  • src/omnibase_core/models/contracts/model_contract_compute.py
  • src/omnibase_core/models/transformations/__init__.py
  • src/omnibase_core/models/contracts/model_contract_effect.py
  • src/omnibase_core/models/contracts/model_contract_version.py
  • src/omnibase_core/models/contracts/__init__.py
  • src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.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/test_model_contract_version.py
🧠 Learnings (8)
📚 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:

  • src/omnibase_core/models/contracts/model_contract_reducer.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/models/contracts/model_contract_reducer.py
  • src/omnibase_core/models/contracts/model_contract_compute.py
  • src/omnibase_core/models/contracts/model_contract_effect.py
  • src/omnibase_core/models/contracts/model_contract_version.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/models/contracts/model_contract_reducer.py
  • src/omnibase_core/models/contracts/model_contract_compute.py
  • src/omnibase_core/models/contracts/model_contract_effect.py
  • src/omnibase_core/models/contracts/__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/**/*.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/models/contracts/model_contract_reducer.py
  • src/omnibase_core/models/contracts/model_contract_compute.py
  • src/omnibase_core/models/contracts/model_contract_effect.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 duck typing with protocols. Do not use isinstance checks with protocol types. Rely on the protocol interface directly.

Applied to files:

  • scripts/validation/validate_structure.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:

  • src/omnibase_core/models/contracts/model_contract_version.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/models/contracts/__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/**/*.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:

  • src/omnibase_core/models/contracts/__init__.py
🧬 Code graph analysis (2)
src/omnibase_core/models/contracts/model_contract_version.py (1)
src/omnibase_core/enums/enum_core_error_code.py (1)
  • EnumCoreErrorCode (9-154)
tests/unit/models/contracts/test_model_contract_version.py (1)
src/omnibase_core/models/contracts/model_contract_version.py (10)
  • ModelContractVersion (21-277)
  • from_string (69-103)
  • is_upgrade_from (207-225)
  • is_downgrade_from (227-245)
  • bump_major (166-177)
  • bump_minor (179-190)
  • bump_patch (192-205)
  • validate_progression (247-277)
  • to_string (60-62)
  • from_tuple (106-130)
⏰ 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 (15)
src/omnibase_core/models/contracts/model_contract_effect.py (1)

38-40: LGTM!

The import path update from mixin_node_type_validator to model_mixin_node_type_validator correctly follows the project's model_ prefix naming convention for files in the models directory.

src/omnibase_core/models/contracts/model_contract_compute.py (1)

29-31: LGTM!

Consistent import path update matching the refactoring in other contract modules.

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

74-74: LGTM!

Import path updated to use model_types module, consistent with the broader refactoring to follow the model_ prefix naming convention for type definition files.

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

78-78: LGTM!

Import path updated consistently with other modules in this PR.

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

29-29: LGTM!

The import path change from .types to .model_types for ModelTransformationConfig aligns with the broader refactoring pattern in this PR to relocate imports to dedicated model_* modules. The public API remains unchanged.

src/omnibase_core/models/contracts/model_contract_reducer.py (1)

39-41: LGTM!

The import path change for MixinNodeTypeValidator from .mixin_node_type_validator to .model_mixin_node_type_validator is consistent with the broader refactoring pattern across contract model files in this PR.

src/omnibase_core/models/contracts/__init__.py (2)

10-17: LGTM!

The new ModelContractVersion import and the updated MixinNodeTypeValidator import path are correctly added, making ModelContractVersion publicly importable from omnibase_core.models.contracts.


61-61: LGTM!

ModelContractVersion is appropriately placed under "Foundation models" in __all__, reflecting its role as a core versioning primitive for contracts.

tests/unit/models/contracts/test_model_contract_version.py (3)

28-29: Good use of public API import path.

Importing ModelContractVersion from omnibase_core.models.contracts (the package) rather than the direct module path validates that the __init__.py exports are correctly configured.


509-516: LGTM!

The tests correctly verify that comparisons with non-ModelContractVersion types return False (via NotImplemented), covering strings, integers, and None. This validates the __eq__ implementation's type checking.


719-750: LGTM!

Excellent coverage of semver prerelease (-alpha, -beta.1) and build metadata (+build, +build.456) parsing. These tests validate that from_string() correctly extracts the base X.Y.Z version while ignoring optional suffixes.

src/omnibase_core/models/contracts/model_contract_version.py (4)

41-50: LGTM!

The model configuration follows Pydantic best practices with frozen=True for immutability (per coding guidelines for thread safety), extra="forbid" for strict validation, and strict=True to prevent type coercion. The ge=0 constraint on all fields ensures non-negative version components.


89-103: LGTM!

The regex pattern correctly implements semver parsing rules:

  • Disallows leading zeros (e.g., rejects 01.02.03)
  • Allows optional prerelease (-alpha) and build metadata (+build) suffixes
  • Properly extracts the numeric components while ignoring extensions

132-164: LGTM!

The comparison operators are correctly implemented:

  • Using to_tuple() provides correct lexicographic ordering (major > minor > patch)
  • Returning NotImplemented for type mismatches allows Python to handle comparison fallback correctly
  • __hash__ is consistent with __eq__ (equal objects have equal hashes)

166-205: LGTM!

The bump methods correctly implement semver semantics:

  • bump_major(): increments major, resets minor and patch to 0
  • bump_minor(): increments minor, resets patch to 0
  • bump_patch(): increments only patch

All methods return new instances, preserving immutability of the frozen model.

Comment on lines +364 to +382
# Protocol directories are allowed in:
# - omnibase_spi: Higher-level protocol abstractions
# - omnibase_core: Core-native protocols for self-contained operation (v0.3.6+)
# See CLAUDE.md: "dependency inversion - SPI now depends on Core, not vice versa"
PROTOCOL_ALLOWED_REPOS = {"omnibase_spi", "omnibase_core"}

if self.repo_name not in PROTOCOL_ALLOWED_REPOS and protocols_path.exists():
self.violations.append(
StructureViolation(
level=ViolationLevel.ERROR,
category="Protocol Location",
message="Only omnibase_spi should contain protocols directory",
message="Only omnibase_spi and omnibase_core should contain protocols directory",
path=f"src/{self.repo_name}/protocols/",
suggestion="Remove local protocols, import from omnibase_spi instead",
suggestion="Remove local protocols, import from omnibase_spi or omnibase_core instead",
)
)

# Count protocol files in non-SPI repositories
if self.repo_name != "omnibase_spi":
# Count protocol files in repositories that don't have explicit protocol allowance
if self.repo_name not in PROTOCOL_ALLOWED_REPOS:

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 | 🟡 Minor

Logical inconsistency: omnibase_core special handling at line 406 is now dead code.

Since omnibase_core is now in PROTOCOL_ALLOWED_REPOS (line 368), the protocol counting block (lines 382-417) is entirely skipped for omnibase_core. This makes the special case at line 406 (max_protocols = 7 if self.repo_name == "omnibase_core" else 3) unreachable.

If this is intentional (protocol counting should not apply to allowed repos), consider removing the dead code for clarity. If protocol counting should still apply to omnibase_core, the condition needs adjustment.

-        # Count protocol files in repositories that don't have explicit protocol allowance
-        if self.repo_name not in PROTOCOL_ALLOWED_REPOS:
+        # Count protocol files in repositories that don't have explicit protocol allowance
+        # Note: omnibase_core has a temporary allowance for up to 7 protocols during migration
+        if self.repo_name not in PROTOCOL_ALLOWED_REPOS or self.repo_name == "omnibase_core":

Alternatively, if protocol counting should be completely disabled for allowed repos, remove lines 396-417 (the omnibase_core special case comment and handling).

- Fix import sorting in contract models (I001 violations):
  - model_contract_compute.py
  - model_contract_effect.py
  - model_contract_orchestrator.py
  - model_contract_reducer.py
  - subcontracts/model_compute_pipeline_step.py

- Fix import order in __init__.py files:
  - models/contracts/__init__.py
  - models/transformations/__init__.py

- Update test_protocol_location_validation_non_spi test:
  - Test was outdated - expected omnibase_core to NOT have protocols
  - v0.3.6+ allows both omnibase_spi AND omnibase_core to have protocols
  - Changed test to use 'omnibase_other' as the non-allowed repo
  - Added test_protocol_location_validation_core_repo to verify core is allowed

- Update pre-commit config to use modern stage names (pre-commit 4.x)

@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)
src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py (1)

72-78: Import path update for ModelTransformationConfig looks good

Switching to omnibase_core.models.transformations.model_types keeps the type usage intact and matches the new module layout. Since ModelTransformationConfig is also re-exported from the transformations package, you could optionally import via from omnibase_core.models.transformations import ModelTransformationConfig to decouple this contract from the internal module structure, but the current import is perfectly valid if you prefer explicit module paths.

tests/unit/validation/test_validate_structure.py (2)

180-200: Test logic correctly validates the updated protocol location rules.

The test properly creates a non-whitelisted repository and verifies that a violation is raised. The updated docstring clearly explains the v0.3.6+ behavior change.

Optional: Consider verifying both allowed repositories in the message.

The assertion at line 199 only checks for "omnibase_spi" in the violation message. Since the validation logic references both omnibase_spi and omnibase_core as allowed repositories, you could make the assertion more comprehensive:

-        assert "omnibase_spi" in protocol_violations[0].message
+        assert "omnibase_spi" in protocol_violations[0].message
+        assert "omnibase_core" in protocol_violations[0].message

66-227: Consider adding pytest markers per coding guidelines.

As per coding guidelines, unit tests should include @pytest.mark.unit decorators and @pytest.mark.timeout() for hang prevention. This helps with test categorization and adds timeout protection.

Example for the modified tests:

@pytest.mark.unit
@pytest.mark.timeout(60)
def test_protocol_location_validation_non_spi(self, temp_repo):
    """Test that non-SPI/non-core repositories shouldn't have protocols directory.
    ...
    """
@pytest.mark.unit
@pytest.mark.timeout(60)
def test_protocol_location_validation_core_repo(self, temp_repo):
    """Test that omnibase_core repository is allowed to have protocols (v0.3.6+)."""

This pattern should be applied to all test methods in the file.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5ab98c6 and b2aaf38.

📒 Files selected for processing (9)
  • .pre-commit-config.yaml (4 hunks)
  • src/omnibase_core/models/contracts/__init__.py (4 hunks)
  • src/omnibase_core/models/contracts/model_contract_compute.py (1 hunks)
  • src/omnibase_core/models/contracts/model_contract_effect.py (1 hunks)
  • src/omnibase_core/models/contracts/model_contract_orchestrator.py (1 hunks)
  • src/omnibase_core/models/contracts/model_contract_reducer.py (1 hunks)
  • src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py (1 hunks)
  • src/omnibase_core/models/transformations/__init__.py (1 hunks)
  • tests/unit/validation/test_validate_structure.py (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • .pre-commit-config.yaml
  • src/omnibase_core/models/contracts/init.py
  • src/omnibase_core/models/contracts/model_contract_reducer.py
  • src/omnibase_core/models/contracts/model_contract_effect.py
  • src/omnibase_core/models/contracts/model_contract_compute.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:

  • src/omnibase_core/models/contracts/subcontracts/model_compute_pipeline_step.py
  • tests/unit/validation/test_validate_structure.py
  • src/omnibase_core/models/contracts/model_contract_orchestrator.py
  • src/omnibase_core/models/transformations/__init__.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/contracts/subcontracts/model_compute_pipeline_step.py
  • src/omnibase_core/models/contracts/model_contract_orchestrator.py
  • src/omnibase_core/models/transformations/__init__.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/contracts/model_contract_orchestrator.py
  • src/omnibase_core/models/transformations/__init__.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/validation/test_validate_structure.py
🧠 Learnings (5)
📚 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/models/contracts/model_contract_orchestrator.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 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/models/contracts/model_contract_orchestrator.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/models/contracts/model_contract_orchestrator.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:

  • src/omnibase_core/models/contracts/model_contract_orchestrator.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/models/contracts/model_contract_orchestrator.py
🧬 Code graph analysis (1)
tests/unit/validation/test_validate_structure.py (1)
scripts/validation/validate_structure.py (1)
  • OmniStructureValidator (43-542)
⏰ 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 (3)
src/omnibase_core/models/contracts/model_contract_orchestrator.py (1)

42-44: Import relocation for MixinNodeTypeValidator looks correct

The updated import path matches the new module name while preserving the same mixin symbol, and remains consistent with how _DEFAULT_NODE_TYPE is used in this model. No further changes needed here.

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

22-40: Public re‑export of ModelTransformationConfig is consistent and useful

Importing ModelTransformationConfig from .model_types and adding it to __all__ cleanly exposes the discriminated union via the package API, matching the docstring and allowing callers to depend on a stable omnibase_core.models.transformations import surface. No further changes needed here.

tests/unit/validation/test_validate_structure.py (1)

201-212: LGTM! New test correctly validates omnibase_core protocol allowance.

The test properly verifies that omnibase_core is whitelisted and can contain a protocols directory without triggering violations, matching the v0.3.6+ behavior described in the PR objectives.

@claude

claude Bot commented Dec 8, 2025

Copy link
Copy Markdown

PR Review: ModelContractVersion Implementation

This PR implements ModelContractVersion with typed semver fields. The implementation is well-structured and follows ONEX best practices with 88% test coverage.

Strengths

  • Excellent code quality with immutability enforced
  • Strong typing with Field validation
  • Complete comparison operators
  • Proper error handling using ModelOnexError
  • 86 comprehensive unit tests
  • Follows repository conventions

Recommendations

  1. Add test coverage for leading-zero rejection - No explicit tests verify that "01.2.3" is rejected
  2. Document pre-commit behavioral change - The --exit-non-zero-on-fix flag changes workflow
  3. Clarify file rename rationale - Why is mixin_node_type_validator.py renamed in this PR?
  4. Explain validation script changes - How does PROTOCOL_ALLOWED_REPOS relate to this feature?
  5. Consider reaching 90% coverage goal - Add 3-5 more edge case tests

Security & Performance

  • No vulnerabilities detected
  • Performance is O(1) for all operations
  • Proper input validation via Pydantic

Final Verdict

APPROVE with minor recommendations

This is a high-quality PR demonstrating excellent software engineering. The implementation is robust and well-tested. The recommendations above are nice-to-have improvements, not blockers.

Great work!

Move mixin from models/contracts/ to mixins/ directory per ONEX
architecture principles:
- Mixins belong in src/omnibase_core/mixins/
- Models belong in src/omnibase_core/models/

Changes:
- Move model_mixin_node_type_validator.py → mixin_node_type_validator.py
- Update imports in all contract models
- Export from mixins/__init__.py
- Maintain re-export from contracts/__init__.py for compatibility
@claude

claude Bot commented Dec 8, 2025

Copy link
Copy Markdown

Code Review - PR #116: ModelContractVersion Implementation

I have thoroughly reviewed this pull request implementing ModelContractVersion with typed semver fields.

✅ Strengths

1. Excellent Code Quality

  • Clean implementation following Pydantic best practices
  • Immutability enforced with frozen=True, extra=forbid, strict=True
  • Proper error handling using ModelOnexError (follows CLAUDE.md conventions)
  • Full type annotations with proper return types

2. Comprehensive Testing (750 lines!)

  • 86 unit tests with 88% coverage exceeding 60% threshold
  • Well-organized test classes by functionality
  • Edge cases covered: large numbers, negative values, immutability, hashability

3. Strong Design Patterns

  • Comparison operators properly return NotImplemented for incompatible types
  • Factory methods from_string() and from_tuple()
  • Immutable bump operations follow semver conventions correctly
  • Downgrade protection with explicit allow_downgrade flag

🔍 Issues and Recommendations

1. CRITICAL: Pre-commit Configuration Change ⚠️
The .pre-commit-config.yaml changes appear unrelated to this PR (changed stages, added --exit-non-zero-on-fix). These infrastructure changes should be in a separate PR unless essential for this feature.

2. Documentation: from_string() Prerelease Behavior
The from_string() method accepts prerelease suffixes (1.2.3-alpha) but silently ignores them. Add a note in the docstring warning that prerelease info is discarded.

3. Optional Performance Optimization
Consider pre-compiling the regex pattern at module level.

📊 Test Coverage: 88.16% (exceeds 60% requirement) ✅

🔧 Refactoring Changes

Good: Mixin Relocation - Moving MixinNodeTypeValidator to mixins/ is correct.
Good: Transformation Types Rename - Renaming types.py to model_types.py follows conventions.

✅ Final Verdict

APPROVED with minor recommendations

This is high-quality work with excellent implementation, comprehensive testing, and strong adherence to project conventions.

Suggested next steps:

  1. Address the pre-commit config concern (revert or justify)
  2. Consider the documentation improvements
  3. Merge once CI passes

Great work! The implementation is solid and well-tested.


Reviewed by: Claude Code (Sonnet 4.5)

@jonahgabriel
jonahgabriel merged commit fe15901 into main Dec 8, 2025
26 checks passed
@jonahgabriel
jonahgabriel deleted the jonah/omn-154-06-create-modelcontractversion-with-typed-semver-fields branch December 8, 2025 01:43
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