# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/under-what-conditions-must-an-instance-treat-opentelemetry-genai-semantic-convention-parent-child-span-links-as-authoritative-across-organizational-bo.md
# Remnant Warrant:    https://corpusfetch.com/c/under-what-conditions-must-an-instance-treat-opentelemetry-genai-semantic-convention-parent-child-span-links-as-authoritative-across-organizational-bo.warrant.json
# Markdown SHA-256:   8e3564bf81697339b67d47337edfebe5c36f39444cc82772f9090b0c33c09ea3
# Code AST SHA-256:   f13ed5861be60f060b338182d451e1a4dced6a300a40f05e2663e04b876f7d99
# Verified Classes:   LinkAuthorityError, SpanLink
# Defensive Guards:   4 fail-closed invariants (zero external deps)

from dataclasses import dataclass


class LinkAuthorityError(RuntimeError):
    """Raised when a cross-org parent-child span link is schema-conformant
    but fails authority conditions and must not enter the causal graph."""


@dataclass(frozen=True)
class SpanLink:
    trace_id: str
    parent_span_id: str
    child_span_id: str
    child_agent_id: str
    dispatch_nonce: str
    parent_signer_trusted: bool
    child_agent_signer_matches: bool
    parent_observed: bool


def admit_link(link: SpanLink, seen_nonces: dict[str, str]) -> bool:
    """Return True only if the link is authoritative per conditions 1-4.

    Non-authoritative links are routed to the attribute graph by the caller;
    this function never silently accepts them as causal edges.
    """
    if not link.parent_signer_trusted:
        raise LinkAuthorityError(
            f"parent span {link.parent_span_id} in trace {link.trace_id} "
            "was not minted by a trusted signer; link is non-authoritative"
        )
    if not link.child_agent_signer_matches:
        raise LinkAuthorityError(
            f"child agent {link.child_agent_id} identity is not asserted by "
            f"the span minting signer for {link.child_span_id}; possible identity laundering"
        )
    if not link.parent_observed:
        raise LinkAuthorityError(
            f"parent span {link.parent_span_id} has not been observed or attested; "
            "cannot accept child as causal edge"
        )
    prior = seen_nonces.get(link.dispatch_nonce)
    if prior is not None and prior != link.child_span_id:
        # Retry duplication: same dispatch nonce, different child. Quarantine.
        raise LinkAuthorityError(
            f"dispatch nonce {link.dispatch_nonce} already bound to "
            f"{prior}; {link.child_span_id} is a duplicate emission and must be quarantined"
        )
    seen_nonces[link.dispatch_nonce] = link.child_span_id
    return True
