"""Step definitions for Plan v3 domain model tests."""

from behave import given, then, when
from behave.runner import Context
from pydantic import ValidationError

from cleveragents.domain.models.core.plan import (
    AutomationProfileProvenance,
    AutomationProfileRef,
    InvariantSource,
    NamespacedName,
    Plan,
    PlanIdentity,
    PlanInvariant,
    PlanPhase,
    ProcessingState,
    ProjectLink,
    can_transition,
)

# NamespacedName Steps


@when('I parse the namespaced name "{full_name}"')
def step_parse_namespaced_name(context: Context, full_name: str) -> None:
    """Parse a full namespaced name string."""
    context.namespaced_name = NamespacedName.parse(full_name)


@then('the parsed namespace should be "{expected}"')
def step_check_namespace(context: Context, expected: str) -> None:
    """Check the namespace matches expected value."""
    assert context.namespaced_name.namespace == expected, (
        f"Expected namespace '{expected}', got '{context.namespaced_name.namespace}'"
    )


@then('the parsed item name should be "{expected}"')
def step_check_name(context: Context, expected: str) -> None:
    """Check the name matches expected value."""
    assert context.namespaced_name.name == expected, (
        f"Expected name '{expected}', got '{context.namespaced_name.name}'"
    )


@then("the parsed server should be empty")
def step_check_server_empty(context: Context) -> None:
    """Check the server is None."""
    assert context.namespaced_name.server is None, (
        f"Expected server to be None, got '{context.namespaced_name.server}'"
    )


@then('the parsed server should be "{expected}"')
def step_check_server(context: Context, expected: str) -> None:
    """Check the server matches expected value."""
    assert context.namespaced_name.server == expected, (
        f"Expected server '{expected}', got '{context.namespaced_name.server}'"
    )


@given(
    'I have a namespaced name with server "{server}" namespace "{namespace}" and name "{name}"'
)
def step_create_namespaced_name_with_server(
    context: Context, server: str, namespace: str, name: str
) -> None:
    """Create a namespaced name with all components."""
    context.namespaced_name = NamespacedName(
        server=server, namespace=namespace, name=name
    )


@given('I have a namespaced name with namespace "{namespace}" and name "{name}"')
def step_create_namespaced_name_without_server(
    context: Context, namespace: str, name: str
) -> None:
    """Create a namespaced name without server."""
    context.namespaced_name = NamespacedName(
        server=None, namespace=namespace, name=name
    )


@given('I create a namespaced name with an empty namespace and name "{name}"')
def step_create_namespaced_name_empty_namespace(context: Context, name: str) -> None:
    """Create a namespaced name with an empty namespace."""
    context.namespaced_name = NamespacedName(server=None, namespace="", name=name)


@then('the namespaced string representation should be "{expected}"')
def step_check_string_representation(context: Context, expected: str) -> None:
    """Check the string representation matches expected."""
    result = str(context.namespaced_name)
    assert result == expected, f"Expected '{expected}', got '{result}'"


@when(
    'I try to create a namespaced name with namespace "{namespace}" and name "{name}"'
)
def step_try_create_invalid_namespaced_name(
    context: Context, namespace: str, name: str
) -> None:
    """Attempt to create a namespaced name that might fail validation."""
    context.error = None
    try:
        context.namespaced_name = NamespacedName(
            server=None, namespace=namespace, name=name
        )
    except ValidationError as e:
        context.error = e


# Note: "a validation error should be raised" step is defined in domain_models_steps.py


# PlanPhase Steps


@then('the plan phases should be in order "{expected_order}"')
def step_check_phase_order(context: Context, expected_order: str) -> None:
    """Verify that phases are in the expected order."""
    expected_phases = [p.strip() for p in expected_order.split(",")]
    actual_phases = [phase.value for phase in PlanPhase]
    assert actual_phases == expected_phases, (
        f"Expected phases {expected_phases}, got {actual_phases}"
    )


# Plan Creation Steps


