Skip to content
32 changes: 20 additions & 12 deletions scripts/validation/validate_naming.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,19 +219,27 @@ class NamingConventionValidator:
"merge/": [
"ContractMergeEngine", # Merge engine for typed contract merging (OMN-1127)
],
# REPLAY INFRASTRUCTURE: Effect recording and replay for deterministic testing
# Location: pipeline/replay/ - Replay/recording infrastructure for effects
# Rationale: RecorderEffect records effects for replay, not a Node class.
# The heuristic flags "effect" as a Node indicator, but RecorderEffect
# is a recorder that captures effects, not a node that processes them.
# Similarly, other replay infrastructure classes use descriptive names
# appropriate to their function (ExecutorReplay, InjectorRng, etc.)
# REPLAY INFRASTRUCTURE: Deterministic replay utilities for testing and debugging
# Location: services/replay/ - Replay infrastructure services (injectors/recorders)
# Rationale: These classes provide deterministic replay capabilities (OMN-1116, OMN-1205).
# RecorderEffect, InjectorTime, InjectorRNG are passive observers and injection
# mechanisms - NOT nodes. The heuristic flags "effect" as a Node indicator, but
# RecorderEffect RECORDS effects, it doesn't PERFORM them as a node would.
# Nodes are addressable graph vertices with contracts and dispatch semantics.
# Recorders and injectors are lifecycle-bound utilities for side-effect capture.
"services/replay/": [
"RecorderEffect", # Effect recording for deterministic replay (OMN-1116)
"InjectorTime", # Time injection for deterministic replay (OMN-1116)
"InjectorRNG", # RNG injection for deterministic replay (OMN-1116)
],
# REPLAY INFRASTRUCTURE: Effect replay execution for deterministic testing
# Location: pipeline/replay/ - Replay execution and session management
# Rationale: ExecutorReplay and SessionReplay handle replay execution and session state.
# The heuristic flags "effect" as a Node indicator, but these are replay
# infrastructure classes that EXECUTE replays, not node implementations.
"pipeline/replay/": [
"RecorderEffect", # Effect recorder for deterministic replay (OMN-1116)
"ExecutorReplay", # Replay executor for effect playback
"InjectorRng", # RNG injector for deterministic randomness
"InjectorTime", # Time injector for deterministic timestamps
"SessionReplay", # Replay session manager
"ExecutorReplay", # Replay executor for effect playback (OMN-1116)
"SessionReplay", # Replay session manager (OMN-1116)
],
}

Expand Down
10 changes: 9 additions & 1 deletion src/omnibase_core/enums/replay/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,23 @@
# SPDX-License-Identifier: Apache-2.0
"""Replay infrastructure enums.

This module provides enums for the deterministic replay infrastructure.
This module provides enums for the deterministic replay infrastructure:

- **EnumRecorderMode**: Recording/replaying/pass-through modes for effect recorder
- **EnumReplayMode**: Production/recording/replaying execution modes
- **EnumOverrideInjectionPoint**: Injection points for config overrides (OMN-1205)

.. versionadded:: 0.4.0
"""

from omnibase_core.enums.replay.enum_override_injection_point import (
EnumOverrideInjectionPoint,
)
from omnibase_core.enums.replay.enum_recorder_mode import EnumRecorderMode
from omnibase_core.enums.replay.enum_replay_mode import EnumReplayMode

__all__ = [
"EnumOverrideInjectionPoint",
"EnumRecorderMode",
"EnumReplayMode",
]
55 changes: 55 additions & 0 deletions src/omnibase_core/enums/replay/enum_override_injection_point.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# SPDX-FileCopyrightText: 2025 OmniNode Team <info@omninode.ai>
#
# SPDX-License-Identifier: Apache-2.0
"""EnumOverrideInjectionPoint - Injection points for config overrides.

Defines where configuration overrides can be applied during replay execution.
This is a CLOSED vocabulary - new injection points require explicit addition.

.. versionadded:: 0.4.0
Added Configuration Override Injection (OMN-1205)
"""

from enum import Enum


