Skip to content

feat: add new models, contracts, and documentation [OMN-675] - #180

Merged
jonahgabriel merged 4 commits into
mainfrom
feat/new-models-contracts-docs
Dec 13, 2025
Merged

jonahgabriel merged 4 commits into
mainfrom
feat/new-models-contracts-docs

Conversation

@jonahgabriel

@jonahgabriel jonahgabriel commented Dec 13, 2025 •

Copy link
Copy Markdown
Contributor

Summary

  • Add 16 new common model files for better code organization and reusability
  • Split typed_dict_status_summaries.py into 3 separate files for cleaner imports
  • Update 15 YAML contract files with fingerprints and schema changes
  • Add documentation for naming conventions and Pydantic best practices
  • Add scripts/regenerate_fingerprints.py utility

Part 2 of 3 in PR #168 split (see also PR #179 for import normalization).

Changes

New Common Models (16 files)

  • model_config_schema_property.py - Configuration schema property definitions
  • model_custom_health_metrics.py - Custom health metrics
  • model_effect_metadata.py - Effect node metadata
  • model_event_subscription_config.py - Event subscription configuration
  • model_graph_node_data.py - Graph node data structures
  • model_graph_node_inputs.py - Graph node input definitions
  • model_intent_payload.py - Intent payload model
  • model_introspection_custom_metrics.py - Introspection custom metrics
  • model_mixin_config_schema.py - Mixin configuration schema
  • model_node_capabilities_metadata.py - Node capabilities metadata
  • model_operation_data.py - Operation data structures
  • model_reducer_metadata.py - Reducer node metadata
  • model_request_metadata.py - Request metadata model
  • model_shutdown_metrics.py - Shutdown metrics
  • model_tool_metadata_fields.py - Tool metadata fields
  • model_tool_result_data.py - Tool result data structures

TypedDict Refactoring (3 new files, 1 deleted)

  • Split typed_dict_status_summaries.py into:
    • typed_dict_active_summary.py
    • typed_dict_error_summary.py
    • typed_dict_maintenance_summary.py
  • Updated imports in model_node_status_*.py files

Contract Updates (15 files)

  • Updated fingerprints across runtime and example contracts
  • Pre-commit config updates

Documentation (2 files)

  • docs/conventions/NAMING_CONVENTIONS.md
  • docs/conventions/PYDANTIC_BEST_PRACTICES.md

Scripts (2 files)

  • scripts/regenerate_fingerprints.py - Utility for regenerating contract fingerprints
  • scripts/README.md - Updated documentation

Test plan

  • mypy passes (strict mode, 0 errors)
  • pytest passes (1278 tests in models/common and types)
  • All pre-commit hooks pass
  • New models follow existing ONEX patterns
  • Import updates are consistent across codebase

Related PRs

Summary by CodeRabbit

  • New Features

    • CLI to regenerate/update contract fingerprints with recursive, dry-run, JSON and verbose modes.
  • New Types

    • Many new typed Pydantic models and TypedDicts for metadata, metrics, operations, intents, and graph/node data.
  • Contract Changes

    • Multiple runtime/effect/reducer/orchestrator contracts bumped to v1.1.0 with expanded metadata, operations, FSMs, retry policies, and new fingerprints.
  • Documentation

    • Added naming conventions, Pydantic best-practices, and rewritten scripts README.
  • Tests

    • Comprehensive unit tests for the fingerprint regeneration flow.
  • Chores

    • Updated pre-commit exclusions and YAML validation allowlist.

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

Add 16 new common model files for better code organization:
- model_config_schema_property.py
- model_custom_health_metrics.py
- model_effect_metadata.py
- model_event_subscription_config.py
- model_graph_node_data.py
- model_graph_node_inputs.py
- model_intent_payload.py
- model_introspection_custom_metrics.py
- model_mixin_config_schema.py
- model_node_capabilities_metadata.py
- model_operation_data.py
- model_reducer_metadata.py
- model_request_metadata.py
- model_shutdown_metrics.py
- model_tool_metadata_fields.py
- model_tool_result_data.py

Split typed_dict_status_summaries.py into separate files:
- typed_dict_active_summary.py
- typed_dict_error_summary.py
- typed_dict_maintenance_summary.py

Update 15 YAML contract files with fingerprints and schema changes.

Add documentation:
- NAMING_CONVENTIONS.md
- PYDANTIC_BEST_PRACTICES.md

Add scripts/regenerate_fingerprints.py utility.

Part 2 of 3 in PR #168 split.
@coderabbitai

coderabbitai Bot commented Dec 13, 2025 •

Copy link
Copy Markdown
Contributor

Walkthrough

Adds a CLI to regenerate contract YAML fingerprints, many new typed Pydantic models and TypedDict splits, bumps/rewrites numerous runtime/example contract YAMLs to v1.1.0, updates tooling/docs, and adjusts pre-commit and YAML-validation allowlist entries.

Changes

