"""Canonical, protocol-neutral execution failure contracts.""" from dataclasses import FrozenInstanceError, fields, is_dataclass import pytest from free_claude_code.core.failures import ( ExecutionFailure, FailureKind, find_execution_failure, ) def test_failure_kind_has_only_protocol_neutral_semantics() -> None: assert tuple(FailureKind) == ( FailureKind.INVALID_REQUEST, FailureKind.AUTHENTICATION, FailureKind.PERMISSION, FailureKind.RATE_LIMIT, FailureKind.OVERLOADED, FailureKind.TIMEOUT, FailureKind.UPSTREAM, FailureKind.UNAVAILABLE, ) assert tuple(kind.value for kind in FailureKind) == ( "invalid_request", "authentication", "permission", "rate_limit", "overloaded", "timeout", "upstream", "unavailable", ) def test_execution_failure_is_the_direct_frozen_slotted_exception() -> None: failure = ExecutionFailure( kind=FailureKind.RATE_LIMIT, status_code=429, message="Provider rate limit reached.", retryable=True, ) assert is_dataclass(failure) assert tuple(field.name for field in fields(failure)) == ( "kind", "status_code", "message", "retryable", ) assert ExecutionFailure.__slots__ == ( "kind", "status_code", "message", "retryable", ) assert str(failure) == "Provider rate limit reached." assert failure.args == ("Provider rate limit reached.",) with pytest.raises(ExecutionFailure) as raised: raise failure assert raised.value is failure with pytest.raises(FrozenInstanceError): failure.status_code = 500 def test_execution_failure_uses_exception_identity_not_value_equality() -> None: first = ExecutionFailure( kind=FailureKind.UPSTREAM, status_code=500, message="same", retryable=True, ) second = ExecutionFailure( kind=FailureKind.UPSTREAM, status_code=500, message="same", retryable=True, ) assert first is not second assert first != second def test_find_execution_failure_recurses_through_nested_groups() -> None: failure = ExecutionFailure( kind=FailureKind.RATE_LIMIT, status_code=429, message="provider is busy", retryable=True, ) grouped = ExceptionGroup( "stream and cleanup failed", [ RuntimeError("cleanup failed"), ExceptionGroup("provider failed", [failure]), ], ) assert find_execution_failure(failure) is failure assert find_execution_failure(grouped) is failure def test_find_execution_failure_leaves_unrelated_groups_unclassified() -> None: grouped = BaseExceptionGroup( "unrelated failures", [RuntimeError("socket closed"), KeyboardInterrupt()], ) assert find_execution_failure(grouped) is None