def _default_plan(
    *,
    identity: PlanIdentity | None = None,
    namespaced_name: NamespacedName | None = None,
    description: str = "Test plan description",
    definition_of_done: str | None = None,
    action_name: str = "local/test-action",
    phase: PlanPhase = PlanPhase.STRATEGIZE,
    processing_state: ProcessingState = ProcessingState.QUEUED,
    strategy_actor: str | None = None,
    execution_actor: str | None = None,
    created_by: str | None = None,
    reusable: bool = True,
    read_only: bool = False,
    error_message: str | None = None,
) -> Plan:
    """Helper to create a Plan with sensible defaults for testing.

    All plans require ``action_name`` and start in STRATEGIZE phase.
    """
    if identity is None:
        identity = PlanIdentity(plan_id="01ARZ3NDEKTSV4RRFFQ69G5FAV")
    if namespaced_name is None:
        namespaced_name = NamespacedName(
            server=None, namespace="local", name="test-plan"
        )
    return Plan(
        identity=identity,
        namespaced_name=namespaced_name,
        description=description,
        definition_of_done=definition_of_done,
        action_name=action_name,
        phase=phase,
        processing_state=processing_state,
        strategy_actor=strategy_actor,
        execution_actor=execution_actor,
        created_by=created_by,
        reusable=reusable,
        read_only=read_only,
        error_message=error_message,
    )


@given("I create a new plan")
def step_create_new_plan(context: Context) -> None:
    """Create a new plan with default values."""
    context.plan = _default_plan()


@given('I create a new plan with description "{description}"')
def step_create_plan_with_description(context: Context, description: str) -> None:
    """Create a new plan with specific description."""
    context.plan = _default_plan(description=description)


@given("I create a plan in strategize phase")
def step_create_plan_strategize_phase(context: Context) -> None:
    """Create a plan in STRATEGIZE phase."""
    context.plan = _default_plan(
        phase=PlanPhase.STRATEGIZE,
        processing_state=ProcessingState.QUEUED,
    )


@given(
    "I create a plan in strategize phase with action state set and no processing state"
)
def step_create_plan_strategize_with_action_state(context: Context) -> None:
    """Create a plan in STRATEGIZE phase with QUEUED state."""
    context.plan = _default_plan(
        phase=PlanPhase.STRATEGIZE,
        processing_state=ProcessingState.QUEUED,
    )


@given("I create a plan in strategize phase with errored state")
def step_create_plan_strategize_errored(context: Context) -> None:
    """Create a plan in STRATEGIZE phase with ERRORED state."""
    context.plan = _default_plan(
        phase=PlanPhase.STRATEGIZE,
        processing_state=ProcessingState.ERRORED,
        error_message="Test error",
    )


@given("I create a plan in strategize phase with processing state")
def step_create_plan_strategize_processing(context: Context) -> None:
    """Create a plan in STRATEGIZE phase with PROCESSING state."""
    context.plan = _default_plan(
        phase=PlanPhase.STRATEGIZE,
        processing_state=ProcessingState.PROCESSING,
    )


@given("I create a plan in applied phase")
def step_create_plan_applied_phase(context: Context) -> None:
    """Create a plan in APPLY phase with APPLIED processing state (terminal)."""
    context.plan = _default_plan(
        phase=PlanPhase.APPLY,
        processing_state=ProcessingState.APPLIED,
    )


@given("I create a plan in apply phase as terminal")
def step_create_plan_apply_terminal(context: Context) -> None:
    """Create a plan in APPLY phase with APPLIED processing state (terminal)."""
    context.plan = _default_plan(
        phase=PlanPhase.APPLY,
        processing_state=ProcessingState.APPLIED,
    )


@given("I create a new plan in action phase")
def step_create_plan_action_phase(context: Context) -> None:
    """Create a plan in STRATEGIZE phase (formerly ACTION phase)."""
    context.plan = _default_plan(
        phase=PlanPhase.STRATEGIZE,
        processing_state=ProcessingState.QUEUED,
    )


@given("I create a plan in action phase without action state")
def step_create_plan_action_without_state(context: Context) -> None:
    """Create a plan in STRATEGIZE phase without explicit state."""
    context.plan = _default_plan(
        phase=PlanPhase.STRATEGIZE,
        processing_state=ProcessingState.QUEUED,
    )


@given("I create a plan in action phase with available state")
def step_create_plan_action_available(context: Context) -> None:
    """Create a plan in STRATEGIZE phase with COMPLETE state (can transition)."""
    context.plan = _default_plan(
        phase=PlanPhase.STRATEGIZE,
        processing_state=ProcessingState.COMPLETE,
    )