Cohort / File(s) Summary
Pre-commit & Allowlist
\.pre-commit-config.yaml, \.yaml-validation-allowlist.yaml
Expanded pre-commit exclude pattern with file-level and protocols/ exclusions and added scripts/regenerate_fingerprints.py to the YAML validation allowlist with rationale and review dates.
Fingerprint Regen Script
scripts/regenerate_fingerprints.py
New CLI script to discover contract YAMLs, detect contract model, compute canonical fingerprint, and update YAMLs; adds dataclasses, model detection, fingerprint computation, YAML update logic, file-size guard, and CLI flags (--recursive, --dry-run, --verbose, --json).
Scripts Docs
scripts/README.md
Rewritten README focusing on contract fingerprinting, regeneration workflow, CLI usage, exit codes, and validation guidance.
Runtime Contracts
contracts/runtime/...
contracts/runtime/contract_loader_effect.yaml, .../contract_registry_reducer.yaml, .../event_bus_wiring_effect.yaml, .../node_graph_reducer.yaml, .../runtime_orchestrator.yaml
Replaced legacy fingerprint scaffolding with canonical fingerprint fields, bumped to v1.1.0, and expanded FSMs/operations/subscriptions/publications, handlers, retry policies, metadata, and v1.1.0 required-fields sections.
Example Contracts
examples/contracts/**
examples/contracts/compute/user_profile_normalizer.yaml, examples/contracts/effect/*.yaml, examples/contracts/orchestrator_data_pipeline.yaml, examples/contracts/reducer_metrics_aggregator.yaml
Bumped contract/subcontract versions to v1.1.0, standardized fingerprint format, removed legacy top-level handlers/subscriptions/profile_tags in many files, and expanded per-operation configs, pipelines, or FSM definitions as appropriate.
New Documentation
docs/conventions/NAMING_CONVENTIONS.md, docs/conventions/PYDANTIC_BEST_PRACTICES.md
Added naming conventions and Pydantic best-practices guidance (ConfigDict, validators, frozen models, safety patterns).
New Pydantic Models
src/omnibase_core/models/common/*.py (16 files)
Added ~16 typed Pydantic models (e.g., ModelConfigSchemaProperty, ModelMixinConfigSchema, ModelCustomHealthMetrics, ModelEffectMetadata, ModelEventSubscriptionConfig, ModelGraphNodeData, ModelGraphNodeInputs, ModelIntentPayload, ModelIntrospectionCustomMetrics, ModelNodeCapabilitiesMetadata, ModelOperationData, ModelReducerMetadata, ModelRequestMetadata, ModelShutdownMetrics, ModelToolMetadataFields, ModelToolResultData) with validation/config rules and exported __all__.
TypedDict Split & Exports
src/omnibase_core/types/typed_dict_*.py, src/omnibase_core/types/typed_dict_status_summaries.py, src/omnibase_core/types/__init__.py
Removed monolithic typed_dict_status_summaries.py, added typed_dict_active_summary.py, typed_dict_error_summary.py, typed_dict_maintenance_summary.py, and updated types.__init__ to re-export new TypedDicts.
Model Import Fixes & Validators
src/omnibase_core/models/* (several)
Updated import paths in node-status modules to new TypedDict locations; added model_validator hooks enforcing required-properties subset checks in YAML/schema models and broadened ModelConfigSchemaProperty enum/default types.
Tests
tests/unit/scripts/test_regenerate_fingerprints.py
New comprehensive unit tests covering regenerate_fingerprints behavior: model detection, fingerprint computation, YAML updates, dry-run, errors, file discovery, size enforcement, and result serialization.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant User as CLI User
    participant CLI as regenerate_fingerprints CLI
    participant FS as File System
    participant YAML as YAML Parser
    participant Detector as Model Detector
    participant FPR as Fingerprint Generator
    participant Writer as YAML Updater

    User->>CLI: invoke (file/dir + flags)
    CLI->>FS: find_contract_files(path, recursive)
    FS-->>CLI: file list
    loop per file
        CLI->>FS: read file (check MAX_FILE_SIZE_BYTES)
        FS-->>CLI: file contents
        CLI->>YAML: parse -> dict
        YAML-->>CLI: contract_data
        CLI->>Detector: detect_contract_model(contract_data)
        Detector-->>CLI: model_type / fallback
        CLI->>FPR: compute_fingerprint_for_contract(contract_data, model_type)
        FPR-->>CLI: fingerprint
        alt dry-run = false
            CLI->>Writer: update_fingerprint_in_yaml(original_text, fingerprint)
            Writer->>FS: write updated content
            FS-->>Writer: write result
        else dry-run = true
            CLI-->>User: report proposed change
        end
        CLI-->>User: per-file RegenerateResult (JSON/verbose)
    end
    CLI-->>User: final exit code
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Areas requiring extra attention:

  • scripts/regenerate_fingerprints.py: model-detection logic, error mapping, YAML update strategy (preserving formatting/comments), CLI edge cases and exit codes.
  • New Pydantic models and validators: field constraints, frozen/extra settings, model_validator hooks, and compatibility with existing serialization/validation.
  • Large YAML contract edits: ensure fingerprint/version consistency and that contract semantics in v1.1.0 sections align with validators.
  • Typing/exports and import path changes: ensure no broken imports from splitting TypedDicts and update downstream consumers.

Possibly related PRs

Poem

🐇 I sniffed the YAML, small hops and a twitch,

Rewrote fingerprints without making a glitch,
Typed models sprang up where loose dicts once sprawled,
Contracts upgraded and docs got installed,
The rabbit applauds — tidy changes, well stitched!

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 accurately describes the main changes: adding new models, contracts, and documentation with an issue reference.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/new-models-contracts-docs

📜 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 0a16f9b and 17aefde.

📒 Files selected for processing (1)
  • .pre-commit-config.yaml (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • .pre-commit-config.yaml
⏰ 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 @coderabbitai help to get the list of available commands and usage tips.

@claude

claude Bot commented Dec 13, 2025

Copy link
Copy Markdown

Code Review - PR #180: Add new models, contracts, and documentation [OMN-675]

Summary

This PR adds 16 new common models, refactors TypedDict definitions, updates 15 YAML contracts with fingerprints, and adds comprehensive documentation. The changes are well-structured and follow ONEX conventions. Overall this is high-quality work with strong attention to detail.


✅ Strengths

1. Excellent Model Design

The new common models demonstrate strong Pydantic practices:

  • Proper type safety: ModelConfigSchemaProperty includes runtime validation that default values match declared types (lines 60-100)
  • Immutability where appropriate: ModelConfigSchemaProperty uses frozen=True for immutable config schemas
  • Clear separation of concerns: Each model has a single, well-defined purpose

2. Outstanding Script Implementation

scripts/regenerate_fingerprints.py is exceptionally well-crafted:

  • Comprehensive error handling: File size limits (10MB), encoding errors, YAML parse errors
  • Multiple output formats: Human-readable, JSON, verbose modes
  • Smart contract detection: Auto-detects contract type from node_type field before selecting Pydantic model
  • Preserves formatting: Updates fingerprints in-place while maintaining YAML structure
  • Proper exit codes: 0=success, 1=drift detected, 2=error (excellent for CI/CD)
  • DoS protection: File size validation prevents processing malicious files

3. TypedDict Refactoring

The split of typed_dict_status_summaries.py into three separate files improves:

  • Import granularity: Import only what you need
  • Code organization: Each status type gets its own module
  • Maintainability: Easier to locate and update specific status types

4. Comprehensive Documentation

  • NAMING_CONVENTIONS.md: 423 lines of detailed naming rules with examples
  • PYDANTIC_BEST_PRACTICES.md: 361 lines covering ConfigDict, from_attributes safety, frozen models
  • Copy-paste safe examples: Handler examples include all necessary imports

5. Contract Fingerprint Updates

All 15 contract files updated with consistent fingerprint format:

  • Follows documented spec: v{version}:{12-char-hash}
  • Includes helpful comments referencing CONTRACT_STABILITY_SPEC.md
  • Proper version bumps where needed

🔍 Issues Found

1. Security: YAML Parsing Without Validation ⚠️

File: scripts/regenerate_fingerprints.py:326

contract_data = yaml.safe_load(content)  # noqa: ONEX-YAML

Issue: The script uses yaml.safe_load() which is approved via .yaml-validation-allowlist.yaml, but the justification could be stronger.

Why it matters: While the script does validate with Pydantic models AFTER parsing (line 206), there's a window where untrusted YAML data exists as a raw dict.

Recommendation: The current approach is acceptable since:

  1. File size is validated first (10MB limit)
  2. Pydantic validation follows immediately
  3. The allowlist entry documents the necessity

Suggested improvement: Add a comment in the allowlist entry noting that Pydantic validation happens immediately after YAML parsing.

2. Type Safety: Broad Exception Catching ⚠️

File: scripts/regenerate_fingerprints.py:208

except (ValueError, TypeError, ModelOnexError):
    return None

Issue: Silently returning None on validation errors loses error context.

Impact: Users won't know WHY fingerprint computation failed - was it a schema mismatch? Missing field? Type error?

Recommendation: Capture and return the error message:

except (ValueError, TypeError, ModelOnexError) as e:
    # Store error in RegenerateResult instead of returning None
    # This preserves error context for debugging

The calling code at line 364-371 already handles None returns with a generic error message. Consider passing the actual exception message through.

3. Validation: Float vs Integer Handling

File: src/omnibase_core/models/common/model_config_schema_property.py:88-93

if self.type == "integer" and isinstance(self.default, float):
    if not self.default.is_integer():
        raise ValueError(...)

Issue: This allows default=3.0 for type="integer", which is technically correct but could be confusing.

Impact: Minor - users might wonder why 3.0 is accepted for integer types.

Recommendation: Consider adding a warning or normalizing to int:

# Option 1: Normalize
if self.default.is_integer():
    object.__setattr__(self, 'default', int(self.default))
    
# Option 2: Warn but accept
# (current behavior is fine, just document it)

Current behavior is acceptable - just ensure it's documented.

4. Model Design: All-Optional Fields Pattern

Files:

  • model_intent_payload.py
  • model_operation_data.py
  • model_tool_result_data.py

Pattern observed: All fields are str | None or dict[str, str] with no required fields.

Concern: These models accept empty objects, which might not represent valid business states:

# This is valid but semantically meaningless:
payload = ModelIntentPayload()  # All fields None/empty

Recommendation: Consider adding a model_validator to ensure at least ONE field is populated:

@model_validator(mode='after')
def _validate_has_data(self) -> "ModelIntentPayload":
    if all(v is None or v == {} or v == [] for v in self.__dict__.values()):
        raise ValueError("At least one field must be populated")
    return self

Justification: If these models are used as union types where the presence of specific fields determines behavior, the current design is fine. But if they represent concrete intent/operation data, validation would improve safety.


📊 Testing Observations

Positive:

  • ✅ Test coverage mentioned: "pytest passes (1278 tests in models/common and types)"
  • ✅ mypy strict mode: All new models should pass type checking
  • ✅ Pre-commit hooks: Mentioned as passing

Recommendations:

  1. Add negative test cases for ModelConfigSchemaProperty:

    • Test that default=3.5 with type="integer" raises error
    • Test that default="text" with type="number" raises error
    • Test that default=42 with type="string" raises error
  2. Add integration tests for regenerate_fingerprints.py:

    • Test dry-run mode doesn't modify files
    • Test that regenerated fingerprints match compute_contract_fingerprint()
    • Test error handling for malformed YAML
    • Test file size limit enforcement
  3. Test TypedDict refactoring:

    • Ensure all imports of old typed_dict_status_summaries are updated
    • Verify backward compatibility if this is a public API

🎯 Performance Considerations

✅ Good:

  • File size limits: 10MB cap prevents DoS attacks
  • Lazy loading: Script only loads files when processing
  • Efficient YAML updates: Regex-based replacement preserves formatting without full re-serialization

Suggestions:

  1. Parallel processing: For large contract directories, consider using multiprocessing or concurrent.futures:

    from concurrent.futures import ProcessPoolExecutor
    
    with ProcessPoolExecutor() as executor:
        results = list(executor.map(regenerate_fingerprint, files_to_process))
  2. Caching: If running repeatedly in CI, consider caching file hashes to skip unchanged files


🔒 Security Assessment

✅ Secure:

  • File size validation: Prevents resource exhaustion
  • Path traversal protection: Uses Path objects with proper validation
  • YAML safety: Uses yaml.safe_load() (not yaml.load())
  • Pydantic validation: All contract data validated before use
  • No code execution: Script doesn't execute arbitrary code from contracts

⚠️ Minor Concerns:

  1. Directory exclusion list (line 428): Relies on string matching in path parts. Consider using .gitignore-style patterns for robustness.

  2. Error message exposure: Error messages include file paths (line 556). Ensure these don't leak sensitive information in production logs.


📝 Documentation Quality

✅ Excellent:

  • NAMING_CONVENTIONS.md: Comprehensive with real examples
  • PYDANTIC_BEST_PRACTICES.md: Covers from_attributes safety in detail
  • Script docstrings: Clear usage examples with exit codes documented
  • Inline comments: Contract files have helpful fingerprint format comments

Suggestions:

  1. Add migration guide: Document how to migrate existing code that used typed_dict_status_summaries.py

  2. Cross-reference docs: Link between NAMING_CONVENTIONS.md and PYDANTIC_BEST_PRACTICES.md

  3. Add examples: Show complete end-to-end examples of using the new models:

    # Example: Using ModelIntentPayload
    intent = ModelIntentPayload(
        event_type="user.registered",
        event_data={"user_id": "123"},
        log_level="info",
        log_message="User registration complete"
    )

🏗️ Architecture & Patterns

✅ Follows ONEX Conventions:

  • Model naming: All classes use Model prefix
  • File naming: Consistent model_*.py pattern
  • Frozen models: Config schemas appropriately frozen
  • Protocol-driven: Handler examples use protocol interfaces
  • SemVer: Fingerprints use semantic versioning

Suggestions:

  1. Consider Protocol definitions: For models like ModelIntentPayload, consider defining a ProtocolIntentPayload to enable duck typing

  2. Add factory methods: For complex models like ModelConfigSchemaProperty, add factory methods:

    @classmethod
    def string_property(cls, description: str, default: str | None = None, required: bool = False):
        return cls(type="string", description=description, default=default, required=required)

✅ Final Verdict

Recommendation: APPROVE with minor suggestions

This PR demonstrates:

  • ✅ Strong adherence to ONEX conventions
  • ✅ Excellent code quality and documentation
  • ✅ Thoughtful design with proper validation
  • ✅ Comprehensive tooling (regenerate_fingerprints.py)
  • ⚠️ Minor issues that don't block merging

Before Merging:

  1. Address exception handling: Consider preserving error context in compute_fingerprint_for_contract()
  2. Add tests: Negative test cases for model validators
  3. Update allowlist comment: Clarify Pydantic validation in YAML allowlist entry

Post-Merge Follow-ups:

  1. Add integration tests for fingerprint regeneration script
  2. Consider adding model_validator to ensure payload models have data
  3. Add migration guide for TypedDict refactoring
  4. Benchmark fingerprint regeneration performance on large contract sets

📚 References

  • ✅ Follows CLAUDE.md conventions
  • ✅ Consistent with existing codebase patterns
  • ✅ Proper SemVer in fingerprints
  • ✅ Documentation cross-references architecture specs

Great work on this PR! The attention to detail in the fingerprint script and documentation is particularly impressive. The minor issues noted above are suggestions for improvement, not blockers.

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

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
examples/contracts/effect/db_query.yaml (1)

55-78: Update the “v1.0 Contract Schema Version” header to match 1.1.0.
With contract_version.minor: 1 and effect_operations.version at 1.1.0, the current header reads stale/misleading.

🟡 Minor comments (5)
contracts/runtime/event_bus_wiring_effect.yaml-239-247 (1)

239-247: Consider making ProtocolLogger required if observability logging is enabled.

Given observability.log_request/log_response are set to true, treating ProtocolLogger as optional risks silently losing logs or requiring implicit no-op behavior. Either make it required, or gate those observability flags on logger availability.

examples/contracts/effect/resilient_effect.yaml-63-63 (1)

63-63: Version comment inconsistency.

Line 63 states "v1.0 Contract Schema Version" but the contract_version at lines 70-73 is 1.1.0. Update the comment to reflect the actual version.

-# v1.0 Contract Schema Version
+# v1.1.0 Contract Schema Version
src/omnibase_core/models/common/model_config_schema_property.py-39-42 (1)

39-42: default field type doesn't support array/object defaults.

The default field is typed as str | int | float | bool | None, but the model supports type: "array" and type: "object". If someone sets type: "array", they cannot provide a list default value. Either expand the type union to include list and dict, or document that defaults for array/object types are not supported.

-    default: str | int | float | bool | None = Field(
+    default: str | int | float | bool | list | dict | None = Field(
         default=None,
         description="Default value (type should match the 'type' field)",
     )
src/omnibase_core/models/common/model_config_schema_property.py-87-98 (1)

87-98: Boolean values pass validation for integer type due to Python's type hierarchy.

In Python, bool is a subclass of int, so isinstance(True, int) returns True. If someone sets type: "integer" with default: true (boolean), the validation passes incorrectly. Add explicit boolean rejection for integer type.

         # Special handling: integer type should not accept float (unless it's a whole number)
         if self.type == "integer" and isinstance(self.default, float):
             if not self.default.is_integer():
                 raise ValueError(
                     f"Default value {self.default!r} is a float but type is 'integer'. "
                     "Use an integer value instead."
                 )
+        # Special handling: integer type should not accept bool
+        elif self.type == "integer" and isinstance(self.default, bool):
+            raise ValueError(
+                f"Default value {self.default!r} is a boolean but type is 'integer'. "
+                "Use an integer value instead."
+            )
         elif not isinstance(self.default, expected_types):
contracts/runtime/contract_registry_reducer.yaml-4-6 (1)

4-6: Fingerprint format inconsistency - uses v prefix.

This contract's fingerprint uses "v1.1.0:c753f440fda3" with a v prefix, but other contracts in this PR (e.g., user_profile_normalizer.yaml, http_api_call.yaml, kafka_produce.yaml) use the format without the v prefix: "1.1.0:...". This inconsistency could cause validation or comparison issues.

 # Fingerprint: SHA-256 hash of canonical normalized contract content (excluding fingerprint field).
 # See docs/architecture/CONTRACT_STABILITY_SPEC.md for normalization specification.
-fingerprint: "v1.1.0:c753f440fda3"
+fingerprint: "1.1.0:c753f440fda3"

Note: The fingerprint hash value will likely change after regeneration if the format is corrected. Run the regeneration script after fixing.

🧹 Nitpick comments (18)
src/omnibase_core/models/common/model_custom_health_metrics.py (1)

1-64: Solid typed replacement for dict-based metrics; consider tightening status / status_code if semantics are fixed.
If status is expected to be one of a small set (healthy/warning/critical/error) and status_code is normalized, using Literal[...] and adding bounds (e.g., ge=0.0, le=1.0) would prevent drift.

src/omnibase_core/models/common/model_tool_result_data.py (1)

10-41: Looks good; consider whether metrics / data_fields are too narrow.

If tool outputs can include ints/strings/bools (common for metrics and extra fields), dict[str, float] and dict[str, str] may force lossy conversions. If strictness is desired, consider widening types intentionally (and adding extra="forbid" to avoid regressing to “free-form dict”).

src/omnibase_core/models/common/model_mixin_config_schema.py (1)

12-32: Add invariant validation for required_properties and consider strict/extra-forbid config.

At minimum, validate that every entry in required_properties exists in properties keys; otherwise you can ship an internally inconsistent schema that only fails downstream.

Recommended sketch:

-from pydantic import BaseModel, Field
+from pydantic import BaseModel, Field, model_validator
...
 class ModelMixinConfigSchema(BaseModel):
+    @model_validator(mode="after")
+    def _validate_required_properties(self) -> "ModelMixinConfigSchema":
+        missing = [p for p in self.required_properties if p not in self.properties]
+        if missing:
+            raise ValueError(f"required_properties not present in properties: {missing}")
+        return self

Also consider aligning strictness with ModelConfigSchemaProperty (e.g., extra="forbid").

src/omnibase_core/models/common/model_operation_data.py (1)

51-54: Consider more flexible type for headers field.

HTTP headers typically have string values, but some headers may contain structured data or need special encoding. While dict[str, str] is generally acceptable for headers, consider whether this aligns with how headers are handled elsewhere in the codebase.

src/omnibase_core/models/common/model_tool_metadata_fields.py (1)

10-51: Consider consolidating with ModelNodeCapabilitiesMetadata.

ModelToolMetadataFields shares 7 out of 8 fields with ModelNodeCapabilitiesMetadata (author, trust_score, documentation_url, source_repository, license, capabilities, and dependencies vs maintainers). This duplication suggests a shared base model might be appropriate.

Consider extracting common metadata fields into a base model:

class ModelBaseMetadata(BaseModel):
    """Base metadata fields shared across nodes and tools."""
    author: str | None = Field(default=None, description="...")
    trust_score: float | None = Field(default=None, ge=0.0, le=1.0, description="...")
    documentation_url: str | None = Field(default=None, description="...")
    source_repository: str | None = Field(default=None, description="...")
    license: str | None = Field(default=None, description="...")
    capabilities: list[str] = Field(default_factory=list, description="...")

class ModelToolMetadataFields(ModelBaseMetadata):
    """Tool-specific metadata fields."""
    category: str | None = Field(default=None, description="...")
    dependencies: list[str] = Field(default_factory=list, description="...")
src/omnibase_core/models/common/model_graph_node_data.py (1)

41-44: Consider more flexible type for output_mapping field.

The output_mapping field is typed as dict[str, str], which may be too restrictive if node outputs include complex types (objects, arrays, numbers). This aligns with similar concerns in other models where dict[str, str] limits flexibility.

If output values can be complex types, consider:

-    output_mapping: dict[str, str] = Field(
+    output_mapping: dict[str, Any] = Field(
         default_factory=dict,
         description="Output variable mappings",
     )
src/omnibase_core/models/common/model_event_subscription_config.py (1)

30-33: Consider adding validation constraint for priority field.

The priority field has no validation constraints. If priority values should be non-negative or have a specific range, adding a ge constraint would prevent invalid values.

If priorities should be non-negative:

     priority: int = Field(
         default=0,
         description="Subscription priority",
+        ge=0,
     )
examples/contracts/effect/filesystem_operations.yaml (1)

68-70: Fingerprint format inconsistency with version.

The fingerprint uses v1.1.0: prefix but the contract_version at lines 64-67 uses dict format {major: 1, minor: 1, patch: 0}. The README indicates fingerprint format should be <semver>:<hash> (e.g., 0.4.0:8fa1e2b4c9d1), not v1.1.0:.... Consider using 1.1.0:920b41e8af2f without the v prefix for consistency.

-fingerprint: "v1.1.0:920b41e8af2f"
+fingerprint: "1.1.0:920b41e8af2f"
src/omnibase_core/models/common/model_config_schema_property.py (2)

43-46: Consider expanding enum to support non-string values.

JSON Schema allows enums with mixed types (numbers, booleans, null). The current list[str] | None restricts enums to strings only. If this is intentional for simplicity, consider adding a doc comment clarifying the limitation.


25-29: Consider adding from_attributes=True to ConfigDict.

Per the coding guidelines, immutable value objects that are nested in other Pydantic models or used in parallel test execution should include from_attributes=True in ConfigDict. Since ModelConfigSchemaProperty will be nested in ModelMixinConfigSchema, this may be beneficial.

     model_config = ConfigDict(
         frozen=True,
         strict=True,
         extra="forbid",
+        from_attributes=True,
     )
src/omnibase_core/models/common/model_shutdown_metrics.py (1)

18-22: Redundant validate_assignment=True with frozen=True.

When frozen=True is set, the model is immutable and assignment is not allowed, making validate_assignment=True redundant. Consider removing it for clarity, or if you need assignment validation, remove frozen=True instead.

     model_config = ConfigDict(
         extra="forbid",
         frozen=True,
-        validate_assignment=True,
     )
scripts/README.md (1)

257-266: Pre-commit hook file pattern may not match example contracts.

The files: ^contracts/.*\.yaml$ pattern assumes contracts are in a root-level contracts/ directory, but the example contracts in this PR are under examples/contracts/. Consider updating to match actual locations:

- repo: local
  hooks:
    - id: regenerate-fingerprints
      name: Regenerate Contract Fingerprints
      entry: poetry run python scripts/regenerate_fingerprints.py
      language: system
      files: ^(contracts|examples/contracts)/.*\.yaml$
      pass_filenames: true
examples/contracts/compute/user_profile_normalizer.yaml (2)

59-60: Minor documentation inconsistency with version reference.

Line 59 mentions "no per-step timeouts in v1.0" but this contract is v1.1.0. Consider updating the comment to reflect the current version.

-  # Pipeline-level timeout (no per-step timeouts in v1.0)
+  # Pipeline-level timeout (no per-step timeouts in v1.1)

356-359: Version reference in metadata description is outdated.

The description mentions "v1.0 step types" but the contract is v1.1.0.

   description: |
     Contract-driven compute pipeline for user profile normalization.
-    Demonstrates all v1.0 step types and transformation types.
+    Demonstrates all v1.1 step types and transformation types.
examples/contracts/effect/http_api_call.yaml (1)

21-24: Version reference inconsistency in header comment.

Line 23 references "v1.0 NodeEffect" but this contract is v1.1.0.

-# This example demonstrates the v1.0 NodeEffect contract-driven HTTP handler
+# This example demonstrates the v1.1 NodeEffect contract-driven HTTP handler
scripts/regenerate_fingerprints.py (2)

201-209: Silent exception swallowing may hide validation issues.

The compute_fingerprint_for_contract function catches ValueError, TypeError, and ModelOnexError but returns None without logging. This can make debugging difficult when fingerprint computation fails due to validation errors.

Consider adding logging for debugging purposes:

+import logging
+
+logger = logging.getLogger(__name__)
+
 def compute_fingerprint_for_contract(
     contract_data: dict[str, object],
 ) -> ModelContractFingerprint | None:
     ...
     try:
         # Remove existing fingerprint to avoid circular dependency
         data_for_fingerprint = {
             k: v for k, v in contract_data.items() if k != "fingerprint"
         }
         contract = model_class.model_validate(data_for_fingerprint)
         return compute_contract_fingerprint(contract)
-    except (ValueError, TypeError, ModelOnexError):
+    except (ValueError, TypeError, ModelOnexError) as e:
+        logger.debug("Failed to compute fingerprint: %s", e)
         return None

Alternatively, if verbose mode is enabled, this information could be surfaced to the user.


240-256: Version pattern may not match dict-style version fields.

The regex pattern at line 242 matches simple string versions like version: "1.0.0" but won't match the dict-style versions used in most contracts in this PR:

contract_version: {major: 1, minor: 1, patch: 0}

This means when inserting a new fingerprint (not replacing an existing one), the fallback to appending at end-of-file (line 255) will be triggered instead of inserting after the version field.

Consider enhancing the pattern to also match dict-style versions, or add a pattern specifically for contract_version:

     # No existing fingerprint - add after version field
     version_pattern = re.compile(
-        r'^(\s*)(version:\s*["\']?[\w./-]+["\']?\s*)$',
+        r'^(\s*)((?:contract_)?version:\s*(?:["\']?[\w./-]+["\']?|\{[^}]+\})\s*)$',
         re.MULTILINE,
     )

Alternatively, add a separate pattern specifically for contract_version with dict format.

examples/contracts/effect/kafka_produce.yaml (1)

21-24: Version reference inconsistency in header comment.

Line 23 references "v1.0 NodeEffect" but this contract is v1.1.0.

-# This example demonstrates the v1.0 NodeEffect contract-driven Kafka handler
+# This example demonstrates the v1.1 NodeEffect contract-driven Kafka handler
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e6dce21 and 9cf09ff.

📒 Files selected for processing (43)
  • .pre-commit-config.yaml (1 hunks)
  • .yaml-validation-allowlist.yaml (1 hunks)
  • contracts/runtime/contract_loader_effect.yaml (2 hunks)
  • contracts/runtime/contract_registry_reducer.yaml (2 hunks)
  • contracts/runtime/event_bus_wiring_effect.yaml (3 hunks)
  • contracts/runtime/node_graph_reducer.yaml (2 hunks)
  • contracts/runtime/runtime_orchestrator.yaml (2 hunks)
  • docs/conventions/NAMING_CONVENTIONS.md (1 hunks)
  • docs/conventions/PYDANTIC_BEST_PRACTICES.md (1 hunks)
  • examples/contracts/compute/user_profile_normalizer.yaml (3 hunks)
  • examples/contracts/effect/db_query.yaml (2 hunks)
  • examples/contracts/effect/filesystem_operations.yaml (1 hunks)
  • examples/contracts/effect/http_api_call.yaml (2 hunks)
  • examples/contracts/effect/kafka_produce.yaml (1 hunks)
  • examples/contracts/effect/resilient_effect.yaml (2 hunks)
  • examples/contracts/orchestrator_data_pipeline.yaml (1 hunks)
  • examples/contracts/reducer_metrics_aggregator.yaml (1 hunks)
  • scripts/README.md (1 hunks)
  • scripts/regenerate_fingerprints.py (1 hunks)
  • src/omnibase_core/models/common/model_config_schema_property.py (1 hunks)
  • src/omnibase_core/models/common/model_custom_health_metrics.py (1 hunks)
  • src/omnibase_core/models/common/model_effect_metadata.py (1 hunks)
  • src/omnibase_core/models/common/model_event_subscription_config.py (1 hunks)
  • src/omnibase_core/models/common/model_graph_node_data.py (1 hunks)
  • src/omnibase_core/models/common/model_graph_node_inputs.py (1 hunks)
  • src/omnibase_core/models/common/model_intent_payload.py (1 hunks)
  • src/omnibase_core/models/common/model_introspection_custom_metrics.py (1 hunks)
  • src/omnibase_core/models/common/model_mixin_config_schema.py (1 hunks)
  • src/omnibase_core/models/common/model_node_capabilities_metadata.py (1 hunks)
  • src/omnibase_core/models/common/model_operation_data.py (1 hunks)
  • src/omnibase_core/models/common/model_reducer_metadata.py (1 hunks)
  • src/omnibase_core/models/common/model_request_metadata.py (1 hunks)
  • src/omnibase_core/models/common/model_shutdown_metrics.py (1 hunks)
  • src/omnibase_core/models/common/model_tool_metadata_fields.py (1 hunks)
  • src/omnibase_core/models/common/model_tool_result_data.py (1 hunks)
  • src/omnibase_core/models/node_metadata/model_node_status_active.py (1 hunks)
  • src/omnibase_core/models/node_metadata/model_node_status_error.py (1 hunks)
  • src/omnibase_core/models/node_metadata/model_node_status_maintenance.py (1 hunks)
  • src/omnibase_core/types/__init__.py (4 hunks)
  • src/omnibase_core/types/typed_dict_active_summary.py (1 hunks)
  • src/omnibase_core/types/typed_dict_error_summary.py (1 hunks)
  • src/omnibase_core/types/typed_dict_maintenance_summary.py (1 hunks)
  • src/omnibase_core/types/typed_dict_status_summaries.py (0 hunks)
💤 Files with no reviewable changes (1)
  • src/omnibase_core/types/typed_dict_status_summaries.py
🧰 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 all Python commands (pytest, mypy, black, isort, etc.), never use pip or direct python execution
Call super().__init__(container) in all node class constructors - this is MANDATORY and eliminates 80+ lines of boilerplate initialization code
Always raise structured errors using ModelOnexError with appropriate EnumCoreErrorCode, never use generic Exception
Use container.get_service("ProtocolName") for dependency injection - always use protocol names, never concrete class names or isinstance checks
Use @standard_error_handling decorator on methods to eliminate 6+ lines of try/catch boilerplate
Do NOT share node instances across threads - use thread-local instances or separate instances per thread for NodeCompute, NodeEffect, NodeReducer, NodeOrchestrator
Use FileRegistry for loading RuntimeHostContract YAML files - handles fail-fast error reporting with specific error codes (FILE_NOT_FOUND, CONFIGURATION_PARSE_ERROR, CONTRACT_VALIDATION_ERROR, etc.)
Use the correct container type: ModelONEXContainer for dependency injection in node constructors, ModelContainer[T] only for wrapping single values with metadata
Use EnumNodeKind for architectural classification (EFFECT, COMPUTE, REDUCER, ORCHESTRATOR) and EnumNodeType for specific implementation type (TRANSFORMER, AGGREGATOR, GATEWAY, etc.)
Format code using poetry run black and sort imports using poetry run isort before committing
Lint code using poetry run ruff check to detect issues and apply auto-fixes with poetry run ruff check --fix

Files:

  • src/omnibase_core/models/common/model_mixin_config_schema.py
  • src/omnibase_core/models/common/model_request_metadata.py
  • src/omnibase_core/models/common/model_config_schema_property.py
  • src/omnibase_core/models/common/model_reducer_metadata.py
  • src/omnibase_core/models/common/model_node_capabilities_metadata.py
  • src/omnibase_core/models/common/model_graph_node_data.py
  • src/omnibase_core/models/common/model_intent_payload.py
  • src/omnibase_core/models/common/model_operation_data.py
  • src/omnibase_core/models/common/model_shutdown_metrics.py
  • src/omnibase_core/models/common/model_introspection_custom_metrics.py
  • src/omnibase_core/types/typed_dict_maintenance_summary.py
  • src/omnibase_core/models/common/model_graph_node_inputs.py
  • src/omnibase_core/types/typed_dict_active_summary.py
  • src/omnibase_core/models/common/model_custom_health_metrics.py
  • scripts/regenerate_fingerprints.py
  • src/omnibase_core/types/__init__.py
  • src/omnibase_core/models/common/model_tool_result_data.py
  • src/omnibase_core/models/common/model_event_subscription_config.py
  • src/omnibase_core/models/node_metadata/model_node_status_active.py
  • src/omnibase_core/models/node_metadata/model_node_status_maintenance.py
  • src/omnibase_core/models/common/model_tool_metadata_fields.py
  • src/omnibase_core/models/common/model_effect_metadata.py
  • src/omnibase_core/models/node_metadata/model_node_status_error.py
  • src/omnibase_core/types/typed_dict_error_summary.py
src/omnibase_core/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/omnibase_core/**/*.py: Achieve and maintain 100% mypy strict mode compliance with 0 errors across all source files
Achieve and maintain pyright basic mode compliance with 0 errors (targets Python 3.12)
For immutable value objects that are nested in other Pydantic models or used in parallel test execution, add from_attributes=True to ConfigDict
Use protocol-based dependency injection with container.get_service() - no isinstance checks with protocols (rely on duck typing instead)

