# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/in-what-scenarios-must-an-instance-reject-cross-origin-span-links-in-federated-genai-agent-traces.md
# Remnant Warrant:    https://corpusfetch.com/c/in-what-scenarios-must-an-instance-reject-cross-origin-span-links-in-federated-genai-agent-traces.warrant.json
# Markdown SHA-256:   04cf5799de05f99a7f3401fd66cc87f0f117e15abb711f16241ef9140112abfc
# Code AST SHA-256:   15c817f0127058935e36c14641d1c3ac7946e864bc632151f7b801fd85d290a8
# Verified Classes:   UnauthorizedSpanLinkError
# Defensive Guards:   2 fail-closed invariants (zero external deps)

class UnauthorizedSpanLinkError(RuntimeError):
    """Raised when a cross-origin span link lacks an explicit origin grant."""
    pass


def validate_link(link, enclosing_span, grants):
    """
    link: dict with trace_id, span_id, target_origin
    enclosing_span: dict with trace_id, emitter_origin
    grants: set of (emitter_origin, target_origin) authorized pairs
    """
    if link["trace_id"] != enclosing_span["trace_id"]:
        # Cross-trace link in an agent trace: context contamination, no override.
        raise UnauthorizedSpanLinkError(
            f"cross-trace link rejected: link.trace_id={link['trace_id']} "
            f"!= span.trace_id={enclosing_span['trace_id']}"
        )

    emitter = enclosing_span["emitter_origin"]
    target = link["target_origin"]

    if emitter != target and (emitter, target) not in grants:
        raise UnauthorizedSpanLinkError(
            f"no origin grant for {emitter!r} -> {target!r}; "
            f"link to span {link['span_id']} quarantined, span retained"
        )

    return {"accepted": True, "federated": emitter != target}