@given("I create a plan in strategize phase with cancelled state")
def step_create_plan_strategize_cancelled(context: Context) -> None:
    """Create a plan in STRATEGIZE phase with CANCELLED processing state."""
    context.plan = _default_plan(
        phase=PlanPhase.STRATEGIZE,
        processing_state=ProcessingState.CANCELLED,
    )


@given("I create a plan in action phase with archived state")
def step_create_plan_action_archived(context: Context) -> None:
    """Create a plan in APPLY phase with APPLIED state (terminal, formerly ACTION/ARCHIVED)."""
    context.plan = _default_plan(
        phase=PlanPhase.APPLY,
        processing_state=ProcessingState.APPLIED,
    )


@given("I create a plan in execute phase with complete processing state")
def step_create_plan_execute_complete(context: Context) -> None:
    """Create a plan in EXECUTE phase with COMPLETE processing_state."""
    context.plan = _default_plan(
        phase=PlanPhase.EXECUTE,
        processing_state=ProcessingState.COMPLETE,
    )


@given("I create a plan with an unknown phase value")
def step_create_plan_unknown_phase(context: Context) -> None:
    """Create a plan with a phase outside the enum."""
    context.plan = Plan.model_construct(
        identity=PlanIdentity(plan_id="01ARZ3NDEKTSV4RRFFQ69G5FAV"),
        namespaced_name=NamespacedName(
            server=None, namespace="local", name="test-plan"
        ),
        description="Test plan",
        action_name="local/test-action",
        phase="mystery",
        processing_state=None,
    )


# Plan State Checks


@then('the plan phase should be "{expected}"')
def step_check_plan_phase(context: Context, expected: str) -> None:
    """Check the plan phase matches expected."""
    actual = context.plan.phase.value
    assert actual == expected, f"Expected phase '{expected}', got '{actual}'"


@then('the plan state should be "{expected}"')
def step_check_plan_state(context: Context, expected: str) -> None:
    """Check the derived plan state matches expected."""
    state = context.plan.state
    actual = state.value
    assert actual == expected, f"Expected plan state '{expected}', got '{actual}'"


@then('the plan processing state should be "{expected}"')
def step_check_processing_state(context: Context, expected: str) -> None:
    """Check the plan state (formerly processing_state, now unified state)."""
    assert context.plan.state is not None, "State is None"
    actual = context.plan.state.value
    assert actual == expected, f"Expected state '{expected}', got '{actual}'"


@then("the plan processing state should be empty")
def step_check_processing_state_empty(context: Context) -> None:
    """Processing state no longer exists as separate field; assert state is present."""
    assert context.plan.state is not None, "Expected state to exist on plan"


@then("the plan should not be terminal")
def step_check_plan_not_terminal(context: Context) -> None:
    """Check the plan is not in a terminal state."""
    assert not context.plan.is_terminal, "Expected plan to not be terminal"


@then("the plan should be terminal")
def step_check_plan_terminal(context: Context) -> None:
    """Check the plan is in a terminal state."""
    assert context.plan.is_terminal, "Expected plan to be terminal"


@then("the plan should be errored")
def step_check_plan_errored(context: Context) -> None:
    """Check the plan is in an errored state."""
    assert context.plan.is_errored, "Expected plan to be errored"


@then("the plan should not be errored")
def step_check_plan_not_errored(context: Context) -> None:
    """Check the plan is not in an errored state."""
    assert not context.plan.is_errored, "Expected plan to not be errored"


@then("the plan can transition to next phase")
def step_check_plan_can_transition(context: Context) -> None:
    """Check the plan can transition to the next phase."""
    assert context.plan.can_transition_to_next_phase, (
        "Expected plan to be able to transition to next phase"
    )


@then("the plan cannot transition to next phase")
def step_check_plan_cannot_transition(context: Context) -> None:
    """Check the plan cannot transition to the next phase."""
    assert not context.plan.can_transition_to_next_phase, (
        "Expected plan to not be able to transition to next phase"
    )


@then('the next phase should be "{expected}"')
def step_check_next_phase(context: Context, expected: str) -> None:
    """Check the next phase matches expected."""
    next_phase = context.plan.get_next_phase()
    assert next_phase is not None, "Expected next phase to exist"
    assert next_phase.value == expected, (
        f"Expected next phase '{expected}', got '{next_phase.value}'"
    )