Files:

  • src/omnibase_core/models/common/model_mixin_config_schema.py
  • src/omnibase_core/models/common/model_request_metadata.py
  • src/omnibase_core/models/common/model_config_schema_property.py
  • src/omnibase_core/models/common/model_reducer_metadata.py
  • src/omnibase_core/models/common/model_node_capabilities_metadata.py
  • src/omnibase_core/models/common/model_graph_node_data.py
  • src/omnibase_core/models/common/model_intent_payload.py
  • src/omnibase_core/models/common/model_operation_data.py
  • src/omnibase_core/models/common/model_shutdown_metrics.py
  • src/omnibase_core/models/common/model_introspection_custom_metrics.py
  • src/omnibase_core/types/typed_dict_maintenance_summary.py
  • src/omnibase_core/models/common/model_graph_node_inputs.py
  • src/omnibase_core/types/typed_dict_active_summary.py
  • src/omnibase_core/models/common/model_custom_health_metrics.py
  • src/omnibase_core/types/__init__.py
  • src/omnibase_core/models/common/model_tool_result_data.py
  • src/omnibase_core/models/common/model_event_subscription_config.py
  • src/omnibase_core/models/node_metadata/model_node_status_active.py
  • src/omnibase_core/models/node_metadata/model_node_status_maintenance.py
  • src/omnibase_core/models/common/model_tool_metadata_fields.py
  • src/omnibase_core/models/common/model_effect_metadata.py
  • src/omnibase_core/models/node_metadata/model_node_status_error.py
  • src/omnibase_core/types/typed_dict_error_summary.py
🧠 Learnings (7)
📚 Learning: 2025-12-13T20:59:19.524Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T20:59:19.524Z
Learning: Applies to src/omnibase_core/mixins/**/*.py : Create reusable behavior mixins with accompanying mixin_metadata.yaml for discovery and capability matching

Applied to files:

  • src/omnibase_core/models/common/model_mixin_config_schema.py
  • src/omnibase_core/models/common/model_node_capabilities_metadata.py
  • src/omnibase_core/models/common/model_tool_metadata_fields.py
📚 Learning: 2025-12-13T20:59:19.523Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T20:59:19.523Z
Learning: Applies to src/omnibase_core/**/*.py : For immutable value objects that are nested in other Pydantic models or used in parallel test execution, add `from_attributes=True` to ConfigDict

Applied to files:

  • src/omnibase_core/models/common/model_mixin_config_schema.py
  • docs/conventions/PYDANTIC_BEST_PRACTICES.md
📚 Learning: 2025-12-13T20:59:19.523Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T20:59:19.523Z
Learning: Applies to **/*.py : Always raise structured errors using ModelOnexError with appropriate EnumCoreErrorCode, never use generic Exception

Applied to files:

  • docs/conventions/PYDANTIC_BEST_PRACTICES.md
📚 Learning: 2025-12-13T20:59:19.523Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T20:59:19.523Z
Learning: Applies to src/omnibase_core/**/*.py : Achieve and maintain pyright basic mode compliance with 0 errors (targets Python 3.12)

Applied to files:

  • .pre-commit-config.yaml
📚 Learning: 2025-12-13T20:59:19.523Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T20:59:19.523Z
Learning: Applies to src/omnibase_core/**/*.py : Achieve and maintain 100% mypy strict mode compliance with 0 errors across all source files

Applied to files:

  • .pre-commit-config.yaml