class EnumOverrideInjectionPoint(str, Enum):
"""Injection points for configuration overrides during replay.

Defines WHERE configuration overrides can be applied during replay
execution. This is a closed vocabulary - new injection points require
explicit addition.

- **HANDLER_CONFIG**: Patch handler configuration model (pre-execution).
Applied before handler execution begins.

- **ENVIRONMENT**: Environment variable overlay (NOT os.environ mutation).
Provides isolated environment context without affecting global state.

- **CONTEXT**: Patch replay context fields (copy only, not original).
Modifies a copy of the context to avoid side effects.

Thread Safety:
Enum values are immutable and thread-safe.

Example:
>>> point = EnumOverrideInjectionPoint.HANDLER_CONFIG
>>> point == "handler_config"
True
>>> EnumOverrideInjectionPoint("environment")
<EnumOverrideInjectionPoint.ENVIRONMENT: 'environment'>

.. versionadded:: 0.4.0
"""

HANDLER_CONFIG = "handler_config"
"""Patch handler configuration model (pre-execution)."""

ENVIRONMENT = "environment"
"""Environment variable overlay (NOT os.environ mutation)."""

CONTEXT = "context"
"""Patch replay context fields (copy only, not original)."""


__all__ = ["EnumOverrideInjectionPoint"]
36 changes: 35 additions & 1 deletion src/omnibase_core/models/replay/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,15 @@

This module provides model definitions for deterministic replay infrastructure:

- **ModelConfigOverride**: Single configuration override with key path and value
- **ModelConfigOverrideSet**: Collection of configuration overrides for replay scenarios
- **ModelConfigOverrideFieldPreview**: Preview of a single field change from override
- **ModelConfigOverridePreview**: Complete preview of all changes from applying overrides
- **ModelConfigOverrideResult**: Result of applying configuration overrides
- **ModelConfigOverrideValidation**: Validation result for configuration overrides
- **ModelEffectRecord**: Captured effect intent and result pair for replay
- **ModelReplayContext**: Determinism context bundling time, RNG seed, and effect records
- **ModelReplayInput**: Input configuration for replay execution
- **ModelExecutionCorpus**: Collection of execution manifests for replay testing
- **ModelCorpusStatistics**: Computed statistics for an execution corpus
- **ModelCorpusTimeRange**: Time range for corpus executions
Expand Down Expand Up @@ -48,13 +55,30 @@
.. versionadded:: 0.4.0
Added Replay Infrastructure (OMN-1116)

.. versionadded:: 0.4.0
Added Configuration Override Models (OMN-1205)

.. versionadded:: 0.4.0
Added Execution Corpus Model (OMN-1202)
"""

from omnibase_core.models.manifest.model_execution_manifest import (
ModelExecutionManifest,
)
from omnibase_core.models.replay.model_config_override import ModelConfigOverride
from omnibase_core.models.replay.model_config_override_field_preview import (
ModelConfigOverrideFieldPreview,
)
from omnibase_core.models.replay.model_config_override_preview import (
ModelConfigOverridePreview,
)
from omnibase_core.models.replay.model_config_override_result import (
ModelConfigOverrideResult,
)
from omnibase_core.models.replay.model_config_override_set import ModelConfigOverrideSet
from omnibase_core.models.replay.model_config_override_validation import (
ModelConfigOverrideValidation,
)
from omnibase_core.models.replay.model_corpus_capture_window import (
ModelCorpusCaptureWindow,
)
Expand All @@ -63,15 +87,25 @@
from omnibase_core.models.replay.model_effect_record import ModelEffectRecord
from omnibase_core.models.replay.model_execution_corpus import ModelExecutionCorpus
from omnibase_core.models.replay.model_replay_context import ModelReplayContext
from omnibase_core.models.replay.model_replay_input import ModelReplayInput

__all__ = [
# Replay models
# Configuration override models
"ModelConfigOverride",
"ModelConfigOverrideFieldPreview",
"ModelConfigOverridePreview",
"ModelConfigOverrideResult",
"ModelConfigOverrideSet",
"ModelConfigOverrideValidation",
# Corpus models
"ModelCorpusCaptureWindow",
"ModelCorpusStatistics",
"ModelCorpusTimeRange",
# Replay models
"ModelEffectRecord",
"ModelExecutionCorpus",
"ModelReplayContext",
"ModelReplayInput",
# Related models re-exported for convenience
"ModelExecutionManifest",
]
60 changes: 60 additions & 0 deletions src/omnibase_core/models/replay/model_config_override.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# SPDX-FileCopyrightText: 2025 OmniNode Team <info@omninode.ai>
#
# SPDX-License-Identifier: Apache-2.0
"""
Single configuration override specification for replay injection.

.. versionadded:: 0.4.0
Added Configuration Override Injection (OMN-1205)
"""

from typing import Any

from pydantic import BaseModel, ConfigDict, Field

from omnibase_core.enums.replay.enum_override_injection_point import (
EnumOverrideInjectionPoint,
)

__all__ = ["ModelConfigOverride"]


class ModelConfigOverride(BaseModel):
"""
A single configuration override specification.