@then("the next phase should be empty")
def step_check_next_phase_empty(context: Context) -> None:
    """Check there is no next phase."""
    next_phase = context.plan.get_next_phase()
    assert next_phase is None, f"Expected no next phase, got '{next_phase}'"


# Plan Identity Steps


@when('I try to create a plan identity with invalid ULID "{ulid}"')
def step_try_create_invalid_identity(context: Context, ulid: str) -> None:
    """Attempt to create a plan identity with invalid ULID."""
    context.error = None
    try:
        context.plan_identity = PlanIdentity(plan_id=ulid)
    except ValidationError as e:
        context.error = e


@when('I create a plan identity with ULID "{ulid}"')
def step_create_valid_identity(context: Context, ulid: str) -> None:
    """Create a plan identity with valid ULID."""
    context.error = None
    try:
        context.plan_identity = PlanIdentity(plan_id=ulid)
    except ValidationError as e:
        context.error = e


@then("the plan identity should be valid")
def step_check_identity_valid(context: Context) -> None:
    """Verify that the plan identity was created successfully."""
    assert context.error is None, f"Expected no validation error, got: {context.error}"
    assert context.plan_identity is not None, "Expected plan identity to exist"


@when('I create a plan identity with parent "{parent}" and root "{root}"')
def step_create_identity_with_hierarchy(
    context: Context, parent: str, root: str
) -> None:
    """Create a plan identity with parent and root plan IDs."""
    context.plan_identity = PlanIdentity(
        plan_id="01ARZ3NDEKTSV4RRFFQ69G5FAX",
        parent_plan_id=parent,
        root_plan_id=root,
    )


@then('the parent plan ID should be "{expected}"')
def step_check_parent_plan_id(context: Context, expected: str) -> None:
    """Check the parent plan ID matches expected."""
    assert context.plan_identity.parent_plan_id == expected, (
        f"Expected parent '{expected}', got '{context.plan_identity.parent_plan_id}'"
    )


@then('the root plan ID should be "{expected}"')
def step_check_root_plan_id(context: Context, expected: str) -> None:
    """Check the root plan ID matches expected."""
    assert context.plan_identity.root_plan_id == expected, (
        f"Expected root '{expected}', got '{context.plan_identity.root_plan_id}'"
    )


# Phase Transition Steps


@then('transition from "{from_phase}" to "{to_phase}" should be valid')
def step_check_valid_transition(
    context: Context, from_phase: str, to_phase: str
) -> None:
    """Check that a phase transition is valid."""
    from_p = PlanPhase(from_phase)
    to_p = PlanPhase(to_phase)
    assert can_transition(from_p, to_p), (
        f"Expected transition from {from_phase} to {to_phase} to be valid"
    )


@then('transition from "{from_phase}" to "{to_phase}" should be invalid')
def step_check_invalid_transition(
    context: Context, from_phase: str, to_phase: str
) -> None:
    """Check that a phase transition is invalid."""
    from_p = PlanPhase(from_phase)
    to_p = PlanPhase(to_phase)
    assert not can_transition(from_p, to_p), (
        f"Expected transition from {from_phase} to {to_phase} to be invalid"
    )


# Invalid Plan Creation Steps


@when("I try to create a plan without description")
def step_try_create_plan_without_description(context: Context) -> None:
    """Attempt to create a plan without description."""
    context.error = None
    try:
        context.plan = Plan.model_validate(
            {
                "identity": PlanIdentity(plan_id="01ARZ3NDEKTSV4RRFFQ69G5FAV"),
                "namespaced_name": NamespacedName(
                    server=None, namespace="local", name="test-plan"
                ),
                "action_name": "local/test-action",
                "definition_of_done": None,
                "phase": PlanPhase.STRATEGIZE,
                "processing_state": ProcessingState.QUEUED,
                "strategy_actor": None,
                "execution_actor": None,
                "created_by": None,
                "reusable": True,
                "read_only": False,
            }
        )
    except ValidationError as e:
        context.error = e


@when("I try to create a plan with invalid phase value")
def step_try_create_plan_with_invalid_phase(context: Context) -> None:
    """Test that creating a plan with an invalid phase value raises ValidationError."""
    context.error = None
    try:
        context.plan = Plan(
            identity=PlanIdentity(plan_id="01ARZ3NDEKTSV4RRFFQ69G5FAV"),
            namespaced_name=NamespacedName(
                server=None, namespace="local", name="test-plan"
            ),
            description="Test plan",
            action_name="local/test-action",
            definition_of_done=None,
            phase="nonexistent",  # Invalid phase value
            processing_state=ProcessingState.QUEUED,
            strategy_actor=None,
            execution_actor=None,
            created_by=None,
            reusable=True,
            read_only=False,
        )
    except ValidationError as e:
        context.error = e