📚 Learning: 2025-12-13T20:59:19.524Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T20:59:19.524Z
Learning: Applies to **/*.py : Format code using `poetry run black` and sort imports using `poetry run isort` before committing

Applied to files:

  • .pre-commit-config.yaml
📚 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/common/model_introspection_custom_metrics.py
🧬 Code graph analysis (15)
src/omnibase_core/models/common/model_mixin_config_schema.py (1)
src/omnibase_core/models/common/model_config_schema_property.py (1)
  • ModelConfigSchemaProperty (17-100)
src/omnibase_core/models/common/model_request_metadata.py (2)
src/omnibase_core/protocols/event_bus/protocol_event_bus_headers.py (4)
  • source (50-52)
  • trace_id (70-72)
  • span_id (75-77)
  • priority (90-92)
src/omnibase_core/protocols/event_bus/protocol_event_bus.py (1)
  • environment (40-42)
src/omnibase_core/models/common/model_reducer_metadata.py (2)
src/omnibase_core/models/metadata/model_metadata_field_info.py (1)
  • uuid (161-180)
src/omnibase_core/protocols/event_bus/protocol_event_bus_headers.py (3)
  • source (50-52)
  • trace_id (70-72)
  • span_id (75-77)
src/omnibase_core/models/common/model_graph_node_data.py (1)
src/omnibase_core/protocols/event_bus/protocol_event_bus_headers.py (2)
  • priority (90-92)
  • retry_count (105-107)
src/omnibase_core/models/common/model_intent_payload.py (2)
src/omnibase_core/protocols/event_bus/protocol_event_bus_headers.py (1)
  • event_type (55-57)
src/omnibase_core/protocols/event_bus/protocol_event_message.py (1)
  • headers (38-40)
src/omnibase_core/models/common/model_graph_node_inputs.py (1)
src/omnibase_core/models/node_metadata/model_function_node.py (1)
  • parameters (79-81)
scripts/regenerate_fingerprints.py (2)
src/omnibase_core/contracts/hash_registry.py (1)
  • compute_contract_fingerprint (215-280)
src/omnibase_core/models/contracts/model_contract_fingerprint.py (1)
  • ModelContractFingerprint (37-229)
src/omnibase_core/types/__init__.py (3)
src/omnibase_core/types/typed_dict_active_summary.py (1)
  • TypedDictActiveSummary (10-20)
src/omnibase_core/types/typed_dict_error_summary.py (1)
  • TypedDictErrorSummary (10-19)
src/omnibase_core/types/typed_dict_maintenance_summary.py (1)
  • TypedDictMaintenanceSummary (10-18)
src/omnibase_core/models/common/model_event_subscription_config.py (1)
src/omnibase_core/protocols/event_bus/protocol_event_bus_headers.py (2)
  • event_type (55-57)
  • priority (90-92)
src/omnibase_core/models/node_metadata/model_node_status_active.py (1)
src/omnibase_core/types/typed_dict_active_summary.py (1)
  • TypedDictActiveSummary (10-20)
src/omnibase_core/models/node_metadata/model_node_status_maintenance.py (1)
src/omnibase_core/types/typed_dict_maintenance_summary.py (1)
  • TypedDictMaintenanceSummary (10-18)
src/omnibase_core/models/common/model_tool_metadata_fields.py (1)
src/omnibase_core/models/node_metadata/model_node_metadata_info.py (1)
  • capabilities (153-155)
src/omnibase_core/models/common/model_effect_metadata.py (2)
src/omnibase_core/protocols/event_bus/protocol_event_bus_headers.py (5)
  • source (50-52)
  • trace_id (70-72)
  • span_id (75-77)
  • priority (90-92)
  • retry_count (105-107)
src/omnibase_core/protocols/event_bus/protocol_event_bus.py (1)
  • environment (40-42)
src/omnibase_core/models/node_metadata/model_node_status_error.py (1)
src/omnibase_core/types/typed_dict_error_summary.py (1)
  • TypedDictErrorSummary (10-19)
src/omnibase_core/types/typed_dict_error_summary.py (3)
src/omnibase_core/models/errors/model_onex_error.py (1)
  • error_code (255-257)
src/omnibase_core/models/node_metadata/model_node_status_error.py (1)
  • has_recovery_suggestion (31-33)
src/omnibase_core/models/validation/model_validation_error.py (1)
  • is_critical (82-84)
⏰ 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 (44)
src/omnibase_core/types/typed_dict_maintenance_summary.py (1)

1-23: LGTM! Clean TypedDict definition.

The maintenance summary TypedDict is well-structured with appropriate field types. The refactoring improves modularity by isolating this type definition into its own module.

src/omnibase_core/models/node_metadata/model_node_status_maintenance.py (1)

9-11: LGTM! Import path correctly updated.

The import path has been properly updated to reference the new dedicated module for TypedDictMaintenanceSummary. The refactoring maintains consistency with no functional changes.

src/omnibase_core/types/typed_dict_active_summary.py (1)

1-25: LGTM! Well-defined active status summary TypedDict.

The TypedDict definition is clean with appropriate types for all fields. The separation into a dedicated module follows good organizational practices.

src/omnibase_core/models/node_metadata/model_node_status_error.py (1)

9-9: LGTM! Import path correctly updated.

The import has been properly updated to use the new dedicated typed_dict_error_summary module. This aligns with the refactoring's goal of separating TypedDict definitions.

src/omnibase_core/models/node_metadata/model_node_status_active.py (1)

9-9: LGTM! Import path correctly updated.

The import path has been appropriately updated to reference the new dedicated module. The refactoring maintains type safety with no functional changes.

src/omnibase_core/types/__init__.py (4)

94-94: LGTM! Import correctly added.

The import for TypedDictActiveSummary is properly placed and consistent with the module's organization.


146-146: LGTM! Import correctly added.

The import for TypedDictErrorSummary is properly placed and follows the existing module structure.


174-174: LGTM! Import correctly added.

The import for TypedDictMaintenanceSummary is properly placed and maintains consistency with the refactoring.


517-520: LGTM! Public exports correctly updated.

The three new TypedDict exports are properly documented under a clear section comment and correctly added to __all__. This completes the refactoring's public API surface.

src/omnibase_core/types/typed_dict_error_summary.py (1)

1-24: LGTM! Well-structured error summary TypedDict.

The TypedDict definition is clean with appropriate field types, including the properly-typed optional recovery_suggestion field using str | None. The separation into a dedicated module improves code organization.

examples/contracts/reducer_metrics_aggregator.yaml (7)

217-230: Operations section with rollback transitions is well-structured.

The reset_aggregation operation includes rollback_transitions (line 224-228), enabling administrative state resets with undo capability. This aligns with the PR's emphasis on explicit operations and recovery. The structure is clear and follows the pattern mentioned in the PR summary.


14-89: State definitions are comprehensive and well-formatted.

All six states (idle, collecting, validating, aggregating, completed, failed) include:

  • Consistent versioning (1.0.0)
  • Descriptive entry/exit actions
  • Metadata with UI hints (colors, icons)
  • Proper terminal/non-terminal classification
  • State type annotations (operational, terminal)

The structure follows the self-describing FSM pattern outlined in the PR.


91-209: Transitions cover happy path and error scenarios comprehensively.

Eight transitions model the complete workflow:

  • Happy path: start_collection → complete_collection → validation_passed → aggregation_complete (normal flow)
  • Retry logic: validation_failed_retry loops back to collecting with retry guards (max 3 retries)
  • Error handling: handle_error and handle_timeout provide cross-state failure recovery

Each transition includes versioning, conditions (with required/optional flags), and timestamped actions. The structure supports reliable state machine execution.


240-240: Documentation URL may point to non-existent resource.

Line 240 includes documentation_url: https://docs.onex.ai/reducers/metrics-aggregator. Verify this resource exists or is planned for creation; otherwise, consider removing or marking as a placeholder.


4-7: Fingerprint format is correct and consistent with the regeneration script.

The fingerprint "1.1.0:adb6c8f6d107" matches the expected format <semver>:<sha256-first-12-hex-chars> as documented in scripts/regenerate_fingerprints.py (lines 27-30). The hash component is deterministically reproducible—the script computes SHA256 of the canonical contract content with the fingerprint field excluded, ensuring no circular dependency. All contract files in the repository use the same fingerprint format consistently.


180-180: The wildcard '*' from_state pattern is fully supported by the FSM runtime engine.

The FSM executor (fsm_executor.py lines 372, 653) and validation layer (fsm_analysis.py lines 232, 304) both explicitly handle wildcard transitions. The feature is well-documented in code comments and extensively tested (test_fsm_analysis.py includes dedicated test cases for wildcard behavior). The transitions on lines 180 and 198 will work correctly at runtime.


9-10: Version separation is intentional and documented.

The state_machine_version (1.0.0) and contract_version (1.1.0) separation reflects the FSM-driven REDUCER design pattern documented in docs/architecture/CONTRACT_DRIVEN_NODEREDUCER_V1_0.md:

  • contract_version (1.1.0): Tracks the entire contract document including metadata, recovery flags, and fingerprint changes.
  • state_machine_version (1.0.0): Tracks the FSM logic definition itself (states, transitions, actions) independent of contract packaging.
  • state_transitions.version (1.1.0): Tracks the state_transitions substructure version.

This separation allows FSM logic evolution to be tracked independently from contract-level updates. The specification explicitly addresses version mismatch handling in the REDUCER v1.0 documentation, indicating this is a known and intentional pattern specific to FSM-based reducers.

.pre-commit-config.yaml (1)

292-298: Expanded exclude rationale is clear; regex looks correct for protocols/ subtree exclusion.
The added comments make future maintenance safer, and excluding model_node_config_value.py alongside other architectural exceptions is consistent.

examples/contracts/orchestrator_data_pipeline.yaml (1)

22-37: Version + fingerprint normalization update is consistent and readable.
Bumping workflow_version to {major: 1, minor: 1, patch: 0} alongside the normalized fingerprint header is cohesive.

.yaml-validation-allowlist.yaml (1)

43-49: Allowlisting scripts/regenerate_fingerprints.py is justified and time-bounded.
The entry documents the “parse-then-detect-model” necessity clearly and sets an appropriate review date.

contracts/runtime/runtime_orchestrator.yaml (1)

468-482: “v1.1.0 Required Fields” block looks consistent and explicit.
Handlers and tags are clear and should improve contract governance.

src/omnibase_core/models/common/model_introspection_custom_metrics.py (1)

1-54: LGTM; optional follow-up: align Pydantic config strictness with the rest of models/common.
If the codebase expects extra="forbid" / other ConfigDict defaults for common models, consider adding it here too for consistency.

contracts/runtime/contract_loader_effect.yaml (1)

57-90: File not found in repository: The file contracts/runtime/contract_loader_effect.yaml does not exist in the current repository, and no related handler implementations or path validation code could be located. Unable to verify the specific interaction between deny_absolute_paths: true and environment variable resolution without access to the actual configuration file and its handler implementation. Please confirm the correct file path or provide the handler code that processes this configuration.

contracts/runtime/event_bus_wiring_effect.yaml (1)

35-45: Fingerprint + effect version bump look consistent.

src/omnibase_core/models/common/model_request_metadata.py (1)

48-48: Export is clean and consistent.

src/omnibase_core/models/common/model_effect_metadata.py (1)

46-50: Good: retry_count is constrained non-negative.

src/omnibase_core/models/common/model_intent_payload.py (1)

18-83: ModelIntentPayload appears to be incomplete/unused—reconsider its design or remove it.

This model is not used anywhere in the codebase; ModelIntent (in src/omnibase_core/models/reducer/model_intent.py) remains the canonical intent structure with payload: dict[str, Any]. The docstring claims ModelIntentPayload "replaces" the flexible payload, but this replacement never happened.

Additionally, the narrow field types (event_data: dict[str, str], storage_value: str | None, request_body: str | None) prevent structured nested data. If this model is intended to replace the flexible dict[str, Any] pattern, consider either:

  • Completing the migration and actually replacing ModelIntent.payload with this typed model, or
  • Using JsonValue (already defined in json_types.py) for fields that need structured data, or
  • Removing this orphaned model if it's not part of the current design
src/omnibase_core/models/common/model_node_capabilities_metadata.py (1)

30-35: LGTM - Trust score validation is correct.

The trust_score field correctly uses ge=0.0 and le=1.0 constraints to enforce the valid range.

src/omnibase_core/models/common/model_reducer_metadata.py (1)

20-51: LGTM - Field types are appropriate for reducer metadata.

The model correctly uses optional strings for tracing identifiers and UUIDs for partition/window IDs, aligning with distributed processing patterns.

src/omnibase_core/models/common/model_tool_metadata_fields.py (1)

22-27: LGTM - Trust score validation is correct.

The trust_score field correctly enforces the 0.0 to 1.0 range with ge and le constraints.

src/omnibase_core/models/common/model_graph_node_data.py (2)

50-53: LGTM - Excellent use of ConfigDict.

This model correctly implements extra="forbid" and validate_assignment=True as recommended in the coding guidelines and PYDANTIC_BEST_PRACTICES.md. The inline comment clearly explains the rationale.


22-36: LGTM - Validation constraints are appropriate.

The numeric fields (priority, timeout_ms, retry_count) correctly use ge=0 to enforce non-negative values.

src/omnibase_core/models/common/model_event_subscription_config.py (2)

18-21: LGTM - Correct use of required field.

The event_type field correctly uses Field(...) to mark it as required, which is appropriate for event subscription configuration.


34-43: LGTM - Validation constraints are appropriate.

The batch_size and timeout_ms fields correctly use ge=1 and ge=0 respectively to enforce valid values.

docs/conventions/PYDANTIC_BEST_PRACTICES.md (1)

1-361: LGTM - Comprehensive and well-structured documentation.

This documentation provides excellent guidance on Pydantic usage in the ONEX codebase. It clearly explains:

  • When to use frozen models and from_attributes
  • Thread safety considerations
  • Validation patterns with ModelOnexError integration
  • Configuration options with practical examples

The safety decision tree and quick reference tables are particularly useful for developers.

examples/contracts/effect/filesystem_operations.yaml (1)

137-139: Path traversal risk in templates - ensure runtime validation.

The file_path_template uses user-controlled inputs like ${input.tenant_id} and ${input.user_id}. If these aren't sanitized, attackers could inject ../ sequences. The data protection note at lines 49-55 covers general security, but consider adding explicit guidance about path traversal prevention in the handler implementation.

This is an example contract, so the actual validation would be in the runtime handler. Verify that the filesystem handler implementation validates/sanitizes path components.

src/omnibase_core/models/common/model_shutdown_metrics.py (1)

10-16: LGTM - clean model definition.

The model structure is well-defined with appropriate field constraints (ge=0 for counts, ge=0.0 for durations). Field descriptions are clear and the model serves a specific purpose replacing dict[str, Any] with typed fields.

examples/contracts/effect/resilient_effect.yaml (2)

74-76: LGTM - fingerprint format follows specification.

The fingerprint format "1.1.0:c8bf04e22bd2" correctly follows the <semver>:<hash> format documented in the README. This is consistent with the specification.


149-159: Ensure sensitive headers are not logged by the runtime handler.

The Authorization header contains ${input.payment_api_token} and X-Idempotency-Key contains sensitive identifiers. While the security notes at lines 50-62 are comprehensive, ensure the effect handler implementation masks or excludes these headers from logs and traces.

scripts/README.md (1)

21-22: LGTM - clear fingerprint format documentation.

The fingerprint format explanation and hash length justification provide excellent context. The collision probability analysis (0.00002% with 10,000 contracts) is a helpful technical detail for understanding the design decision.

contracts/runtime/contract_registry_reducer.yaml (1)

196-255: Excellent recovery documentation.

The recovery_strategies section provides comprehensive operator guidance with detection methods, recommended actions with specific commands, and escalation paths. This level of documentation significantly improves operational readiness.

scripts/regenerate_fingerprints.py (2)

159-178: Contract detection logic handles case variations correctly.

The detect_contract_model function properly handles case-insensitive node types by calling node_type.upper() at line 173. This correctly handles contracts like kafka_produce.yaml which use lowercase node_type: effect.


448-584: Well-structured CLI implementation.

The CLI follows best practices with:

  • Clear exit codes (0=success, 1=changes, 2=error) useful for CI/CD
  • JSON output mode for automation
  • Dry-run for safe preview
  • Verbose mode for debugging
  • Uses Poetry as per coding guidelines
examples/contracts/effect/kafka_produce.yaml (1)

132-217: Good demonstration of durability vs throughput tradeoffs.

The Kafka operations demonstrate appropriate configuration patterns:

  • Registration events: acks=all with snappy compression for durability
  • Activity events: acks=1 with lz4 for high throughput analytics
  • Audit logs: acks=all with no compression prioritizing integrity

This is a well-designed example contract.

Comment thread contracts/runtime/contract_loader_effect.yaml
Comment thread contracts/runtime/event_bus_wiring_effect.yaml
Comment thread contracts/runtime/node_graph_reducer.yaml
Comment on lines +297 to +305
# v1.1.0 Required Fields
handlers:
required: []
optional:
- type: ProtocolLogger
version: {major: 1, minor: 0, patch: 0}
- type: ProtocolEventBus
version: {major: 1, minor: 0, patch: 0}

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

Make required handlers consistent with the transition action types.

handlers.required: [] (Line 299) looks inconsistent with the contract declaring action types like event, logging, and alert throughout the FSM. If those actions are actually executed by the runtime, ProtocolEventBus / ProtocolLogger shouldn’t be optional (or the runtime needs a clearly-defined no-op fallback).

Suggested edit:

 handlers:
-  required: []
-  optional:
-    - type: ProtocolLogger
-      version: {major: 1, minor: 0, patch: 0}
-    - type: ProtocolEventBus
-      version: {major: 1, minor: 0, patch: 0}
+  required:
+    - type: ProtocolEventBus
+      version: {major: 1, minor: 0, patch: 0}
+    - type: ProtocolLogger
+      version: {major: 1, minor: 0, patch: 0}
+  optional: []
📝 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
# v1.1.0 Required Fields
handlers:
required: []
optional:
- type: ProtocolLogger
version: {major: 1, minor: 0, patch: 0}
- type: ProtocolEventBus
version: {major: 1, minor: 0, patch: 0}
# v1.1.0 Required Fields
handlers:
required:
- type: ProtocolEventBus
version: {major: 1, minor: 0, patch: 0}
- type: ProtocolLogger
version: {major: 1, minor: 0, patch: 0}
optional: []
🤖 Prompt for AI Agents
In contracts/runtime/node_graph_reducer.yaml around lines 297 to 305,
handlers.required is currently empty while the FSM uses action types like event,
logging, and alert; update the contract so ProtocolEventBus and ProtocolLogger
are listed under handlers.required with their appropriate version entries (or,
alternatively, document and implement a deterministic no-op fallback), ensuring
the runtime either declares these handlers as mandatory or provides a
clearly-defined fallback path for those actions.

Comment thread contracts/runtime/runtime_orchestrator.yaml
Comment on lines +37 to +40
parameters: dict[str, str] = Field(
default_factory=dict,
description="Query parameters",
)

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

Consider more flexible type for parameters field.

The parameters field is typed as dict[str, str], which only allows string values. Database query parameters often include integers, floats, booleans, dates, and None values. This restriction may force unnecessary string conversions and lose type information.

Consider this alternative:

-    parameters: dict[str, str] = Field(
+    parameters: dict[str, Any] = Field(
         default_factory=dict,
         description="Query parameters",
     )
📝 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
parameters: dict[str, str] = Field(
default_factory=dict,
description="Query parameters",
)
parameters: dict[str, Any] = Field(
default_factory=dict,
description="Query parameters",
)
🤖 Prompt for AI Agents
In src/omnibase_core/models/common/model_operation_data.py around lines 37 to
40, the parameters field is currently typed as dict[str, str] which restricts
values to strings; change the annotation to allow arbitrary value types (e.g.,
dict[str, Any] or Mapping[str, Any]) and import Any (or Mapping) from typing,
keeping the same Field(default_factory=dict, description=...) so query
parameters can be ints, floats, bools, dates, None, etc., without forced string
conversion.

Comment on lines +81 to +84
envelope_payload: dict[str, str] = Field(
default_factory=dict,
description="Event envelope payload data",
)

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

Reconsider type restriction for envelope_payload field.

The envelope_payload field is typed as dict[str, str], which is overly restrictive for event payloads that commonly contain nested objects, arrays, numbers, and booleans. This limitation would require serializing complex data structures to strings, defeating the purpose of structured event data.

Apply this change:

-    envelope_payload: dict[str, str] = Field(
+    envelope_payload: dict[str, Any] = Field(
         default_factory=dict,
         description="Event envelope payload data",
     )
📝 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
envelope_payload: dict[str, str] = Field(
default_factory=dict,
description="Event envelope payload data",
)
envelope_payload: dict[str, Any] = Field(
default_factory=dict,
description="Event envelope payload data",
)
🤖 Prompt for AI Agents
In src/omnibase_core/models/common/model_operation_data.py around lines 81 to
84, the envelope_payload is currently typed as dict[str, str], which is too
restrictive for structured event data; change the annotation to dict[str, Any]
(or Mapping[str, Any]) and add the corresponding Any import from typing so the
field can hold nested objects, arrays, numbers, and booleans without forcing
serialization.

Comment on lines +12 to +51
class ModelReducerMetadata(BaseModel):
"""
Typed metadata for reducer input.

Replaces dict[str, Any] metadata field in ModelReducerInput
with explicit typed fields for reducer metadata.
"""

source: str | None = Field(
default=None,
description="Source identifier",
)
trace_id: str | None = Field(
default=None,
description="Distributed tracing identifier",
)
span_id: str | None = Field(
default=None,
description="Span identifier for tracing",
)
correlation_id: str | None = Field(
default=None,
description="Correlation ID for request tracking",
)
group_key: str | None = Field(
default=None,
description="Key for grouping operations",
)
partition_id: UUID | None = Field(
default=None,
description="Partition identifier for distributed processing",
)
window_id: UUID | None = Field(
default=None,
description="Window identifier for streaming operations",
)
tags: list[str] = Field(
default_factory=list,
description="Tags for categorization",
)

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.

🛠️ Refactor suggestion | 🟠 Major

Add ConfigDict for consistency.

The model lacks explicit configuration. As per coding guidelines, metadata models should specify extra="forbid" and validate_assignment=True.

+from pydantic import BaseModel, ConfigDict, Field

 class ModelReducerMetadata(BaseModel):
     """
     Typed metadata for reducer input.

     Replaces dict[str, Any] metadata field in ModelReducerInput
     with explicit typed fields for reducer metadata.
     """
+
+    model_config = ConfigDict(
+        extra="forbid",
+        validate_assignment=True,
+    )

     source: str | None = Field(
🤖 Prompt for AI Agents
In src/omnibase_core/models/common/model_reducer_metadata.py around lines 12 to
51, the Pydantic model lacks explicit configuration; add a model_config:
ConfigDict = ConfigDict(extra="forbid", validate_assignment=True) to the model
(and import ConfigDict from pydantic if not already imported) so the model
forbids unknown fields and enforces assignment validation.

Comment thread src/omnibase_core/models/common/model_request_metadata.py Outdated
Comment on lines +10 to +51
class ModelToolMetadataFields(BaseModel):
"""
Typed metadata for discovered tools.

Replaces dict[str, Any] metadata field in ModelDiscoveredTool
with explicit typed fields for common tool metadata.
"""

author: str | None = Field(
default=None,
description="Author or maintainer of the tool",
)
trust_score: float | None = Field(
default=None,
description="Trust score for the tool (0.0 to 1.0)",
ge=0.0,
le=1.0,
)
documentation_url: str | None = Field(
default=None,
description="URL to tool documentation",
)
source_repository: str | None = Field(
default=None,
description="Source code repository URL",
)
license: str | None = Field(
default=None,
description="Software license identifier",
)
category: str | None = Field(
default=None,
description="Tool category for classification",
)
capabilities: list[str] = Field(
default_factory=list,
description="List of tool capabilities",
)
dependencies: list[str] = Field(
default_factory=list,
description="List of tool dependencies",
)

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.

🛠️ Refactor suggestion | 🟠 Major

Add ConfigDict for strict validation.

The model lacks explicit configuration. As per coding guidelines, add extra="forbid" and validate_assignment=True.

+from pydantic import BaseModel, ConfigDict, Field

 class ModelToolMetadataFields(BaseModel):
     """
     Typed metadata for discovered tools.

     Replaces dict[str, Any] metadata field in ModelDiscoveredTool
     with explicit typed fields for common tool metadata.
     """
+
+    model_config = ConfigDict(
+        extra="forbid",
+        validate_assignment=True,
+    )

     author: str | None = Field(

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/omnibase_core/models/common/model_tool_metadata_fields.py around lines 10
to 51, the Pydantic model has no explicit config; add a ConfigDict to enforce
strict validation by importing ConfigDict from pydantic and adding model_config
= ConfigDict(extra="forbid", validate_assignment=True) inside the
ModelToolMetadataFields class body so unknown fields are forbidden and
assignments are validated.

Contract Changes:
- Fix fingerprint prefix format: v1.1.0: → 1.1.0: (canonical semver)
- Add version divergence comment in node_graph_reducer.yaml

Model Changes:
- Add ConfigDict(extra="forbid") to all common models
- Add from_attributes=True to metadata models for ORM compatibility
- Fix priority field typing: str → LiteralEventPriority in effect/request metadata
- Add docstrings explaining all-optional fields pattern for metadata models
- Add note about dict[str, str] per ONEX strict typing standards

Documentation Changes:
- Update NAMING_CONVENTIONS.md fingerprint format (remove 'v' prefix)
- Document both hierarchical and simple profile_tags formats

Note: Kept dict[str, str] types per project strict typing standards
(dict[str, Any] is prohibited by pre-commit hooks). Complex values
should be serialized to JSON strings.

[OMN-675]
@claude

claude Bot commented Dec 13, 2025

Copy link
Copy Markdown

🔍 Comprehensive Code Review - PR #180

Executive Summary

This PR adds 16 new common model files, refactors TypedDict files, updates YAML contracts, adds documentation, and introduces a fingerprint regeneration script. I've identified 5 critical issues and 6 high-priority issues that need to be addressed before merging.


🚨 CRITICAL ISSUES (Must Fix Before Merge)

1. Model Duplication - Individual Files vs. Consolidated File ⚠️

Problem: The PR creates 16 individual model files BUT these exact same models are ALSO defined in model_typed_metadata.py (lines 1-725). This creates complete duplication of model definitions.

Evidence:

  • Individual file: model_config_schema_property.py defines ModelConfigSchemaProperty
  • Consolidated file: model_typed_metadata.py ALSO defines ModelConfigSchemaProperty
  • This pattern repeats for ALL 16 models

Impact:

  • Import ambiguity (which version should be imported?)
  • Maintenance nightmare (changes must be made in two places)
  • Type inconsistency risk (models could drift)
  • Violates DRY principle

Recommendation:

  • ✅ Keep individual files (better organization)
  • ❌ DELETE model_typed_metadata.py entirely
  • Update __init__.py to import from individual files

2. Inconsistent Model Configuration Between Versions ⚠️

Problem: Individual model files have more comprehensive configuration than the consolidated model_typed_metadata.py versions.

Example - ModelConfigSchemaProperty:

  • Individual file: model_config = ConfigDict(frozen=True, strict=True, extra="forbid") ✅
  • Consolidated file: NO model_config at all ❌

Example - ModelRequestMetadata:

  • Individual file: model_config = ConfigDict(extra="forbid", from_attributes=True) ✅
  • Consolidated file: NO model_config at all ❌

Impact: If consolidated file is used, models lack important validation and safety features.


3. Missing Type Validation in Consolidated Version ⚠️

Location: model_config_schema_property.py

Problem: Individual file has comprehensive @model_validator (lines 60-100) that validates default field type matches type field. Consolidated file has NO validator.

Example:

# Would be caught by individual file, NOT by consolidated file
ModelConfigSchemaProperty(type="integer", default=3.5)  # Invalid\!

This validator prevents critical bugs.


4. Inconsistent Type Definitions - UUID vs str ⚠️

Location: model_reducer_metadata.py

Problem: ModelReducerMetadata has different field types between versions:

  • Individual file: partition_id: UUID | None ✅ Strongly typed
  • Consolidated file: partition_id: str | None ❌ Weak typing

Impact: Type safety degradation, validation inconsistency, mypy wouldn't catch issues with consolidated file.


5. Missing Test Coverage for All 16 New Models ⚠️

Problem: ZERO test files found for the new models. Searched for:

  • test_model_config_schema*.py - Not found
  • test_model_operation*.py - Not found
  • test_model_intent*.py - Not found
  • (13 more...) - All not found

Impact:

  • No validation that models work correctly
  • No validation that @model_validator in ModelConfigSchemaProperty actually works
  • No coverage for edge cases
  • CI passing only because models aren't tested

Required: Per CLAUDE.md, minimum 60% coverage required. These foundational models should have 80%+ coverage.

Recommendation:

# Example: tests/unit/models/common/test_model_config_schema_property.py
def test_config_schema_property_integer_type_with_float_default_fails():
    with pytest.raises(ValueError, match="is a float but type is 'integer'"):
        ModelConfigSchemaProperty(type="integer", default=3.5)

def test_config_schema_property_frozen_immutable():
    prop = ModelConfigSchemaProperty(type="string")
    with pytest.raises(ValidationError):
        prop.type = "integer"  # Should fail - frozen=True

⚠️ HIGH-PRIORITY ISSUES (Should Fix)

6. Inconsistent from_attributes=True Usage

Models with from_attributes=True:

  • ModelEffectMetadata, ModelRequestMetadata, ModelReducerMetadata, etc.

Models without it:

  • ModelCustomHealthMetrics, ModelShutdownMetadata, ModelOperationData

Concern: Per docs/conventions/PYDANTIC_BEST_PRACTICES.md, from_attributes=True with mutable source objects creates race condition risks. The PR doesn't document:

  • Why these models need from_attributes=True
  • What are the source objects?
  • Are source objects immutable?

Recommendation: Document in docstrings WHY it's needed, verify source immutability, or add thread-safety warnings.


7. ModelShutdownMetrics Configuration Redundancy

Location: model_shutdown_metrics.py (lines 20-21)

Problem:

model_config = ConfigDict(
    frozen=True,              # Immutable - no assignments allowed
    validate_assignment=True, # Validates assignments that can't happen
)

Impact: validate_assignment=True is redundant when frozen=True. This is a code smell.

Recommendation: Remove validate_assignment=True from frozen models.


8. Regenerate Fingerprints Script - Missing Error Context

Location: scripts/regenerate_fingerprints.py (line 208)

Problem:

except (ValueError, TypeError, ModelOnexError):
    return None  # ❌ Error information lost

Impact: When fingerprint computation fails, no indication of WHAT went wrong.

Recommendation:

except (ValueError, TypeError, ModelOnexError) as e:
    return RegenerateResult(
        error=f"Fingerprint computation failed: {e}"
    )

9. Script DoS Protection - File Size Check After Read

Location: scripts/regenerate_fingerprints.py (lines 290-312)

Problem: File size check happens AFTER metadata access, not before parsing. A 100GB file would still be loaded into memory at line 312.

Recommendation: Move size check BEFORE read_text() or use streaming reads.


10. TypedDict Refactoring - Export Inconsistency

Location: src/omnibase_core/types/__init__.py

Problem: PR splits typed_dict_status_summaries.py into 3 files but doesn't provide backward compatibility.

Recommendation: Add deprecation alias:

# Backward compatibility (deprecated)
TypedDictStatusSummaries = TypedDictActiveSummary  # DEPRECATED

11. YAML Fingerprint Regex Weakness

Location: scripts/regenerate_fingerprints.py (lines 226-229)

Problem:

fingerprint_pattern = re.compile(
    r'^(\s*)fingerprint:\s*["\']?[\w.:/-]+["\']?\s*$',
    re.MULTILINE,
)

Issues:

  • Allows invalid characters
  • Optional quotes could match unintended lines
  • Could match comments like # Comment about fingerprint: invalid

Recommendation: Make regex more specific:

r'^(\s*)fingerprint:\s*"[\d]+\.[\d]+\.[\d]+:[0-9a-f]{12}"\s*$'

📋 MEDIUM-PRIORITY ISSUES

12. Documentation Claims Unsupported by Code

Claim: "Add 16 new common model files for better code organization and reusability"

Reality:

  • Models are duplicated in both individual files AND model_typed_metadata.py
  • No actual "reusability" demonstrated yet
  • "Better code organization" undermined by duplication

13. Missing Usage Documentation

Problem: New docs (PYDANTIC_BEST_PRACTICES.md, NAMING_CONVENTIONS.md) don't provide:

  • When to use ModelRequestMetadata vs ModelEffectMetadata vs ModelReducerMetadata
  • How these models interact with existing dict[str, Any] fields
  • Migration path from dict to typed models
  • Performance implications

✅ POSITIVE ASPECTS

  1. ✅ Strong type safety with proper Field() constraints
  2. ✅ Comprehensive docstrings for each model
  3. ✅ Frozen models where appropriate
  4. ✅ Excellent validator implementation in ModelConfigSchemaProperty
  5. ✅ Script has good safety features (file size limits, encoding errors)
  6. ✅ Good CLI design (dry-run, verbose, JSON output)
  7. ✅ TypedDict refactoring improves import clarity

🎯 ACTION ITEMS

Blocking (Must Fix Before Merge):

  • Delete model_typed_metadata.py to eliminate duplication
  • Update models/common/__init__.py to import from individual files
  • Add test coverage for all 16 models (minimum 60%, recommend 80%+)
  • Fix UUID type inconsistency in ModelReducerMetadata
  • Document from_attributes=True usage and thread-safety
  • Remove validate_assignment=True from frozen models
  • Fix error handling in fingerprint script (line 208)

Recommended (Non-blocking):

  • Move file size check before read_text()
  • Add backward compatibility aliases for TypedDict
  • Improve fingerprint regex specificity
  • Make excluded directories configurable
  • Expand docs with usage examples

📊 Summary

Files analyzed: 36
Critical issues: 5 (blocking)
High-priority issues: 6
Medium-priority issues: 4

Security: ✅ No vulnerabilities detected
Performance: ✅ No obvious issues
Thread Safety: ✅ Models are safe for concurrent use

Overall Assessment: Good foundation but needs fixes for model duplication, test coverage, and type consistency before merge.


Review generated by Claude Code using repository's CLAUDE.md conventions
Last updated: 2025-12-13

MAJOR fixes:
- Fix fingerprint prefix in contract_registry_reducer.yaml (v1.1.0: -> 1.1.0:)
- Add handler documentation to event_bus_wiring_effect.yaml and node_graph_reducer.yaml
- Improve fingerprint script error handling with FingerprintResult class
- Update PYDANTIC_BEST_PRACTICES.md for consistency with implementations

MINOR/NITPICK improvements:
- Add required_properties invariant validation to 3 schema models
- Add priority field constraints (ge=0, le=100) to subscription/graph models
- Expand enum field support to non-string values (int, float, bool, None)
- Add comprehensive fingerprint script tests (54 tests)

Test coverage:
- Type validation tests (default/type mismatches)
- Dry-run mode verification
- Fingerprint consistency tests
- Malformed YAML handling
- File size limit enforcement

Note: Pre-commit hooks flag pre-existing issues in model_typed_metadata.py
(16 classes in one file, str IDs) - these are not introduced by this PR.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
contracts/runtime/runtime_orchestrator.yaml (1)

257-258: Add headroom: workflow timeout equals worst-case sequential step time (0ms slack).

total_workflow_timeout_ms: 120000 (Line 334) exactly matches 4 * step_timeout_ms (Line 337), which is brittle once you include orchestration overhead, retries bookkeeping, and event bus latency. Suggest adding slack (e.g., bump workflow timeout to 150000ms) or reducing step timeouts so you keep a buffer.

Also applies to: 333-342

contracts/runtime/contract_loader_effect.yaml (1)

57-90: The security.path_validation fields in the YAML are unsupported by the schema and will cause validation failure.

ModelFilesystemIOConfig does not include a security field. The schema enforces extra="forbid", which means Pydantic will reject these fields during parsing with a validation error at runtime. Either remove the security block from the YAML or update ModelFilesystemIOConfig to include proper security field definitions and path validation enforcement.

Lines 57-90, 132-168: Same issue applies to both filesystem operations.

♻️ Duplicate comments (2)
src/omnibase_core/models/common/model_event_subscription_config.py (1)

18-18: Complete the model configuration with validate_assignment=True and from_attributes=True.

The past review comment suggested adding validate_assignment=True, which remains unaddressed. Additionally, per coding guidelines learnings, nested models should include from_attributes=True for compatibility with parallel test execution and ORM-style attribute access.

Apply this diff to complete the configuration:

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

Based on learnings: "For immutable value objects that are nested in other Pydantic models or used in parallel test execution, add from_attributes=True to ConfigDict."

contracts/runtime/event_bus_wiring_effect.yaml (1)

35-37: Subscription handler fields still need executable dispatch proof (not just comments/docs).

You’ve added strong guidance + a doc pointer (Line 211-223), but please verify the runtime actually loads and invokes subscriptions.topics[].handler and that the named handlers exist (or are registered) with the expected signatures.

#!/bin/bash
set -euo pipefail

# 1) Ensure the referenced doc exists (and isn't a dead link)
ls -la docs/architecture/SUBSCRIPTION_HANDLERS.md

# 2) Find where YAML `subscriptions:` are modeled/parsed and whether `.handler` is used at runtime
rg -n --type py -C3 'subscriptions' src/omnibase_core | head -200
rg -n --type py -C3 '\bhandler\b' src/omnibase_core | head -200

# 3) Look specifically for code that dispatches/invokes subscription handlers by name
rg -n --type py -C3 'subscription.*handler|handler.*subscription|invoke_.*handler|dispatch_.*handler|resolve_.*handler' src/omnibase_core

# 4) Confirm the three handler entrypoints exist somewhere (method or function)
rg -n --type py -C2 'def (wire_all_subscriptions|wire_single_subscription|remove_subscription)\b' src/omnibase_core
rg -n --type py -C2 'wire_all_subscriptions|wire_single_subscription|remove_subscription' src/omnibase_core | head -200

Also applies to: 211-235

🧹 Nitpick comments (4)
src/omnibase_core/models/common/model_node_capabilities_metadata.py (2)

10-22: Consider adding validate_assignment=True to ConfigDict.

The ConfigDict correctly includes extra="forbid" and from_attributes=True. However, the previous review referenced PYDANTIC_BEST_PRACTICES.md recommending validate_assignment=True for metadata models to ensure strict validation when attributes are modified after initialization. These options are not mutually exclusive and can coexist.

Apply this diff to add validate_assignment:

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

42-48: Consider using Pydantic URL types for stricter validation.

The documentation_url and source_repository fields are currently plain strings. Using Pydantic's HttpUrl or AnyUrl types would provide automatic URL format validation, improving data quality for these metadata fields.

Example:

+from pydantic import BaseModel, ConfigDict, Field, HttpUrl
+
 class ModelNodeCapabilitiesMetadata(BaseModel):
     ...
-    documentation_url: str | None = Field(
+    documentation_url: HttpUrl | None = Field(
         default=None,
         description="URL to node documentation",
     )
-    source_repository: str | None = Field(
+    source_repository: HttpUrl | None = Field(
         default=None,
         description="Source code repository URL",
     )
src/omnibase_core/models/common/model_typed_metadata.py (1)

214-253: Avoid long-term drift between “typed metadata” schema models vs new common schema modules.

If src/omnibase_core/models/common/model_config_schema_property.py / model_mixin_config_schema.py are now the canonical implementations, consider re-exporting them here (or deleting the duplicates) to prevent subtle future divergence.

tests/unit/scripts/test_regenerate_fingerprints.py (1)

36-47: sys.path mutation works, but consider isolating it to avoid cross-test leakage.

If this suite ever runs alongside other script-import tests, a monkeypatch.syspath_prepend(...) fixture (scoped) is safer than a module-level sys.path.insert(...).

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9cf09ff and 0a16f9b.

📒 Files selected for processing (22)
  • contracts/runtime/contract_loader_effect.yaml (2 hunks)
  • contracts/runtime/contract_registry_reducer.yaml (2 hunks)
  • contracts/runtime/event_bus_wiring_effect.yaml (3 hunks)
  • contracts/runtime/node_graph_reducer.yaml (2 hunks)
  • contracts/runtime/runtime_orchestrator.yaml (2 hunks)
  • docs/conventions/NAMING_CONVENTIONS.md (1 hunks)
  • docs/conventions/PYDANTIC_BEST_PRACTICES.md (1 hunks)
  • scripts/regenerate_fingerprints.py (1 hunks)
  • src/omnibase_core/models/common/model_config_schema_property.py (1 hunks)
  • src/omnibase_core/models/common/model_effect_metadata.py (1 hunks)
  • src/omnibase_core/models/common/model_event_subscription_config.py (1 hunks)
  • src/omnibase_core/models/common/model_graph_node_data.py (1 hunks)
  • src/omnibase_core/models/common/model_graph_node_inputs.py (1 hunks)
  • src/omnibase_core/models/common/model_mixin_config_schema.py (1 hunks)
  • src/omnibase_core/models/common/model_node_capabilities_metadata.py (1 hunks)
  • src/omnibase_core/models/common/model_operation_data.py (1 hunks)
  • src/omnibase_core/models/common/model_reducer_metadata.py (1 hunks)
  • src/omnibase_core/models/common/model_request_metadata.py (1 hunks)
  • src/omnibase_core/models/common/model_tool_metadata_fields.py (1 hunks)
  • src/omnibase_core/models/common/model_typed_metadata.py (3 hunks)
  • src/omnibase_core/models/core/model_yaml_schema_object.py (2 hunks)
  • tests/unit/scripts/test_regenerate_fingerprints.py (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • docs/conventions/PYDANTIC_BEST_PRACTICES.md
  • docs/conventions/NAMING_CONVENTIONS.md
🚧 Files skipped from review as they are similar to previous changes (8)
  • src/omnibase_core/models/common/model_operation_data.py
  • src/omnibase_core/models/common/model_config_schema_property.py
  • src/omnibase_core/models/common/model_effect_metadata.py
  • src/omnibase_core/models/common/model_tool_metadata_fields.py
  • src/omnibase_core/models/common/model_reducer_metadata.py
  • src/omnibase_core/models/common/model_request_metadata.py
  • src/omnibase_core/models/common/model_graph_node_data.py
  • src/omnibase_core/models/common/model_mixin_config_schema.py
🧰 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 all Python commands (pytest, mypy, black, isort, etc.), never use pip or direct python execution
Call super().__init__(container) in all node class constructors - this is MANDATORY and eliminates 80+ lines of boilerplate initialization code
Always raise structured errors using ModelOnexError with appropriate EnumCoreErrorCode, never use generic Exception
Use container.get_service("ProtocolName") for dependency injection - always use protocol names, never concrete class names or isinstance checks
Use @standard_error_handling decorator on methods to eliminate 6+ lines of try/catch boilerplate
Do NOT share node instances across threads - use thread-local instances or separate instances per thread for NodeCompute, NodeEffect, NodeReducer, NodeOrchestrator
Use FileRegistry for loading RuntimeHostContract YAML files - handles fail-fast error reporting with specific error codes (FILE_NOT_FOUND, CONFIGURATION_PARSE_ERROR, CONTRACT_VALIDATION_ERROR, etc.)
Use the correct container type: ModelONEXContainer for dependency injection in node constructors, ModelContainer[T] only for wrapping single values with metadata
Use EnumNodeKind for architectural classification (EFFECT, COMPUTE, REDUCER, ORCHESTRATOR) and EnumNodeType for specific implementation type (TRANSFORMER, AGGREGATOR, GATEWAY, etc.)
Format code using poetry run black and sort imports using poetry run isort before committing
Lint code using poetry run ruff check to detect issues and apply auto-fixes with poetry run ruff check --fix

Files:

  • src/omnibase_core/models/common/model_typed_metadata.py
  • tests/unit/scripts/test_regenerate_fingerprints.py
  • src/omnibase_core/models/common/model_graph_node_inputs.py
  • src/omnibase_core/models/core/model_yaml_schema_object.py
  • scripts/regenerate_fingerprints.py
  • src/omnibase_core/models/common/model_node_capabilities_metadata.py
  • src/omnibase_core/models/common/model_event_subscription_config.py
src/omnibase_core/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

src/omnibase_core/**/*.py: Achieve and maintain 100% mypy strict mode compliance with 0 errors across all source files
Achieve and maintain pyright basic mode compliance with 0 errors (targets Python 3.12)
For immutable value objects that are nested in other Pydantic models or used in parallel test execution, add from_attributes=True to ConfigDict
Use protocol-based dependency injection with container.get_service() - no isinstance checks with protocols (rely on duck typing instead)

