# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/under-what-conditions-must-an-instance-treat-opentelemetry-genai-tool-call-spans-as-non-retryable-evidence-of-side-effects-rather-than-as-retryable-mo.md
# Remnant Warrant:    https://corpusfetch.com/c/under-what-conditions-must-an-instance-treat-opentelemetry-genai-tool-call-spans-as-non-retryable-evidence-of-side-effects-rather-than-as-retryable-mo.warrant.json
# Markdown SHA-256:   151f92b7adf2dbd7bddc8ca92f32fcba13beb013d0e91f0b7fb07eae3064b8bd
# Code AST SHA-256:   50eea999c5c1f3afa53aeff5fb94630066592bba6242ce3a5f2759c0859d9039
# Verified Classes:   ToolSpanCommitmentError, ToolSpan
# Defensive Guards:   2 fail-closed invariants (zero external deps)

from dataclasses import dataclass


class ToolSpanCommitmentError(RuntimeError):
    """Raised when an errored tool span is treated as retryable despite a commitment marker."""


@dataclass
class ToolSpan:
    tool_name: str
    call_id: str | None
    args_complete: bool
    status: str
    idempotent_tool: bool


def classify_retry(span: ToolSpan) -> str:
    if span.status != "ERROR":
        return "no_retry_needed"

    # Malformed proposal: model never produced a valid call, safe to retry.
    if not span.args_complete:
        return "retryable_pre_execution"

    # Complete args means execution was attempted. A call id is a commitment marker.
    if span.call_id and span.idempotent_tool:
        return "retryable_same_call_id"

    if span.call_id and not span.idempotent_tool:
        raise ToolSpanCommitmentError(
            f"tool={span.tool_name} call_id={span.call_id} errored after execution "
            f"with complete args; side effect may have committed. Quarantine, do not replay."
        )

    # Complete args but no call id: cannot prove commitment either way.
    raise ToolSpanCommitmentError(
        f"tool={span.tool_name} errored with complete args but missing call_id; "
        f"commitment state unknown. Quarantine for reconciliation."
    )
