Repository navigation
feat: add new models, contracts, and documentation [OMN-675] - #180
Conversation
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.
WalkthroughAdds 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
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
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Areas requiring extra attention:
Possibly related PRs
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ 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)
Comment |
Code Review - PR #180: Add new models, contracts, and documentation [OMN-675]SummaryThis 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. ✅ Strengths1. Excellent Model DesignThe new common models demonstrate strong Pydantic practices:
2. Outstanding Script Implementation
3. TypedDict RefactoringThe split of
4. Comprehensive Documentation
5. Contract Fingerprint UpdatesAll 15 contract files updated with consistent fingerprint format:
🔍 Issues Found1. Security: YAML Parsing Without Validation
|
There was a problem hiding this comment.
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.
Withcontract_version.minor: 1andeffect_operations.versionat 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 makingProtocolLoggerrequired if observability logging is enabled.Given
observability.log_request/log_responseare set totrue, treatingProtocolLoggeras 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_versionat lines 70-73 is1.1.0. Update the comment to reflect the actual version.-# v1.0 Contract Schema Version +# v1.1.0 Contract Schema Versionsrc/omnibase_core/models/common/model_config_schema_property.py-39-42 (1)
39-42:defaultfield type doesn't support array/object defaults.The
defaultfield is typed asstr | int | float | bool | None, but the model supportstype: "array"andtype: "object". If someone setstype: "array", they cannot provide a list default value. Either expand the type union to includelistanddict, 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,
boolis a subclass ofint, soisinstance(True, int)returnsTrue. If someone setstype: "integer"withdefault: 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 - usesvprefix.This contract's fingerprint uses
"v1.1.0:c753f440fda3"with avprefix, but other contracts in this PR (e.g.,user_profile_normalizer.yaml,http_api_call.yaml,kafka_produce.yaml) use the format without thevprefix:"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 tighteningstatus/status_codeif semantics are fixed.
Ifstatusis expected to be one of a small set (healthy/warning/critical/error) andstatus_codeis normalized, usingLiteral[...]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 whethermetrics/data_fieldsare too narrow.If tool outputs can include ints/strings/bools (common for metrics and extra fields),
dict[str, float]anddict[str, str]may force lossy conversions. If strictness is desired, consider widening types intentionally (and addingextra="forbid"to avoid regressing to “free-form dict”).src/omnibase_core/models/common/model_mixin_config_schema.py (1)
12-32: Add invariant validation forrequired_propertiesand consider strict/extra-forbid config.At minimum, validate that every entry in
required_propertiesexists inpropertieskeys; 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 selfAlso 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 forheadersfield.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 foroutput_mappingfield.The
output_mappingfield is typed asdict[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 forpriorityfield.The
priorityfield has no validation constraints. If priority values should be non-negative or have a specific range, adding ageconstraint 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 thecontract_versionat 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), notv1.1.0:.... Consider using1.1.0:920b41e8af2fwithout thevprefix 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 expandingenumto support non-string values.JSON Schema allows enums with mixed types (numbers, booleans, null). The current
list[str] | Nonerestricts enums to strings only. If this is intentional for simplicity, consider adding a doc comment clarifying the limitation.
25-29: Consider addingfrom_attributes=Trueto 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=Truein ConfigDict. SinceModelConfigSchemaPropertywill be nested inModelMixinConfigSchema, 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: Redundantvalidate_assignment=Truewithfrozen=True.When
frozen=Trueis set, the model is immutable and assignment is not allowed, makingvalidate_assignment=Trueredundant. Consider removing it for clarity, or if you need assignment validation, removefrozen=Trueinstead.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-levelcontracts/directory, but the example contracts in this PR are underexamples/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: trueexamples/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 handlerscripts/regenerate_fingerprints.py (2)
201-209: Silent exception swallowing may hide validation issues.The
compute_fingerprint_for_contractfunction catchesValueError,TypeError, andModelOnexErrorbut returnsNonewithout 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 NoneAlternatively, 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_versionwith 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
📒 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 - usepoetry runfor all Python commands (pytest, mypy, black, isort, etc.), never use pip or direct python execution
Callsuper().__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
Usecontainer.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 usingpoetry run blackand sort imports usingpoetry run isortbefore committing
Lint code usingpoetry run ruff checkto detect issues and apply auto-fixes withpoetry run ruff check --fix
Files:
src/omnibase_core/models/common/model_mixin_config_schema.pysrc/omnibase_core/models/common/model_request_metadata.pysrc/omnibase_core/models/common/model_config_schema_property.pysrc/omnibase_core/models/common/model_reducer_metadata.pysrc/omnibase_core/models/common/model_node_capabilities_metadata.pysrc/omnibase_core/models/common/model_graph_node_data.pysrc/omnibase_core/models/common/model_intent_payload.pysrc/omnibase_core/models/common/model_operation_data.pysrc/omnibase_core/models/common/model_shutdown_metrics.pysrc/omnibase_core/models/common/model_introspection_custom_metrics.pysrc/omnibase_core/types/typed_dict_maintenance_summary.pysrc/omnibase_core/models/common/model_graph_node_inputs.pysrc/omnibase_core/types/typed_dict_active_summary.pysrc/omnibase_core/models/common/model_custom_health_metrics.pyscripts/regenerate_fingerprints.pysrc/omnibase_core/types/__init__.pysrc/omnibase_core/models/common/model_tool_result_data.pysrc/omnibase_core/models/common/model_event_subscription_config.pysrc/omnibase_core/models/node_metadata/model_node_status_active.pysrc/omnibase_core/models/node_metadata/model_node_status_maintenance.pysrc/omnibase_core/models/common/model_tool_metadata_fields.pysrc/omnibase_core/models/common/model_effect_metadata.pysrc/omnibase_core/models/node_metadata/model_node_status_error.pysrc/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, addfrom_attributes=Trueto 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.pysrc/omnibase_core/models/common/model_request_metadata.pysrc/omnibase_core/models/common/model_config_schema_property.pysrc/omnibase_core/models/common/model_reducer_metadata.pysrc/omnibase_core/models/common/model_node_capabilities_metadata.pysrc/omnibase_core/models/common/model_graph_node_data.pysrc/omnibase_core/models/common/model_intent_payload.pysrc/omnibase_core/models/common/model_operation_data.pysrc/omnibase_core/models/common/model_shutdown_metrics.pysrc/omnibase_core/models/common/model_introspection_custom_metrics.pysrc/omnibase_core/types/typed_dict_maintenance_summary.pysrc/omnibase_core/models/common/model_graph_node_inputs.pysrc/omnibase_core/types/typed_dict_active_summary.pysrc/omnibase_core/models/common/model_custom_health_metrics.pysrc/omnibase_core/types/__init__.pysrc/omnibase_core/models/common/model_tool_result_data.pysrc/omnibase_core/models/common/model_event_subscription_config.pysrc/omnibase_core/models/node_metadata/model_node_status_active.pysrc/omnibase_core/models/node_metadata/model_node_status_maintenance.pysrc/omnibase_core/models/common/model_tool_metadata_fields.pysrc/omnibase_core/models/common/model_effect_metadata.pysrc/omnibase_core/models/node_metadata/model_node_status_error.pysrc/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.pysrc/omnibase_core/models/common/model_node_capabilities_metadata.pysrc/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.pydocs/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_summarymodule. 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
TypedDictActiveSummaryis properly placed and consistent with the module's organization.
146-146: LGTM! Import correctly added.The import for
TypedDictErrorSummaryis properly placed and follows the existing module structure.
174-174: LGTM! Import correctly added.The import for
TypedDictMaintenanceSummaryis 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_suggestionfield usingstr | 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_aggregationoperation includesrollback_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 inscripts/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) andcontract_version(1.1.0) separation reflects the FSM-driven REDUCER design pattern documented indocs/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: Expandedexcluderationale is clear; regex looks correct forprotocols/subtree exclusion.
The added comments make future maintenance safer, and excludingmodel_node_config_value.pyalongside other architectural exceptions is consistent.examples/contracts/orchestrator_data_pipeline.yaml (1)
22-37: Version + fingerprint normalization update is consistent and readable.
Bumpingworkflow_versionto{major: 1, minor: 1, patch: 0}alongside the normalized fingerprint header is cohesive..yaml-validation-allowlist.yaml (1)
43-49: Allowlistingscripts/regenerate_fingerprints.pyis 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 ofmodels/common.
If the codebase expectsextra="forbid"/ otherConfigDictdefaults 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 filecontracts/runtime/contract_loader_effect.yamldoes not exist in the current repository, and no related handler implementations or path validation code could be located. Unable to verify the specific interaction betweendeny_absolute_paths: trueand 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_countis 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(insrc/omnibase_core/models/reducer/model_intent.py) remains the canonical intent structure withpayload: dict[str, Any]. The docstring claimsModelIntentPayload"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 flexibledict[str, Any]pattern, consider either:
- Completing the migration and actually replacing
ModelIntent.payloadwith this typed model, or- Using
JsonValue(already defined injson_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.0andle=1.0constraints 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
geandleconstraints.src/omnibase_core/models/common/model_graph_node_data.py (2)
50-53: LGTM - Excellent use ofConfigDict.This model correctly implements
extra="forbid"andvalidate_assignment=Trueas 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=0to 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_typefield correctly usesField(...)to mark it as required, which is appropriate for event subscription configuration.
34-43: LGTM - Validation constraints are appropriate.The
batch_sizeandtimeout_msfields correctly usege=1andge=0respectively 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_templateuses 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=0for counts,ge=0.0for durations). Field descriptions are clear and the model serves a specific purpose replacingdict[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
Authorizationheader contains${input.payment_api_token}andX-Idempotency-Keycontains 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_strategiessection 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_modelfunction properly handles case-insensitive node types by callingnode_type.upper()at line 173. This correctly handles contracts likekafka_produce.yamlwhich use lowercasenode_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=allwith snappy compression for durability- Activity events:
acks=1with lz4 for high throughput analytics- Audit logs:
acks=allwith no compression prioritizing integrityThis is a well-designed example contract.
| # 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} | ||
|
|
There was a problem hiding this comment.
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.
| # 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.
| parameters: dict[str, str] = Field( | ||
| default_factory=dict, | ||
| description="Query parameters", | ||
| ) |
There was a problem hiding this comment.
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.
| 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.
| envelope_payload: dict[str, str] = Field( | ||
| default_factory=dict, | ||
| description="Event envelope payload data", | ||
| ) |
There was a problem hiding this comment.
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.
| 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.
| 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", | ||
| ) |
There was a problem hiding this comment.
🛠️ 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.
| 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", | ||
| ) |
There was a problem hiding this comment.
🛠️ 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]
🔍 Comprehensive Code Review - PR #180Executive SummaryThis 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
|
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.
There was a problem hiding this comment.
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 matches4 * 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: Thesecurity.path_validationfields in the YAML are unsupported by the schema and will cause validation failure.
ModelFilesystemIOConfigdoes not include asecurityfield. The schema enforcesextra="forbid", which means Pydantic will reject these fields during parsing with a validation error at runtime. Either remove thesecurityblock from the YAML or updateModelFilesystemIOConfigto 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 withvalidate_assignment=Trueandfrom_attributes=True.The past review comment suggested adding
validate_assignment=True, which remains unaddressed. Additionally, per coding guidelines learnings, nested models should includefrom_attributes=Truefor 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=Trueto ConfigDict."contracts/runtime/event_bus_wiring_effect.yaml (1)
35-37: Subscriptionhandlerfields 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[].handlerand 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 -200Also applies to: 211-235
🧹 Nitpick comments (4)
src/omnibase_core/models/common/model_node_capabilities_metadata.py (2)
10-22: Consider addingvalidate_assignment=Trueto ConfigDict.The ConfigDict correctly includes
extra="forbid"andfrom_attributes=True. However, the previous review referenced PYDANTIC_BEST_PRACTICES.md recommendingvalidate_assignment=Truefor 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_urlandsource_repositoryfields are currently plain strings. Using Pydantic'sHttpUrlorAnyUrltypes 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.pyare 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.pathmutation 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-levelsys.path.insert(...).
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 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 - usepoetry runfor all Python commands (pytest, mypy, black, isort, etc.), never use pip or direct python execution
Callsuper().__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
Usecontainer.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 usingpoetry run blackand sort imports usingpoetry run isortbefore committing
Lint code usingpoetry run ruff checkto detect issues and apply auto-fixes withpoetry run ruff check --fix
Files:
src/omnibase_core/models/common/model_typed_metadata.pytests/unit/scripts/test_regenerate_fingerprints.pysrc/omnibase_core/models/common/model_graph_node_inputs.pysrc/omnibase_core/models/core/model_yaml_schema_object.pyscripts/regenerate_fingerprints.pysrc/omnibase_core/models/common/model_node_capabilities_metadata.pysrc/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, addfrom_attributes=Trueto 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.pysrc/omnibase_core/models/common/model_graph_node_inputs.pysrc/omnibase_core/models/core/model_yaml_schema_object.pysrc/omnibase_core/models/common/model_node_capabilities_metadata.pysrc/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.pysrc/omnibase_core/models/core/model_yaml_schema_object.pysrc/omnibase_core/models/common/model_node_capabilities_metadata.pysrc/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 ofdefault_factoryfor list field.The
maintainersfield correctly usesdefault_factory=listto 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_scorefield correctly usesge=0.0andle=1.0constraints 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" fordict[str, str]typing. This pattern is consistently applied throughout the codebase across 500+ model definitions and is explicitly documented in multiple model files (includingModelOperationDatawith the identical note). Thedict[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 withmodel_typed_metadata.pyis 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
ModelEventSubscriptionConfigmodel existing inmodel_typed_metadata.py(lines 689-722). This version includes improved validation (priority hasge=0, le=100constraints), suggesting a deliberate migration or refactoring.To complete this review, clarify:
- Is the duplicate in
model_typed_metadata.pyintentionally 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/EnumCoreErrorCodeinstead of a PydanticValidationError, confirm thisValueErrorpath 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
1when 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_versionandstate_transitions.versiontrack different aspects.
contract_version(1.1.0) reflects the overall contract version and matches the fingerprint prefix.state_transitions.versionandstate_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
| # 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} |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, explore the repository structure
git ls-files | head -30Repository: 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 -20Repository: 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 -10Repository: OmniNode-ai/omnibase_core
Length of output: 94
🏁 Script executed:
# Explore src/omnibase_core structure
find src/omnibase_core -type f -name "*.py" | head -30Repository: OmniNode-ai/omnibase_core
Length of output: 1440
🏁 Script executed:
# Read the node_graph_reducer.yaml file
cat contracts/runtime/node_graph_reducer.yamlRepository: 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 -20Repository: 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 -20Repository: 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 -20Repository: OmniNode-ai/omnibase_core
Length of output: 1260
🏁 Script executed:
# Read FSM execution mixin
cat -n src/omnibase_core/mixins/mixin_fsm_execution.pyRepository: 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.pyRepository: 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.pyRepository: 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 -20Repository: 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 -20Repository: 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 -20Repository: 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 -400Repository: OmniNode-ai/omnibase_core
Length of output: 16641
🏁 Script executed:
# Check comparison operators enum
cat -n src/omnibase_core/enums/enum_comparison_operators.pyRepository: OmniNode-ai/omnibase_core
Length of output: 690
🏁 Script executed:
# Check condition operator enum
cat -n src/omnibase_core/enums/enum_condition_operator.pyRepository: 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 -10Repository: 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 -30Repository: 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 -30Repository: 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.yamlRepository: 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 -20Repository: 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 -20Repository: 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.pyRepository: 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 formatfield operator value. Additionally,is_not_emptyis not in the supported operator whitelist. - Lines 118, 142, 148, 195 (using
equals): The operatorequalsis not inModelFSMTransitionCondition.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_emptywith a supported pattern (e.g.,node_registry != emptyor similar 3-token syntax) - Replace all instances of
equalswith==
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.
| 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' | ||
|
|
There was a problem hiding this comment.
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:
- Prefer top-level
contract_version:(inline and block mapping), - Otherwise handle top-level
version:(inline and block mapping), - 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") |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Add missing ConfigDict options for strict validation and nested usage.
The ConfigDict is incomplete. Based on coding guidelines and learnings:
- Add
validate_assignment=Trueto ensure runtime validation on field assignments - Add
from_attributes=Truesince 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".
| from pydantic import BaseModel, Field, model_validator | ||
|
|
There was a problem hiding this comment.
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".
| 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) | ||
|
|
There was a problem hiding this comment.
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.
| @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 | ||
|
|
There was a problem hiding this comment.
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 NoneCommittable 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.
Code Review - PR #180I'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
|
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.
- 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
* 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
Summary
typed_dict_status_summaries.pyinto 3 separate files for cleaner importsscripts/regenerate_fingerprints.pyutilityPart 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 definitionsmodel_custom_health_metrics.py- Custom health metricsmodel_effect_metadata.py- Effect node metadatamodel_event_subscription_config.py- Event subscription configurationmodel_graph_node_data.py- Graph node data structuresmodel_graph_node_inputs.py- Graph node input definitionsmodel_intent_payload.py- Intent payload modelmodel_introspection_custom_metrics.py- Introspection custom metricsmodel_mixin_config_schema.py- Mixin configuration schemamodel_node_capabilities_metadata.py- Node capabilities metadatamodel_operation_data.py- Operation data structuresmodel_reducer_metadata.py- Reducer node metadatamodel_request_metadata.py- Request metadata modelmodel_shutdown_metrics.py- Shutdown metricsmodel_tool_metadata_fields.py- Tool metadata fieldsmodel_tool_result_data.py- Tool result data structuresTypedDict Refactoring (3 new files, 1 deleted)
typed_dict_status_summaries.pyinto:typed_dict_active_summary.pytyped_dict_error_summary.pytyped_dict_maintenance_summary.pymodel_node_status_*.pyfilesContract Updates (15 files)
Documentation (2 files)
docs/conventions/NAMING_CONVENTIONS.mddocs/conventions/PYDANTIC_BEST_PRACTICES.mdScripts (2 files)
scripts/regenerate_fingerprints.py- Utility for regenerating contract fingerprintsscripts/README.md- Updated documentationTest plan
Related PRs
Summary by CodeRabbit
New Features
New Types
Contract Changes
Documentation
Tests
Chores
✏️ Tip: You can customize this high-level summary in your review settings.