Files:

  • src/omnibase_core/models/common/model_typed_metadata.py
  • src/omnibase_core/models/common/model_graph_node_inputs.py
  • src/omnibase_core/models/core/model_yaml_schema_object.py
  • src/omnibase_core/models/common/model_node_capabilities_metadata.py
  • src/omnibase_core/models/common/model_event_subscription_config.py
tests/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

tests/**/*.py: Maintain minimum 60% code coverage requirement for all tests
Use pytest markers (@pytest.mark.unit, @pytest.mark.integration, @pytest.mark.slow, @pytest.mark.smoke, @pytest.mark.performance) to categorize tests
Run tests with CI performance expectations: average 2m58s per split across 20 parallel runners, with acceptable range 2m30s-3m30s and critical threshold >4m30s

Files:

  • tests/unit/scripts/test_regenerate_fingerprints.py
🧠 Learnings (3)
📚 Learning: 2025-12-13T20:59:19.537Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T20:59:19.537Z
Learning: Applies to src/omnibase_core/**/*.py : For immutable value objects that are nested in other Pydantic models or used in parallel test execution, add `from_attributes=True` to ConfigDict

Applied to files:

  • src/omnibase_core/models/common/model_graph_node_inputs.py
  • src/omnibase_core/models/core/model_yaml_schema_object.py
  • src/omnibase_core/models/common/model_node_capabilities_metadata.py
  • src/omnibase_core/models/common/model_event_subscription_config.py
