# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/which-invariants-prevent-causal-trace-stitching-from-failing-silently-across-federated-agents.md
# Remnant Warrant:    https://corpusfetch.com/c/which-invariants-prevent-causal-trace-stitching-from-failing-silently-across-federated-agents.warrant.json
# Markdown SHA-256:   2db2f084dcab3e60d079b51986a5cdcae09fcdac58354abbdce7c9add6b1d742
# Code AST SHA-256:   cf150070c341f75bceb88a3e02d1b05410c597dd25c5786ed879e70ec4f22d61
# Verified Classes:   CausalStitchError
# Defensive Guards:   4 fail-closed invariants (zero external deps)

class CausalStitchError(RuntimeError):
    """Raised when a federated trace edge cannot be proven causal."""
    pass


def stitch_edge(
    parent_span_id: str,
    child_span_id: str,
    registry: dict[str, list[str]],
    causal_token: int,
    parent_token: int,
) -> str:
    """
    Resolve a parent->child edge across federated agents.

    registry maps span_id -> list of physical execution IDs.
    Returns 'single', 'fan_in', or raises CausalStitchError.
    """
    executions = registry.get(parent_span_id, [])

    if len(executions) == 0:
        # Parent was never observed: broken causal link. Do NOT reparent.
        raise CausalStitchError(
            f"orphan edge: parent {parent_span_id} has zero executions; "
            f"child {child_span_id} cannot be stitched to trace root"
        )

    if causal_token <= parent_token:
        # Causal token did not advance: wall-clock ordering would be invalid.
        raise CausalStitchError(
            f"non-monotonic causal token on edge {parent_span_id}->{child_span_id}: "
            f"child token {causal_token} <= parent token {parent_token}"
        )

    if len(executions) > 1:
        # Retry fan-in: ambiguous parent. Must be classified, not collapsed.
        return "fan_in"

    return "single"


def attribute_latency(edge_kind: str, child_start: float, parent_end: float) -> float:
    if edge_kind == "fan_in":
        raise CausalStitchError(
            "cannot attribute latency to a single parent under retry fan-in; "
            "attribute to earliest attempt and mark duplicates"
        )
    if parent_end < child_start:
        raise CausalStitchError(
            f"negative parent-child interval: parent_end={parent_end} < "
            f"child_start={child_start}; trace quarantined from SLO metrics"
        )
    return child_start - parent_end