Attributes:
path: Dot-separated path to the config field (e.g., "llm.openai.temperature").
value: The new value to set at this path.
injection_point: Where to apply this override (handler_config, environment, context).

Thread Safety:
Immutable (frozen=True) after creation - thread-safe for concurrent reads.

Example:
>>> override = ModelConfigOverride(
... path="llm.temperature",
... value=0.7,
... injection_point=EnumOverrideInjectionPoint.HANDLER_CONFIG,
... )
"""

# from_attributes=True: Enables construction from ORM/dataclass instances
# and ensures pytest-xdist compatibility across worker processes where
# class identity may differ due to independent imports.
# See CLAUDE.md "Pydantic from_attributes=True for Value Objects".
model_config = ConfigDict(frozen=True, extra="forbid", from_attributes=True)

path: str = Field(
...,
min_length=1,
description="Dot-separated path to the config field",
)
value: Any = Field(
...,
description="The new value to set at this path",
)
injection_point: EnumOverrideInjectionPoint = Field(
default=EnumOverrideInjectionPoint.HANDLER_CONFIG,
description="Where to apply this override",
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# SPDX-FileCopyrightText: 2025 OmniNode Team <info@omninode.ai>
#
# SPDX-License-Identifier: Apache-2.0
"""
Single field preview showing before/after state for one config override.

.. versionadded:: 0.4.0
Added Configuration Override Injection (OMN-1205)
"""

from typing import Any

from pydantic import BaseModel, ConfigDict, Field

from omnibase_core.enums.replay.enum_override_injection_point import (
EnumOverrideInjectionPoint,
)

__all__ = ["ModelConfigOverrideFieldPreview"]


class ModelConfigOverrideFieldPreview(BaseModel):
"""
Single field preview showing before/after for one override.

Represents the state change for a single configuration field when an
override is applied. Used for dry-run preview and user confirmation.

Attributes:
path: Dot-separated path to the field (e.g., "retry.max_attempts").
injection_point: Where this override will be applied in the pipeline.
old_value: Value before override (or MISSING sentinel for new fields).
new_value: Value after override.
value_type: Type of the new value (for display purposes).
path_exists: Whether the path exists in the original configuration.

Thread Safety:
Immutable (frozen=True) after creation - thread-safe for concurrent reads.

Example:
>>> preview = ModelConfigOverrideFieldPreview(
... path="timeout",
... injection_point=EnumOverrideInjectionPoint.HANDLER_CONFIG,
... old_value=30,
... new_value=60,
... value_type="int",
... path_exists=True,
... )
>>> preview.to_markdown_row()
'| timeout | handler_config | `30` | `60` | exists |'

.. versionadded:: 0.4.0
"""

# from_attributes=True: Enables construction from ORM/dataclass instances
# and ensures pytest-xdist compatibility across worker processes where
# class identity may differ due to independent imports.
# See CLAUDE.md "Pydantic from_attributes=True for Value Objects".
model_config = ConfigDict(frozen=True, extra="forbid", from_attributes=True)

path: str = Field(..., description="Dot-separated path to the field")
injection_point: EnumOverrideInjectionPoint = Field(
..., description="Where this override will be applied"
)
old_value: Any = Field(
..., description="Value before override (or MISSING sentinel)"
)
new_value: Any = Field(..., description="Value after override")
value_type: str = Field(default="unknown", description="Type of the new value")
path_exists: bool = Field(
default=True, description="Whether the path exists in original"
)

def to_markdown_row(self) -> str:
"""Generate markdown table row for this preview.

Creates a formatted markdown table row showing the field path,
injection point, before/after values, and existence status.

Returns:
A markdown table row string with pipe delimiters.
"""
old_str = self._format_value(self.old_value)
new_str = self._format_value(self.new_value)
status = "exists" if self.path_exists else "NEW"
return f"| {self.path} | {self.injection_point.value} | {old_str} | {new_str} | {status} |"

def _format_value(self, value: Any) -> str:
"""Format value for markdown display.

Wraps values in backticks for code formatting. Handles None
specially as `null` and strings with quotes.

Args:
value: The value to format.

Returns:
A markdown-formatted string representation of the value.
"""
if value is None:
return "`null`"
if isinstance(value, str):
return f'`"{value}"`'
return f"`{value}`"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Loading