📚 Learning: 2025-12-13T20:59:19.537Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T20:59:19.537Z
Learning: Applies to src/omnibase_core/mixins/**/*.py : Create reusable behavior mixins with accompanying mixin_metadata.yaml for discovery and capability matching

Applied to files:

  • src/omnibase_core/models/common/model_node_capabilities_metadata.py
📚 Learning: 2025-12-13T20:59:19.537Z
Learnt from: CR
Repo: OmniNode-ai/omnibase_core PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-13T20:59:19.537Z
Learning: Applies to **/*.py : Use the correct container type: ModelONEXContainer for dependency injection in node constructors, ModelContainer[T] only for wrapping single values with metadata

Applied to files:

  • src/omnibase_core/models/common/model_node_capabilities_metadata.py
🧬 Code graph analysis (4)
src/omnibase_core/models/common/model_graph_node_inputs.py (1)
src/omnibase_core/models/node_metadata/model_function_node.py (1)
  • parameters (79-81)
src/omnibase_core/models/core/model_yaml_schema_object.py (2)
src/omnibase_core/models/common/model_mixin_config_schema.py (1)
  • _validate_required_properties_subset (36-52)
src/omnibase_core/models/common/model_typed_metadata.py (1)
  • _validate_required_properties_subset (236-252)
scripts/regenerate_fingerprints.py (5)
src/omnibase_core/contracts/hash_registry.py (1)
  • compute_contract_fingerprint (215-280)
src/omnibase_core/enums/enum_core_error_code.py (1)
  • EnumCoreErrorCode (9-168)
src/omnibase_core/models/contracts/model_yaml_contract.py (1)
  • ModelYamlContract (27-191)
src/omnibase_core/models/errors/model_onex_error.py (1)
  • ModelOnexError (51-356)
src/omnibase_core/models/contracts/model_contract_fingerprint.py (1)
  • ModelContractFingerprint (37-229)
src/omnibase_core/models/common/model_event_subscription_config.py (2)
src/omnibase_core/models/common/model_typed_metadata.py (1)
  • ModelEventSubscriptionConfig (690-723)
src/omnibase_core/protocols/event_bus/protocol_event_bus_headers.py (2)
  • event_type (55-57)
  • priority (90-92)
🔇 Additional comments (12)
src/omnibase_core/models/common/model_node_capabilities_metadata.py (2)

54-57: Good use of default_factory for list field.

The maintainers field correctly uses default_factory=list to avoid the common Python pitfall of mutable default arguments. This ensures each instance gets its own list rather than sharing a single list across instances.


36-41: Proper validation constraints for trust_score.

The trust_score field correctly uses ge=0.0 and le=1.0 constraints to ensure values remain within the valid range. This provides automatic validation and clear error messages when invalid scores are provided.

src/omnibase_core/models/common/model_graph_node_inputs.py (1)

17-38: The docstring accurately references "ONEX strict typing standards" for dict[str, str] typing. This pattern is consistently applied throughout the codebase across 500+ model definitions and is explicitly documented in multiple model files (including ModelOperationData with the identical note). The dict[str, str] restriction for inputs/outputs is an intentional architectural choice, not an error or undocumented pattern. While this design requires manual JSON serialization for complex types, it is the established standard for this framework.

Likely an incorrect or invalid review comment.

src/omnibase_core/models/common/model_event_subscription_config.py (3)

1-7: LGTM!

Module docstring and imports are well-structured and follow Pydantic v2 conventions.


50-50: LGTM!

Export list correctly defines the public API surface.


20-47: Verify if duplication with model_typed_metadata.py is intentional; determine if both versions should coexist or if one should be removed.

The field definitions and validation constraints in lines 20-47 are correct and follow the coding guidelines. However, the original review flags a duplication concern: an identical or similar ModelEventSubscriptionConfig model existing in model_typed_metadata.py (lines 689-722). This version includes improved validation (priority has ge=0, le=100 constraints), suggesting a deliberate migration or refactoring.

To complete this review, clarify:

  • Is the duplicate in model_typed_metadata.py intentionally being phased out?
  • Should both versions coexist or should one be removed/deprecated?
  • If this is Part 2 of a multi-part migration, ensure the deprecation path is clear in subsequent PRs.
src/omnibase_core/models/core/model_yaml_schema_object.py (1)

9-50: Good defensive validation; consider standardizing the error type if callers rely on ONEX error codes.

The subset check is correct and mirrors your mixin schema validator; this should prevent “required-but-undefined” contract drift early. If any CLI/loader code expects ModelOnexError/EnumCoreErrorCode instead of a Pydantic ValidationError, confirm this ValueError path is acceptable for consumers. (Pydantic v2 validator API.)

scripts/regenerate_fingerprints.py (1)

150-236: Exit codes + dry-run semantics look solid for CI drift detection.

Returning 1 when any fingerprint would change (even in --dry-run) is a nice, automation-friendly contract.

Also applies to: 474-610

contracts/runtime/contract_registry_reducer.yaml (1)

3-12: The versioning is intentionally separated: contract_version and state_transitions.version track different aspects.

contract_version (1.1.0) reflects the overall contract version and matches the fingerprint prefix. state_transitions.version and state_machine_version (both 1.0.0) track the FSM schema version separately. This is not an inconsistency—the pattern is consistent across all FSM blocks in the file (including lines 286-316). No changes needed.

contracts/runtime/runtime_orchestrator.yaml (1)

53-55: Fingerprint + v1.1.0 Required Fields blocks look consistent with the rest of the upgrade.

Also applies to: 468-482

contracts/runtime/contract_loader_effect.yaml (1)

21-23: Overall contract structure + fingerprint/versioning changes read clean and consistent.

Also applies to: 30-49, 206-223

contracts/runtime/node_graph_reducer.yaml (1)

4-6: The added in-file rationale (FSM version separation; optional handlers) is clear and resolves prior ambiguity.

Also applies to: 8-12, 318-331

Comment on lines +8 to +12
# NOTE: FSM version (1.0.0) intentionally differs from contract_version (1.1.0).
# The contract version tracks overall contract changes (handlers, metadata, profile_tags),
# while the FSM version only increments when states, transitions, or conditions change.
# This separation allows metadata updates without implying FSM structural changes.
version: {major: 1, minor: 0, patch: 0}

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 | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# First, explore the repository structure
git ls-files | head -30

Repository: OmniNode-ai/omnibase_core

Length of output: 908


🏁 Script executed:

# Look for FSM-related files and the YAML file in question
find . -type f -name "*.yaml" -o -name "*.yml" | grep -E '(node_graph|FSM|runtime)' | head -20

Repository: OmniNode-ai/omnibase_core

Length of output: 306


🏁 Script executed:

# Check if src/omnibase_core exists and explore its structure
find . -type d -name "omnibase_core" -o -name "src" | head -10

Repository: OmniNode-ai/omnibase_core

Length of output: 94


🏁 Script executed:

# Explore src/omnibase_core structure
find src/omnibase_core -type f -name "*.py" | head -30

Repository: OmniNode-ai/omnibase_core

Length of output: 1440


🏁 Script executed:

# Read the node_graph_reducer.yaml file
cat contracts/runtime/node_graph_reducer.yaml

Repository: OmniNode-ai/omnibase_core

Length of output: 13804


🏁 Script executed:

# Search for FSM/state machine runtime implementation
find src/omnibase_core -type f -name "*.py" | xargs grep -l "state_machine\|state_transitions\|FSM" | head -20

Repository: OmniNode-ai/omnibase_core

Length of output: 1309


🏁 Script executed:

# Search for expression evaluator implementation
find src/omnibase_core -type f -name "*.py" | xargs grep -l "expression\|evaluate.*condition\|parse.*expression" | head -20

Repository: OmniNode-ai/omnibase_core

Length of output: 1323


🏁 Script executed:

# Search for action executor
find src/omnibase_core -type f -name "*.py" | xargs grep -l "action_type\|action_executor\|execute.*action" | head -20

Repository: OmniNode-ai/omnibase_core

Length of output: 1260


🏁 Script executed:

# Read FSM execution mixin
cat -n src/omnibase_core/mixins/mixin_fsm_execution.py

Repository: OmniNode-ai/omnibase_core

Length of output: 9171


🏁 Script executed:

# Read FSM transition condition model
cat -n src/omnibase_core/models/fsm/model_fsm_transition_condition.py

Repository: OmniNode-ai/omnibase_core

Length of output: 10487


🏁 Script executed:

# Read FSM transition action model
cat -n src/omnibase_core/models/contracts/subcontracts/model_fsmtransitionaction.py

Repository: OmniNode-ai/omnibase_core

Length of output: 4025


🏁 Script executed:

# Search for expression evaluator
find src/omnibase_core -type f -name "*.py" | xargs grep -l "evaluate.*expression\|parse.*expression\|is_not_empty\|equals" | head -20

Repository: OmniNode-ai/omnibase_core

Length of output: 360


🏁 Script executed:

# Search for FSM executor to find the actual expression evaluation
find src/omnibase_core -type f -name "*fsm*executor*"

Repository: OmniNode-ai/omnibase_core

Length of output: 108


🏁 Script executed:

# Search for action_type enum or constants
find src/omnibase_core -type f -name "*.py" | xargs grep -l "action_type.*enum\|ActionType\|VALID_ACTION_TYPES\|action_type.*event\|action_type.*logging" | head -20

Repository: OmniNode-ai/omnibase_core

Length of output: 1179


🏁 Script executed:

# Search for wildcard transition handling
find src/omnibase_core -type f -name "*.py" | xargs grep -n "from_state.*\*\|wildcard.*transition" | head -20

Repository: OmniNode-ai/omnibase_core

Length of output: 2413


🏁 Script executed:

# Read fsm_executor.py to see expression evaluation
cat -n src/omnibase_core/utils/fsm_executor.py | head -400

Repository: OmniNode-ai/omnibase_core

Length of output: 16641


🏁 Script executed:

# Check comparison operators enum
cat -n src/omnibase_core/enums/enum_comparison_operators.py

Repository: OmniNode-ai/omnibase_core

Length of output: 690


🏁 Script executed:

# Check condition operator enum
cat -n src/omnibase_core/enums/enum_condition_operator.py

Repository: OmniNode-ai/omnibase_core

Length of output: 876


🏁 Script executed:

# Continue reading fsm_executor.py from line 400 onwards
cat -n src/omnibase_core/utils/fsm_executor.py | sed -n '400,550p'

Repository: OmniNode-ai/omnibase_core

Length of output: 7112


🏁 Script executed:

# Search for action executor implementation
find src/omnibase_core -type f -name "*.py" | xargs grep -l "execute.*action\|action_executor" | grep -v test | head -10

Repository: OmniNode-ai/omnibase_core

Length of output: 306


🏁 Script executed:

# Read more of fsm_executor to find action execution
cat -n src/omnibase_core/utils/fsm_executor.py | sed -n '549,700p'

Repository: OmniNode-ai/omnibase_core

Length of output: 4103


🏁 Script executed:

# Search for what action types are actually supported
find src/omnibase_core -type f -name "*.py" | xargs grep -n "action_type.*event\|action_type.*logging\|action_type.*alert\|action_type.*data_capture\|action_type.*persistence\|action_type.*cleanup" | head -30

Repository: OmniNode-ai/omnibase_core

Length of output: 51


🏁 Script executed:

# Look for handler resolution and defaults
find src/omnibase_core -type f -name "*.py" | xargs grep -n "ProtocolLogger\|ProtocolEventBus\|handler.*default\|required.*\[\]" | head -30

Repository: OmniNode-ai/omnibase_core

Length of output: 3724


🏁 Script executed:

# Extract the actual expressions from the YAML file
grep -n "expression:" contracts/runtime/node_graph_reducer.yaml

Repository: OmniNode-ai/omnibase_core

Length of output: 336


🏁 Script executed:

# Search for any special handling of is_not_empty or exists operators
find src/omnibase_core -type f -name "*.py" | xargs grep -n "is_not_empty\|exists\|NOT_EXISTS\|EXISTS" | grep -v test | head -20

Repository: OmniNode-ai/omnibase_core

Length of output: 2235


🏁 Script executed:

# Read the exact VALID_OPERATORS whitelist from the condition model
cat -n src/omnibase_core/models/fsm/model_fsm_transition_condition.py | sed -n '99,101p'

Repository: OmniNode-ai/omnibase_core

Length of output: 226


🏁 Script executed:

# Confirm what operators are actually handled in the executor
grep -n "elif operator ==" src/omnibase_core/utils/fsm_executor.py | head -20

Repository: OmniNode-ai/omnibase_core

Length of output: 388


🏁 Script executed:

# Check if there's any override or additional handling for expressions
rg -A5 "is_not_empty|exists" src/omnibase_core/utils/fsm_executor.py

Repository: OmniNode-ai/omnibase_core

Length of output: 798


FSM contract expressions will fail validation—is_not_empty and equals operators are not supported.

The contract declares expressions using unsupported operators that will cause validation/execution failures:

  • Line 112 (node_registry is_not_empty): This is a 2-token expression, but the validator enforces exactly 3 tokens in format field operator value. Additionally, is_not_empty is not in the supported operator whitelist.
  • Lines 118, 142, 148, 195 (using equals): The operator equals is not in ModelFSMTransitionCondition.VALID_OPERATORS (which only includes ==, !=, <, >, <=, >=, in, not_in, contains, matches). Validation will reject these expressions at model instantiation.

The executor does handle equals as an alias for == (line 471 in fsm_executor.py), but the model validator blocks it first. Expressions must conform to the 3-token format with operators from the whitelist.

Suggested fixes:

  • Replace node_registry is_not_empty with a supported pattern (e.g., node_registry != empty or similar 3-token syntax)
  • Replace all instances of equals with ==

Also verify:

  • Wildcard transitions (from_state: '*') are confirmed as supported in the executor
  • Action types (event, logging, alert, data_capture, persistence, cleanup) are passed through intents without explicit type validation in the executor
  • Handler defaults (when required: []) rely on DI container resolution—confirm default implementations exist for all declared action types
🤖 Prompt for AI Agents
In contracts/runtime/node_graph_reducer.yaml around lines 8 and specifically
lines 112, 118, 142, 148 and 195, update FSM transition expressions to conform
to the validator's 3-token format and the operator whitelist: replace the
2-token "node_registry is_not_empty" with a 3-token form such as "node_registry
!= empty" (or another supported operator/value pair), and replace every use of
the unsupported "equals" operator with "=="; after making these operator
changes, verify that wildcard transitions (from_state: "*") are supported by the
executor and confirm that default handler implementations exist in the DI
container for the declared action types (event, logging, alert, data_capture,
persistence, cleanup) so required: [] defaults resolve correctly.

Comment on lines +238 to +282
def update_fingerprint_in_yaml(
content: str,
new_fingerprint: str,
) -> str:
"""Update fingerprint field in YAML content while preserving formatting.

Args:
content: Original YAML file content.
new_fingerprint: New fingerprint value to set.

Returns:
Updated YAML content with new fingerprint.
"""
# Pattern to match existing fingerprint field
fingerprint_pattern = re.compile(
r'^(\s*)fingerprint:\s*["\']?[\w.:/-]+["\']?\s*$',
re.MULTILINE,
)

match = fingerprint_pattern.search(content)
if match:
# Replace existing fingerprint
indent = match.group(1)
return fingerprint_pattern.sub(
f'{indent}fingerprint: "{new_fingerprint}"',
content,
)

# No existing fingerprint - add after version field
version_pattern = re.compile(
r'^(\s*)(version:\s*["\']?[\w./-]+["\']?\s*)$',
re.MULTILINE,
)
version_match = version_pattern.search(content)
if version_match:
indent = version_match.group(1)
version_line = version_match.group(0)
return content.replace(
version_line,
f'{version_line}\n{indent}fingerprint: "{new_fingerprint}"',
)

# Fallback: add at end of file
return content.rstrip() + f'\nfingerprint: "{new_fingerprint}"\n'

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

update_fingerprint_in_yaml() won’t insert correctly for common ONEX contracts (contract_version: / block version:), and will often append at EOF.

Recommend updating the insertion logic to:

  1. Prefer top-level contract_version: (inline and block mapping),
  2. Otherwise handle top-level version: (inline and block mapping),
  3. Then fallback to EOF.

Proposed patch (keeps “preserve formatting” approach, but handles block mappings by inserting after the indented block):

 def update_fingerprint_in_yaml(
     content: str,
     new_fingerprint: str,
 ) -> str:
@@
-    # No existing fingerprint - add after version field
-    version_pattern = re.compile(
-        r'^(\s*)(version:\s*["\']?[\w./-]+["\']?\s*)$',
-        re.MULTILINE,
-    )
-    version_match = version_pattern.search(content)
-    if version_match:
-        indent = version_match.group(1)
-        version_line = version_match.group(0)
-        return content.replace(
-            version_line,
-            f'{version_line}\n{indent}fingerprint: "{new_fingerprint}"',
-        )
+    def _insert_after_key_block(key: str) -> str | None:
+        lines = content.splitlines(True)
+        key_re = re.compile(rf'^(?P<indent>\s*){re.escape(key)}:\s*(?P<rest>.*)?$')
+        for i, line in enumerate(lines):
+            m = key_re.match(line)
+            if not m:
+                continue
+            indent = m.group("indent") or ""
+            rest = (m.group("rest") or "").strip()
+            # Inline mapping/scalar: insert right after the line.
+            if rest and not rest.startswith("#"):
+                lines.insert(i + 1, f'{indent}fingerprint: "{new_fingerprint}"\n')
+                return "".join(lines)
+            # Block mapping: insert after subsequent lines that are more-indented than the key.
+            key_indent_len = len(indent)
+            j = i + 1
+            while j < len(lines):
+                nxt = lines[j]
+                if not nxt.strip() or nxt.lstrip().startswith("#"):
+                    j += 1
+                    continue
+                nxt_indent_len = len(nxt) - len(nxt.lstrip(" "))
+                if nxt_indent_len <= key_indent_len:
+                    break
+                j += 1
+            lines.insert(j, f'{indent}fingerprint: "{new_fingerprint}"\n')
+            return "".join(lines)
+        return None
+
+    # No existing fingerprint - add after contract_version or version (top-level)
+    updated = _insert_after_key_block("contract_version")
+    if updated is not None:
+        return updated
+    updated = _insert_after_key_block("version")
+    if updated is not None:
+        return updated
 
     # Fallback: add at end of file
     return content.rstrip() + f'\nfingerprint: "{new_fingerprint}"\n'
🤖 Prompt for AI Agents
In scripts/regenerate_fingerprints.py around lines 238 to 282,
update_fingerprint_in_yaml currently only matches a single-line top-level
fingerprint or a one-line version entry and therefore fails for common ONEX
manifests that use top-level contract_version or a block-mapped version
(indented block), often appending to EOF; change the insertion logic to (1)
first detect a top-level contract_version key (both inline and block mapping)
and insert the fingerprint immediately after that key or after the end of its
indented block, (2) otherwise detect a top-level version key (both inline and
block mapping) and insert after that key or its indented block, and (3) only
then fallback to appending at EOF; implement this by using regexes that assert a
true top-level key (no non-space prefix), detect if the value is inline or
followed by an indented block, and when a block is present find the end by
scanning for the next line with indentation less than or equal to the key’s
indent (or next top-level key) and insert the fingerprint at that point while
preserving existing indentation and newline style.

For complex values, serialize to JSON strings.
"""

model_config = ConfigDict(extra="forbid")

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.

🛠️ Refactor suggestion | 🟠 Major

Add missing ConfigDict options for strict validation and nested usage.

The ConfigDict is incomplete. Based on coding guidelines and learnings:

  1. Add validate_assignment=True to ensure runtime validation on field assignments
  2. Add from_attributes=True since this model will be nested in other Pydantic models (e.g., ModelGraphNode)

Apply this diff:

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

Based on learnings, from_attributes=True is required for immutable value objects that are nested in other Pydantic models.

🤖 Prompt for AI Agents
In src/omnibase_core/models/common/model_graph_node_inputs.py around line 21,
the ConfigDict currently only sets extra="forbid"; update it to include
validate_assignment=True and from_attributes=True so the model enforces runtime
validation on field assignments and can be constructed when nested inside other
Pydantic models (e.g., ModelGraphNode). Ensure the single ConfigDict declaration
adds both options alongside extra="forbid".

Comment on lines +8 to 9
from pydantic import BaseModel, Field, model_validator

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

default/enum typing widened, but type↔value consistency is still unenforced.

Now that default/enum support non-strings, it’s easy to produce schemas like type="boolean", default="true" without any model-level guard. If nothing else enforces this downstream, consider adding a small @model_validator(mode="after") on ModelConfigSchemaProperty to validate default and each enum entry against the declared type (Pydantic v2 API).

Also applies to: 176-253

🤖 Prompt for AI Agents
In src/omnibase_core/models/common/model_typed_metadata.py around lines 8-9 and
also apply to 176-253, add a Pydantic v2 @model_validator(mode="after") on
ModelConfigSchemaProperty that enforces consistency between the declared "type"
and the values in "default" and each entry of "enum": for each
non-missing/defaulted value, coerce or check it matches the schema 'type' (e.g.,
"string", "number"/"integer", "boolean", "object", "array") and raise a clear
ValueError if a mismatch is found; treat null/None and any explicit "nullable"
semantics appropriately (allow None if nullable), and include the property name
and offending value in the error message so downstream consumers cannot create
schemas like type="boolean" with default="true".

Comment on lines +429 to +460
def test_compute_fingerprint_for_contract_consistency(self) -> None:
"""Test compute_fingerprint_for_contract returns consistent results."""
contract_data = {
"name": "TestContract",
"version": {"major": 1, "minor": 0, "patch": 0},
"node_type": "COMPUTE_GENERIC",
"description": "Test contract",
"input_model": "ModelInput",
"output_model": "ModelOutput",
"dependencies": [],
"algorithm": {
"algorithm_type": "default",
"factors": {
"default_factor": {
"weight": 1.0,
"calculation_method": "identity",
}
},
},
}

# Compute multiple times
fingerprints = [
compute_fingerprint_for_contract(contract_data) for _ in range(5)
]

# Filter out None results and check consistency
valid_fingerprints = [fp for fp in fingerprints if fp is not None]
if valid_fingerprints:
first = str(valid_fingerprints[0])
assert all(str(fp) == first for fp in valid_fingerprints)

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 | 🔴 Critical

Fingerprint consistency test is currently incorrect (uses FingerprintResult instead of its .fingerprint).

This should compare FingerprintResult.fingerprint (stringified fingerprint), not str(FingerprintResult):

 def test_compute_fingerprint_for_contract_consistency(self) -> None:
     """Test compute_fingerprint_for_contract returns consistent results."""
@@
-    fingerprints = [
-        compute_fingerprint_for_contract(contract_data) for _ in range(5)
-    ]
-
-    # Filter out None results and check consistency
-    valid_fingerprints = [fp for fp in fingerprints if fp is not None]
-    if valid_fingerprints:
-        first = str(valid_fingerprints[0])
-        assert all(str(fp) == first for fp in valid_fingerprints)
+    results = [compute_fingerprint_for_contract(contract_data) for _ in range(5)]
+    fingerprints = [r.fingerprint for r in results if r.fingerprint is not None and r.error is None]
+    if fingerprints:
+        first = str(fingerprints[0])
+        assert all(str(fp) == first for fp in fingerprints)
🤖 Prompt for AI Agents
In tests/unit/scripts/test_regenerate_fingerprints.py around lines 429 to 460,
the fingerprint consistency test compares str(FingerprintResult) instead of the
actual fingerprint string; update the test to extract
FingerprintResult.fingerprint from each non-None result (e.g., map or list
comprehension to collect fp.fingerprint), then compare those fingerprint strings
for equality (use the first fingerprint string as the baseline and assert all
others equal it). Ensure you still filter out None results before accessing
.fingerprint to avoid AttributeError.

Comment on lines +1108 to +1141
@pytest.mark.unit
class TestFingerprintComputationEdgeCases:
"""Edge case tests for fingerprint computation."""

def test_compute_fingerprint_with_schema_validation_error(self) -> None:
"""Test that schema validation errors are handled gracefully."""
# Create contract data that will fail schema validation
contract_data = {
"node_type": "COMPUTE_GENERIC",
"name": "TestBadContract",
"version": "invalid_version", # Invalid version format
"input_model": "ModelInput",
"output_model": "ModelOutput",
"description": "Test",
}

fingerprint = compute_fingerprint_for_contract(contract_data)

# Should return None on validation error (not raise)
# Note: actual behavior depends on implementation
# This test documents expected behavior

def test_compute_fingerprint_with_missing_required_fields(self) -> None:
"""Test fingerprint computation with missing required fields."""
contract_data = {
"node_type": "COMPUTE_GENERIC",
"name": "TestMinimal",
# Missing other required fields
}

fingerprint = compute_fingerprint_for_contract(contract_data)

# Should return None or handle gracefully

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

Two tests are placeholders with no assertions; they won’t catch regressions.

At minimum, assert the expected “error-but-no-raise” contract:

 def test_compute_fingerprint_with_schema_validation_error(self) -> None:
@@
-    fingerprint = compute_fingerprint_for_contract(contract_data)
-
-    # Should return None on validation error (not raise)
-    # Note: actual behavior depends on implementation
-    # This test documents expected behavior
+    result = compute_fingerprint_for_contract(contract_data)
+    assert result.fingerprint is None
+    assert result.error is not None
@@
 def test_compute_fingerprint_with_missing_required_fields(self) -> None:
@@
-    fingerprint = compute_fingerprint_for_contract(contract_data)
-
-    # Should return None or handle gracefully
+    result = compute_fingerprint_for_contract(contract_data)
+    assert result.fingerprint is None
+    assert result.error is not None

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In tests/unit/scripts/test_regenerate_fingerprints.py around lines 1108 to 1141,
the two placeholder tests for schema validation and missing fields have no
assertions and therefore don't validate behavior; update each test to assert the
expected "error-but-no-raise" contract by calling
compute_fingerprint_for_contract(...) inside the test and asserting the returned
fingerprint is None (or explicitly comparing to the project’s documented
fallback value), and optionally assert no exception was raised by not wrapping
the call in try/except; keep the tests minimal and deterministic so they fail if
compute_fingerprint_for_contract starts raising or returns an unexpected value.

@claude

claude Bot commented Dec 13, 2025

Copy link
Copy Markdown

Code Review - PR #180

I've completed a comprehensive review of this PR. Overall, this is solid foundational work that adds valuable structure to the codebase. Here's my assessment:


✅ Strengths

  1. Excellent Documentation 📚

    • The new NAMING_CONVENTIONS.md and PYDANTIC_BEST_PRACTICES.md are comprehensive and well-structured
    • Clear examples and rationale for design decisions
    • Aligns with ONEX architecture principles
  2. Structured Type Safety 🛡️

    • Replacing dict[str, Any] with explicit Pydantic models (ModelOperationData, ModelIntentPayload, etc.) significantly improves type safety
    • All new models follow strict typing conventions
    • Proper use of extra="forbid" for validation
  3. Utility Script Quality 🔧

    • scripts/regenerate_fingerprints.py is well-documented and production-ready
    • Comprehensive error handling with proper exit codes
    • Good CLI ergonomics (dry-run, verbose, JSON output)
    • Appropriate security measures (10MB file size limit)
  4. Consistent Patterns 🎯

    • TypedDict refactoring into separate files improves modularity
    • Contract updates follow consistent fingerprint format
    • All models use appropriate Pydantic ConfigDict settings

⚠️ Issues Requiring Attention

CRITICAL: Fingerprint Format Inconsistency 🚨

Location: contracts/runtime/contract_registry_reducer.yaml:6, contracts/runtime/node_graph_reducer.yaml:6, and potentially others

Issue: Some contracts use "v1.1.0:..." (with 'v' prefix) while documentation and other contracts use "1.1.0:..." (no prefix).

Per docs/conventions/NAMING_CONVENTIONS.md:363:

Important: The semver component must NOT include a 'v' prefix. Use 1.0.0, not v1.0.0.

Impact: This will cause fingerprint validation failures and contract loading errors.

Fix Required:

# Regenerate all fingerprints to ensure consistency
poetry run python scripts/regenerate_fingerprints.py contracts/ --recursive

MAJOR: Type Safety Concerns 🔒

1. dict[str, str] May Be Too Restrictive

Files:

  • src/omnibase_core/models/common/model_operation_data.py (lines 42, 57, 87)
  • src/omnibase_core/models/common/model_intent_payload.py (lines 25, 75)

Issue: Using dict[str, str] for parameters, headers, event_data, etc. forces all values to be strings. However:

  • HTTP headers can have integer values (e.g., Content-Length: 1024)
  • Event data often contains numbers, booleans, or nested structures
  • Query parameters may include arrays or objects

Recommendation: Consider one of these approaches:

  1. Use dict[str, Any] with a comment explaining serialization requirements
  2. Use dict[str, ModelSchemaValue] to leverage existing typed value wrapper
  3. Document that complex values must be JSON-serialized to strings
2. Boolean/Integer Type Confusion

File: src/omnibase_core/models/common/model_config_schema_property.py:87-98

Issue: Python's bool is a subclass of int, so isinstance(True, int) returns True. The current validation allows booleans for integer type fields.

Fix:

# Add before line 92
if self.type == "integer" and isinstance(self.default, bool):
    raise ValueError(
        f"Default value {self.default\!r} is boolean but type is 'integer'. "
        "Use an integer value instead."
    )
3. default Field Type Limitation

File: src/omnibase_core/models/common/model_config_schema_property.py:39-42

Issue: Field supports type: "array" and type: "object" but default is typed as str | int | float | bool | None, preventing list/dict defaults.

Fix: Either:

  • Expand type to str | int | float | bool | list | dict | None
  • Or document that array/object defaults are not supported

MAJOR: Missing Schema Validation 📋

File: src/omnibase_core/models/common/model_mixin_config_schema.py:12-32

Issue: No validation ensures required_properties references exist in properties. You can ship an internally inconsistent schema.

Fix:

from pydantic import model_validator

@model_validator(mode="after")
def _validate_required_properties(self) -> "ModelMixinConfigSchema":
    missing = [p for p in self.required_properties if p not in self.properties]
    if missing:
        raise ValueError(f"required_properties not in properties: {missing}")
    return self

MINOR: Inconsistencies

  1. Version Comments in Example Contracts

    • Several example contracts have comments referencing "v1.0" but are actually v1.1.0
    • Files: user_profile_normalizer.yaml, http_api_call.yaml, kafka_produce.yaml, resilient_effect.yaml
  2. Redundant Config

    • model_shutdown_metrics.py:21: validate_assignment=True is redundant with frozen=True
  3. Missing from_attributes=True

    • Per CLAUDE.md guidelines, ModelConfigSchemaProperty should have from_attributes=True since it's nested in other models
    • Same for several other metadata models

🎯 Recommendations

High Priority

  1. Run fingerprint regeneration to fix format inconsistencies
  2. Add boolean rejection in integer type validation
  3. Add schema validation for ModelMixinConfigSchema
  4. Reconsider dict[str, str] restrictions - document or expand types

Medium Priority

  1. Update version comments in example contracts
  2. Add from_attributes=True to immutable nested models
  3. Consider deduplicating ModelToolMetadataFields and ModelNodeCapabilitiesMetadata (7/8 fields overlap)

Low Priority

  1. Add logging to regenerate_fingerprints.py for debugging
  2. Enhance regex pattern to match dict-style YAML versions
  3. Remove redundant validate_assignment=True where frozen=True is used

📊 Testing & CI

Question: What test coverage exists for the new models?

  • I don't see test files for model_operation_data, model_intent_payload, regenerate_fingerprints, etc.
  • Per CLAUDE.md, 60%+ coverage is required
  • The script has complex logic (YAML parsing, regex, file I/O) that should be tested

Recommendation: Add unit tests for:

  • ModelOperationData validation edge cases
  • ModelIntentPayload validation
  • ModelConfigSchemaProperty type validation (especially bool/int confusion)
  • regenerate_fingerprints.py core functions

🎓 Code Quality Compliance

✅ Passes:

  • Follows ONEX naming conventions
  • Uses Poetry (script documented with poetry run)
  • Structured errors (ModelOnexError) in appropriate places
  • Good documentation and docstrings
  • Follows Pydantic best practices (mostly)

⚠️ Needs Verification:

  • Type checker compliance (mypy strict + pyright) - did CI pass?
  • Test coverage metrics - are we above 60%?
  • Pre-commit hooks passed?

🚀 Conclusion

This PR represents significant progress in adding structured typing and improving maintainability. The documentation additions are particularly valuable.

Recommendation: Request changes for the fingerprint format inconsistency and type safety issues. These should be addressed before merge to prevent downstream problems.

Once the critical issues are fixed, this will be a strong addition to the codebase.

Estimated effort to fix: 2-3 hours

  • 30 min: Regenerate fingerprints
  • 60 min: Fix type validation issues
  • 30 min: Add schema validation
  • 30 min: Update version comments

Reviewed by: Claude (Sonnet 4.5)
Review Date: 2025-12-13
PR Size: 4,132 additions / 777 deletions (84% new code)
Files Changed: 46

@jonahgabriel
jonahgabriel merged commit 3d4c7a9 into main Dec 13, 2025
27 of 30 checks passed
@jonahgabriel
jonahgabriel deleted the feat/new-models-contracts-docs branch December 13, 2025 23:15
jonahgabriel added a commit that referenced this pull request Dec 13, 2025
CRITICAL fixes:
- Fix FSM expression in node_graph_reducer.yaml (is_not_empty → min_length 1)
- Fix fingerprint consistency test to use .fingerprint attribute

NEW TYPED MODELS (replacing dict[str, str] anti-pattern):
- ModelGraphNodeParameter: Individual typed parameter with value inference
- ModelGraphNodeParameters: Container with from_dict/to_dict helpers
- ModelOutputReference: Validated "node_id.output_name" references
- ModelOutputMapping: Container for output mappings
- ModelQueryParameters: Query params with ParameterValue union type
- ModelEnvelopePayload: Typed event payload with common fields

MAJOR fixes:
- Add from_attributes=True to ConfigDict in 3 models
- Add type↔default consistency validator to ModelConfigSchemaProperty
- Improve update_fingerprint_in_yaml() for dict-style versions
- Add TODO comments for unimplemented subscription handlers
- Fix fingerprint prefix format (remove v prefix) in example contract
- Update model_graph_node_inputs.py to use typed models
- Update model_operation_data.py to use typed models
- Update model_typed_metadata.py to use typed models
- Change partition_id/window_id to UUID type

MINOR fixes:
- Implement 2 placeholder tests with proper assertions
- Add 22 new tests for type validation
- Update documentation versions to v0.4.0

Note: model_typed_metadata.py single-class-per-file violation is
pre-existing (16 classes existed before this PR). Tracked separately.
jonahgabriel added a commit that referenced this pull request Dec 14, 2025
- Add type↔value consistency validation for default/enum fields in ModelTypedMetadata
- Fix FSM contract is_recoverable constraint for terminal stopped state
- Add handler_status and handler_implementation metadata to event_bus_wiring contract
- Improve regenerate_fingerprints.py to handle flow-style YAML and OSError
- Remove redundant validate_assignment=True from frozen models (6 files)
- Update documentation version references from v0.4.0 to v0.3.6
- Add 43 new tests for type validation and 3 new contract handler tests
jonahgabriel added a commit that referenced this pull request Dec 15, 2025
* feat: add new models, contracts, and documentation [OMN-675]

Add 16 new common model files for better code organization:
- model_config_schema_property.py
- model_custom_health_metrics.py
- model_effect_metadata.py
- model_event_subscription_config.py
- model_graph_node_data.py
- model_graph_node_inputs.py
- model_intent_payload.py
- model_introspection_custom_metrics.py
- model_mixin_config_schema.py
- model_node_capabilities_metadata.py
- model_operation_data.py
- model_reducer_metadata.py
- model_request_metadata.py
- model_shutdown_metrics.py
- model_tool_metadata_fields.py
- model_tool_result_data.py

Split typed_dict_status_summaries.py into separate files:
- typed_dict_active_summary.py
- typed_dict_error_summary.py
- typed_dict_maintenance_summary.py

Update 15 YAML contract files with fingerprints and schema changes.

Add documentation:
- NAMING_CONVENTIONS.md
- PYDANTIC_BEST_PRACTICES.md

Add scripts/regenerate_fingerprints.py utility.

Part 2 of 3 in PR #168 split.

* fix: address PR #180 review feedback for models and contracts

Contract Changes:
- Fix fingerprint prefix format: v1.1.0: → 1.1.0: (canonical semver)
- Add version divergence comment in node_graph_reducer.yaml

Model Changes:
- Add ConfigDict(extra="forbid") to all common models
- Add from_attributes=True to metadata models for ORM compatibility
- Fix priority field typing: str → LiteralEventPriority in effect/request metadata
- Add docstrings explaining all-optional fields pattern for metadata models
- Add note about dict[str, str] per ONEX strict typing standards

Documentation Changes:
- Update NAMING_CONVENTIONS.md fingerprint format (remove 'v' prefix)
- Document both hierarchical and simple profile_tags formats

Note: Kept dict[str, str] types per project strict typing standards
(dict[str, Any] is prohibited by pre-commit hooks). Complex values
should be serialized to JSON strings.

[OMN-675]

* fix: address remaining PR #180 review feedback

MAJOR fixes:
- Fix fingerprint prefix in contract_registry_reducer.yaml (v1.1.0: -> 1.1.0:)
- Add handler documentation to event_bus_wiring_effect.yaml and node_graph_reducer.yaml
- Improve fingerprint script error handling with FingerprintResult class
- Update PYDANTIC_BEST_PRACTICES.md for consistency with implementations

MINOR/NITPICK improvements:
- Add required_properties invariant validation to 3 schema models
- Add priority field constraints (ge=0, le=100) to subscription/graph models
- Expand enum field support to non-string values (int, float, bool, None)
- Add comprehensive fingerprint script tests (54 tests)

Test coverage:
- Type validation tests (default/type mismatches)
- Dry-run mode verification
- Fingerprint consistency tests
- Malformed YAML handling
- File size limit enforcement

Note: Pre-commit hooks flag pre-existing issues in model_typed_metadata.py
(16 classes in one file, str IDs) - these are not introduced by this PR.

* fix: address PR #180 review with proper typed Pydantic models

CRITICAL fixes:
- Fix FSM expression in node_graph_reducer.yaml (is_not_empty → min_length 1)
- Fix fingerprint consistency test to use .fingerprint attribute

NEW TYPED MODELS (replacing dict[str, str] anti-pattern):
- ModelGraphNodeParameter: Individual typed parameter with value inference
- ModelGraphNodeParameters: Container with from_dict/to_dict helpers
- ModelOutputReference: Validated "node_id.output_name" references
- ModelOutputMapping: Container for output mappings
- ModelQueryParameters: Query params with ParameterValue union type
- ModelEnvelopePayload: Typed event payload with common fields

MAJOR fixes:
- Add from_attributes=True to ConfigDict in 3 models
- Add type↔default consistency validator to ModelConfigSchemaProperty
- Improve update_fingerprint_in_yaml() for dict-style versions
- Add TODO comments for unimplemented subscription handlers
- Fix fingerprint prefix format (remove v prefix) in example contract
- Update model_graph_node_inputs.py to use typed models
- Update model_operation_data.py to use typed models
- Update model_typed_metadata.py to use typed models
- Change partition_id/window_id to UUID type

MINOR fixes:
- Implement 2 placeholder tests with proper assertions
- Add 22 new tests for type validation
- Update documentation versions to v0.4.0

Note: model_typed_metadata.py single-class-per-file violation is
pre-existing (16 classes existed before this PR). Tracked separately.

* docs: add comprehensive docstrings for typed Pydantic models

- Enhanced module-level docstrings with examples for all 6 new typed models
- Added security documentation (MAX_PARAMETERS, max_length constraints, URL encoding)
- Cross-referenced related classes in docstrings for discoverability
- Simplified UUID field descriptions without legacy migration patterns

Addresses PR #186 review feedback:
- Security Considerations: Documented existing security measures
- Error Context Consistency: Verified consistent patterns
- Generate Docstrings: Added comprehensive docstrings to all new models
- UUID Type Change: Simplified documentation (no legacy support per ONEX policy)

Note: single-class-per-file violation in model_typed_metadata.py is pre-existing
(16 classes existed before this PR) - tracked separately for future refactor.

* fix: remove duplicate ModelGraphNodeInputs class from model_typed_metadata

PR #186 review identified a critical issue: ModelGraphNodeInputs was
defined in two files with different implementations:
- model_graph_node_inputs.py (complete: has from_attributes=True, helper methods)
- model_typed_metadata.py (incomplete: lacks from_attributes, no helpers)

This commit:
- Removes the duplicate class from model_typed_metadata.py
- Updates __init__.py to import from the correct module
- Removes ModelGraphNodeInputs from model_typed_metadata's __all__ list

The correct implementation in model_graph_node_inputs.py includes:
- ConfigDict(extra="forbid", from_attributes=True)
- get_parameter_dict() helper method
- get_output_mapping_dict() helper method

Note: single-class-per-file violation in model_typed_metadata.py is
pre-existing (15 classes existed before this PR) - tracked separately.

* fix: correct fingerprint version format and mixin default type in tests

- Remove incorrect 'v' prefix expectation from fingerprint version tests
  (actual format is '1.1.0:hash', not 'v1.1.0:hash')
- Fix mixin discovery test to use integer default (3) instead of string ("3")
- Updates 3 test methods in test_contract_v110_fields.py
- Fixes 16 CI test failures in Split 7/20

* fix(models): address PR #186 review feedback

- Fix priority constraint in ModelGraphNodeData: change le=100 to le=1000
  to match ModelWorkflowStep and allow priority=500 used in tests
- Replace OMN-XXX placeholders with generic TODO comments in
  event_bus_wiring_effect.yaml
- Use keyword arguments for ModelOnexError context in
  model_query_parameters.py for cleaner API usage

Note: Pre-commit hook failures are pre-existing issues unrelated to this change:
- service/ vs services/ directory duplication (tracked separately)
- model_typed_metadata.py single-class-per-file (tracked separately)

* fix(models): add security constraints and O(1) caching [PR #186]

Additional fixes from PR #186 review:
- Add O(1) caching for ModelOutputMapping reference lookups
- Add security constraints (MAX limits, length validation) to:
  - ModelEnvelopePayload: MAX_FIELD_LENGTH, MAX_DATA_ENTRIES
  - ModelOperationData: MAX_HEADERS, MAX_BODY_SIZE, etc.
  - ModelOutputReference: max_length on description/transform
- Update Version History in CONTAINER_TYPES.md for v0.4.0

* fix(models): address PR #180 review feedback

- Add type↔value consistency validation for default/enum fields in ModelTypedMetadata
- Fix FSM contract is_recoverable constraint for terminal stopped state
- Add handler_status and handler_implementation metadata to event_bus_wiring contract
- Improve regenerate_fingerprints.py to handle flow-style YAML and OSError
- Remove redundant validate_assignment=True from frozen models (6 files)
- Update documentation version references from v0.4.0 to v0.3.6
- Add 43 new tests for type validation and 3 new contract handler tests

* fix(contracts): remove 'v' prefix from fingerprint versions

Remove the 'v' prefix from fingerprint version strings in all contract
YAML files to match the expected format in v1.1.0 contract spec.

The fingerprint format should be "{version}:{12-char-hash}" where version
is X.Y.Z without a 'v' prefix (e.g., "1.1.0:c753f440fda3").

This matches the contract_version dict format {major: X, minor: Y, patch: Z}
and fixes test_fingerprint_version_matches_contract_version failures.

Files updated:
- contracts/runtime/contract_registry_reducer.yaml
- contracts/runtime/contract_loader_effect.yaml
- contracts/runtime/runtime_orchestrator.yaml
- contracts/runtime/event_bus_wiring_effect.yaml
- examples/contracts/reducer_metrics_aggregator.yaml
- examples/contracts/compute/user_profile_normalizer.yaml
- examples/contracts/orchestrator_data_pipeline.yaml
- examples/contracts/effect/db_query.yaml
- examples/contracts/effect/kafka_produce.yaml
- examples/contracts/effect/http_api_call.yaml
- examples/contracts/effect/resilient_effect.yaml

* fix(models): address CodeRabbit PR #186 review feedback

- Fix get_bool() to return default for unrecognized strings instead of False
- Fix ModelOperationData validator to use Self return type and ModelOnexError
- Add duplicate local_name validation to ModelOutputMapping
- Fix timezone handling in ModelEnvelopePayload.with_timestamp() to use UTC
- Add from_attributes=True to ModelConfig for parallel test compatibility
- Update NAMING_CONVENTIONS.md version from v0.3.6 to v0.4.0
- Fix OMN-XXX placeholder with proper Tracking comment in contract

* fix(models): use Self return types, ModelOnexError, remove dict round-trips

Address CodeRabbit PR #186 review feedback:

## Self return types and ModelOnexError
- model_envelope_payload.py: _validate_data_size(), set_data(), with_timestamp()
- model_output_mapping.py: _build_lookup_cache(), from_dict()

## Remove unnecessary dict round-trip patterns
- model_connection_info.py: Remove redundant model_dump/model_validate
- model_git_hub_actions_workflow.py: Use direct model validation
- model_secret_config.py: Use model_validate instead of **model_dump()
- model_backend_config.py: Add from_attributes=True for direct validation

* fix(models): address additional PR #186 review feedback

- Remove unused timezone import from model_envelope_payload.py
- Add guard assertions to find()-based ordering tests to prevent
  vacuously true comparisons when substrings are not found

* feat(events): add runtime event models for event_bus_wiring contract

Create typed event models referenced in event_bus_wiring_effect.yaml,
following ONEX single-class-per-file convention.

Base:
- ModelRuntimeEventBase: Common fields for all runtime events

Node lifecycle:
- ModelNodeRegisteredEvent: Node registration for hot-reload
- ModelNodeUnregisteredEvent: Node removal and cleanup

Subscription lifecycle:
- ModelSubscriptionCreatedEvent: Successful subscription confirmation
- ModelSubscriptionRemovedEvent: Subscription cleanup
- ModelSubscriptionFailedEvent: Subscription failure tracking

Runtime state:
- ModelRuntimeReadyEvent: Runtime fully initialized
- ModelWiringErrorEvent: Critical wiring errors

Graph events:
- ModelNodeGraphReadyEvent: Node graph ready for wiring
- ModelWiringResultEvent: Wiring operation outcome

Supporting typed models (replacing dict[str, Any]):
- ModelNodeGraphInfo: Typed node information for graphs
- ModelWiringErrorInfo: Typed error details for wiring

Addresses PR #186 review feedback for missing event schema models.

* fix(models): convert model_typed_metadata.py to re-export module

- Replace model_config_schema_property.py with full implementation
  from model_typed_metadata.py including:
  - type: str field (supports aliases: 'bool', 'int', 'str', 'float')
  - Full validate_type_default_consistency validator
  - Full validate_type_enum_consistency validator
  - Full _validate_value_type helper with ModelOnexError
- Fix Self return type in model_mixin_config_schema.py validator
- Convert model_typed_metadata.py to unified re-export module
  (all 15 classes now in individual files per ONEX rules)

All 43 typed_metadata tests pass including type alias tests.
Addresses PR #186 review feedback.

* fix(events): address PR #186 review feedback for runtime event models

Changes:
- model_envelope_payload.py: Fix from_dict/to_dict round-trip mismatch,
  add RESERVED_KEYS constant, prefix reserved keys in to_string_dict()
  to prevent collision with typed fields
- Runtime event models: Use timezone-aware UTC datetimes for timestamp,
  subscribed_at, removed_at, failed_at, ready_at fields
- Event factory methods: Replace `x or []` patterns with explicit
  `x if x is not None else []` to preserve empty lists
- Add from_attributes=True to ConfigDict for pytest-xdist compatibility
  in model_runtime_event_base, model_node_graph_info, model_wiring_error_info

Files modified (13):
- src/omnibase_core/models/common/model_envelope_payload.py
- src/omnibase_core/models/events/model_runtime_event_base.py
- src/omnibase_core/models/events/model_subscription_*.py (3 files)
- src/omnibase_core/models/events/model_runtime_ready_event.py
- src/omnibase_core/models/events/model_wiring_*.py (2 files)
- src/omnibase_core/models/events/model_node_*.py (3 files)
- src/omnibase_core/models/events/model_node_graph_info.py
- src/omnibase_core/models/events/model_wiring_error_info.py

Verified: mypy strict (0 errors), 998 unit tests pass

* fix(models): address PR #186 review feedback - comprehensive fixes

CRITICAL:
- ModelEventSubscriptionConfig: Change priority constraint from 0-100 to 0-1000
  to align with other models and prevent rejection of valid test data

MAJOR:
- ModelEnvelopePayload: Add warnings for silent data loss when dict values
  are skipped, improve reserved-key collision handling in to_string_dict()
- ModelNodeRegisteredEvent: Change node_type from str to EnumNodeKind
  for type safety and ONEX pattern consistency
- ModelEventEnvelope: Use timezone-aware datetime.now(UTC) for distributed
  event tracing consistency

NITPICKS:
- ModelNodeGraphReadyEvent/ModelRuntimeReadyEvent: Add node_count consistency
  validators to ensure node_count matches len(nodes) when both provided
- event_bus_wiring_effect.yaml: Remove OMN-XXX placeholder text

TESTS:
- Add comprehensive test suite for ModelEnvelopePayload (34 tests)
- Add comprehensive test suite for ModelQueryParameters (42 tests)

* docs(CLAUDE.md): fix from_attributes=True model paths and expand list

- Fix 4 incorrect file paths for documented models
- Add total count (29 models use this pattern)
- Add discovery command for finding all models
- Add additional key models: ModelContractBase, ModelFSMStateSnapshot
- Reference model categories: common, events, configuration

* fix(models): fix CI test failures for introspection and contract tests

- Remove invalid metadata={"error": ...} from ModelNodeCapabilities in
  create_error_response() - error message already in additional_info
- Add tracking reference for planned handlers in event_bus_wiring_effect.yaml

Fixes test_error_handling, test_factory_methods, and
test_planned_handlers_are_documented failures in PR #186 CI.

* fix(models): address PR #186 review feedback - nitpicks and improvements

- Add from_attributes=True to 13 frozen FSM/contract models for pytest-xdist
  compatibility (model_fsm_state, model_fsm_transition, model_intent, etc.)
- Fix 22 occurrences of `or []` pattern → `is not None else []` across 20 files
  to preserve empty lists instead of treating them as falsy
- Add strict mode to ModelEnvelopePayload.to_string_dict() with reserved-key
  collision detection and has_reserved_key_collision() method
- Add comprehensive timezone handling documentation to model_runtime_event_base.py
  and model_envelope_payload.py
- Add descriptive error messages to find()-based assertions in
  test_regenerate_fingerprints.py

All 9,005 model tests pass. No breaking changes.

* fix(models): address PR #186 review feedback - release ready improvements

- Add validate_assignment=True to 7 mutable models with validators
  - model_output_reference, model_operation_data, model_query_parameters
  - model_envelope_payload, model_validation_issue, model_value_container
  - model_mixin_config_schema

- Fix explicit None handling patterns (x or [] -> x if x is not None else [])
  - model_yaml_value, model_schema_value (2 occurrences)
  - model_flexible_value, model_mixin_metadata_collection (8 occurrences)
  - model_unified_hub_contract (2 occurrences), model_generic_collection

- Replace ValueError with ModelOnexError in model_node_graph_ready_event
  - Use EnumCoreErrorCode.VALIDATION_ERROR for consistency

- Add comprehensive round-trip documentation to ModelEnvelopePayload
  - Document that to_string_dict/from_string_dict are NOT round-trip compatible
  - Explain transformations: reserved key prefixing, type serialization

- Add @pytest.mark.unit markers to 9 test classes in test_model_query_parameters.py

- Add descriptive assertion messages to find()-based ordering tests
  - test_regenerate_fingerprints.py: 4 ordering assertions improved

* fix(models): fix Pydantic validation errors for config_schema and typed mapping

- Fix ModelTypedMapping test to use correct serialization format
- Add JSON Schema field mapping validator to ModelConfigSchemaProperty
- Add flat-to-structured format converter for ModelMixinConfigSchema
- Allow extra fields in config schema property for JSON Schema support

Fixes 18 CI test failures in PR #186
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