# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/what-structural-signals-indicate-prompt-injection-taint-requires-provenance-relabeling-at-tool-boundaries.md
# Remnant Warrant:    https://corpusfetch.com/c/what-structural-signals-indicate-prompt-injection-taint-requires-provenance-relabeling-at-tool-boundaries.warrant.json
# Markdown SHA-256:   78a9ac6292d1046fa53c91221689383e963e96250f63858cc47a2391600d8b3b
# Code AST SHA-256:   63011dfa617314e9a1ff599fa2eb8707f92702a58baafeb786d32ee71ee092a6
# Verified Classes:   TaintJoinViolation
# Defensive Guards:   3 fail-closed invariants (zero external deps)

class TaintJoinViolation(RuntimeError):
    """Raised when a tool boundary would emit output with taint lower than the join of its inputs."""
    pass


# Ordered taint lattice: higher index = less trusted.
TAINT_ORDER = ["trusted:system", "trusted:tool", "untrusted:web", "untrusted:tool_output"]


def join_taint(*labels: str) -> str:
    if not labels:
        return "trusted:system"
    return max(labels, key=TAINT_ORDER.index)


def tool_boundary(tool_name: str, intrinsic_trust: str, arg_taints: list[str]) -> str:
    """Compute the output label for a tool call, enforcing the join invariant."""
    if intrinsic_trust not in TAINT_ORDER:
        raise TaintJoinViolation(f"unknown intrinsic trust {intrinsic_trust!r} for {tool_name}")
    for t in arg_taints:
        if t not in TAINT_ORDER:
            raise TaintJoinViolation(f"unknown argument taint {t!r} passed to {tool_name}")

    joined = join_taint(intrinsic_trust, *arg_taints)

    # Contract check: a tool declaring it never emits instruction-bearing text
    # must not receive tainted arguments; a mismatch is a contract violation.
    if tool_name in {"calculator", "json_parse"} and joined != intrinsic_trust:
        raise TaintJoinViolation(
            f"{tool_name} received tainted args (join={joined}); "
            f"tool contract forbids instruction-bearing input"
        )

    return joined


def emit_tool_result(tool_name: str, intrinsic_trust: str, arg_taints: list[str], payload: str) -> dict:
    out_label = tool_boundary(tool_name, intrinsic_trust, arg_taints)
    return {"label": out_label, "content": payload}