@when("I try to create a plan with empty description")
def step_try_create_plan_empty_description(context: Context) -> None:
    """Attempt to create a plan with empty description."""
    context.error = None
    try:
        context.plan = Plan(
            identity=PlanIdentity(plan_id="01ARZ3NDEKTSV4RRFFQ69G5FAV"),
            namespaced_name=NamespacedName(
                server=None, namespace="local", name="test-plan"
            ),
            description="",
            action_name="local/test-action",
            definition_of_done=None,
            phase=PlanPhase.STRATEGIZE,
            processing_state=ProcessingState.QUEUED,
            strategy_actor=None,
            execution_actor=None,
            created_by=None,
            reusable=True,
            read_only=False,
        )
    except ValidationError as e:
        context.error = e


# Automation Profile Provenance Steps


@given('I create a plan with automation profile "{profile_name}"')
def step_create_plan_with_automation_profile(
    context: Context, profile_name: str
) -> None:
    """Create a plan with an automation profile name set."""
    context.plan = Plan(
        identity=PlanIdentity(plan_id="01ARZ3NDEKTSV4RRFFQ69G5FAV"),
        namespaced_name=NamespacedName(
            server=None, namespace="local", name="test-plan"
        ),
        description="Plan with automation profile",
        action_name="local/test-action",
        definition_of_done=None,
        phase=PlanPhase.STRATEGIZE,
        processing_state=ProcessingState.QUEUED,
        automation_profile=AutomationProfileRef(
            profile_name=profile_name,
            provenance=AutomationProfileProvenance.PLAN,
        ),
        strategy_actor=None,
        execution_actor=None,
        created_by=None,
        reusable=True,
        read_only=False,
    )


@given("I create a plan with automation profile and snapshot")
def step_create_plan_with_profile_snapshot(context: Context) -> None:
    """Create a plan with automation profile."""
    context.plan = Plan(
        identity=PlanIdentity(plan_id="01ARZ3NDEKTSV4RRFFQ69G5FAV"),
        namespaced_name=NamespacedName(
            server=None, namespace="local", name="test-plan"
        ),
        description="Plan with profile snapshot",
        action_name="local/test-action",
        definition_of_done=None,
        phase=PlanPhase.STRATEGIZE,
        processing_state=ProcessingState.QUEUED,
        automation_profile=AutomationProfileRef(
            profile_name="org/high-trust-profile",
            provenance=AutomationProfileProvenance.ACTION,
        ),
        strategy_actor=None,
        execution_actor=None,
        created_by=None,
        reusable=True,
        read_only=False,
    )


@then('the plan automation profile name should be "{expected}"')
def step_check_automation_profile_name(context: Context, expected: str) -> None:
    """Check the plan automation profile name."""
    assert context.plan.automation_profile is not None, "Expected profile to be set"
    assert context.plan.automation_profile.profile_name == expected, (
        f"Expected profile '{expected}', got '{context.plan.automation_profile.profile_name}'"
    )


@then('the plan model automation level should be "{expected}"')
def step_check_automation_level(context: Context, expected: str) -> None:
    """Check the plan automation profile (automation_level removed)."""
    # automation_level field was removed; verify via profile instead
    if context.plan.automation_profile is not None:
        actual = context.plan.automation_profile.profile_name
    else:
        actual = "manual"
    # Map old level values to profile names for backward compat
    level_to_profile = {
        "manual": "manual",
        "review_before_apply": "auto",
        "full_automation": "full-auto",
    }
    expected_profile = level_to_profile.get(expected, expected)
    assert actual == expected_profile, (
        f"Expected profile '{expected_profile}', got '{actual}'"
    )


@then('the plan effective profile snapshot should contain "{key}"')
def step_check_profile_snapshot_key(context: Context, key: str) -> None:
    """Check the automation profile has expected provenance."""
    assert context.plan.automation_profile is not None, "Expected profile to be set"
    # Profile snapshot is no longer separate; check provenance instead
    assert context.plan.automation_profile.provenance is not None


