"""Canonical execution failures and their protocol-owned wire mappings.""" import pytest from free_claude_code.core.anthropic.errors import ( anthropic_error_type_for_failure, anthropic_failure_payload, ) from free_claude_code.core.failures import ExecutionFailure, FailureKind from free_claude_code.core.openai_responses.errors import ( openai_error_type_for_failure, openai_failure_payload, ) @pytest.mark.parametrize( ("kind", "anthropic_type", "openai_type"), [ (FailureKind.INVALID_REQUEST, "invalid_request_error", "invalid_request_error"), (FailureKind.AUTHENTICATION, "authentication_error", "authentication_error"), (FailureKind.PERMISSION, "permission_error", "permission_error"), (FailureKind.RATE_LIMIT, "rate_limit_error", "rate_limit_error"), (FailureKind.OVERLOADED, "overloaded_error", "overloaded_error"), # Existing finalized transport timeouts are exposed as api_error; the # semantic kind becomes more precise without changing that wire contract. (FailureKind.TIMEOUT, "api_error", "api_error"), (FailureKind.UPSTREAM, "api_error", "api_error"), (FailureKind.UNAVAILABLE, "api_error", "api_error"), ], ) def test_each_protocol_owns_failure_kind_to_wire_type_mapping( kind: FailureKind, anthropic_type: str, openai_type: str, ) -> None: assert anthropic_error_type_for_failure(kind) == anthropic_type assert openai_error_type_for_failure(kind) == openai_type def test_finalized_status_502_timeout_keeps_existing_api_error_wire_type() -> None: failure = ExecutionFailure( kind=FailureKind.TIMEOUT, status_code=502, message="Provider request timed out.", retryable=True, ) assert anthropic_failure_payload(failure)["error"]["type"] == "api_error" assert openai_failure_payload(failure)["error"]["type"] == "api_error"