@then("the automation profile should be immutable after creation")
def step_check_profile_immutable(context: Context) -> None:
    """Verify the profile exists and is set."""
    assert context.plan.automation_profile is not None, "Expected profile to be set"


# Invariant Ordering Steps


@given("I create a plan with ordered invariants")
def step_create_plan_with_invariants(context: Context) -> None:
    """Create a plan with invariants in specific order."""
    context.plan = Plan(
        identity=PlanIdentity(plan_id="01ARZ3NDEKTSV4RRFFQ69G5FAV"),
        namespaced_name=NamespacedName(
            server=None, namespace="local", name="test-plan"
        ),
        description="Plan with invariants",
        action_name="local/test-action",
        definition_of_done=None,
        phase=PlanPhase.STRATEGIZE,
        processing_state=ProcessingState.QUEUED,
        invariants=[
            PlanInvariant(
                text="Global rule",
                source=InvariantSource.GLOBAL,
            ),
            PlanInvariant(
                text="Project rule",
                source=InvariantSource.PROJECT,
            ),
            PlanInvariant(
                text="Plan rule",
                source=InvariantSource.PLAN,
            ),
        ],
        strategy_actor=None,
        execution_actor=None,
        created_by=None,
        reusable=True,
        read_only=False,
    )


@then('the invariant at index {index:d} should have text "{expected}"')
def step_check_invariant_text(context: Context, index: int, expected: str) -> None:
    """Check invariant text at given index."""
    invariants = context.plan.invariants
    assert index < len(invariants), (
        f"Index {index} out of range (have {len(invariants)} invariants)"
    )
    actual = invariants[index].text
    assert actual == expected, (
        f"Expected text '{expected}' at index {index}, got '{actual}'"
    )


@then('the invariant at index {index:d} should have scope "{expected}"')
def step_check_invariant_scope(context: Context, index: int, expected: str) -> None:
    """Check invariant scope at given index."""
    invariants = context.plan.invariants
    assert index < len(invariants), (
        f"Index {index} out of range (have {len(invariants)} invariants)"
    )
    actual = invariants[index].source.value
    assert actual == expected, (
        f"Expected scope '{expected}' at index {index}, got '{actual}'"
    )


@when("I try to create a plan invariant with empty text")
def step_try_create_invariant_empty_text(context: Context) -> None:
    """Attempt to create an invariant with empty text."""
    context.error = None
    try:
        PlanInvariant(text="", source=InvariantSource.GLOBAL)
    except ValidationError as e:
        context.error = e


# Fully Populated Plan for CLI Dict Testing


@given("I create a fully populated plan for cli dict testing")
def step_create_fully_populated_plan(context: Context) -> None:
    """Create a plan with all optional fields populated."""
    context.plan = Plan(
        identity=PlanIdentity(
            plan_id="01ARZ3NDEKTSV4RRFFQ69G5FAV",
            parent_plan_id="01ARZ3NDEKTSV4RRFFQ69G5FAW",
            root_plan_id="01ARZ3NDEKTSV4RRFFQ69G5FAX",
            attempt=3,
        ),
        namespaced_name=NamespacedName(
            server=None, namespace="local", name="full-plan"
        ),
        description="Fully populated plan",
        action_name="local/full-action",
        definition_of_done="All features complete",
        phase=PlanPhase.EXECUTE,
        processing_state=ProcessingState.PROCESSING,
        automation_profile=AutomationProfileRef(
            profile_name="org/full-profile",
            provenance=AutomationProfileProvenance.ACTION,
        ),
        strategy_actor="openai/gpt-4",
        execution_actor="openai/gpt-4",
        estimation_actor="openai/gpt-4-turbo",
        invariant_actor="openai/gpt-4-turbo",
        arguments={"target": "/src", "mode": "strict"},
        arguments_order=["target", "mode"],
        invariants=[
            PlanInvariant(
                text="Keep it safe",
                source=InvariantSource.GLOBAL,
            ),
        ],
        project_links=[
            ProjectLink(project_name="local/proj"),
        ],
        changeset_id="01ARZ3NDEKTSV4RRFFQ69G5FAY",
        sandbox_refs=["sandbox-001"],
        error_message="Partial failure in step 3",
        error_details={"step": 3, "reason": "timeout"},
        tags=["critical", "v2"],
        created_by="test-user",
        reusable=True,
        read_only=False,
    )
