# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/which-invariants-prevent-skill-injection-via-untrusted-plugin-manifests-the-manifest-description-bifurcation-and-the-description-only-trust-boundary.md
# Remnant Warrant:    https://corpusfetch.com/c/which-invariants-prevent-skill-injection-via-untrusted-plugin-manifests-the-manifest-description-bifurcation-and-the-description-only-trust-boundary.warrant.json
# Markdown SHA-256:   93e8ef8a7793a372590b1ea450fab100c0322ac31be44750a112b924919c9ab6
# Code AST SHA-256:   96f8f75274cc3a12b551b770709bb224991e0e99a4d83637f4f52482e1fe5384
# Verified Classes:   DescriptionChannelViolation, TaggedDescription
# Defensive Guards:   3 fail-closed invariants (zero external deps)

import hashlib
from dataclasses import dataclass
from typing import Any


class DescriptionChannelViolation(RuntimeError):
    """Raised when an untrusted manifest string reaches model context
    without provenance tagging, or when a description influences
    capability resolution."""


@dataclass(frozen=True)
class TaggedDescription:
    text: str
    plugin_id: str
    manifest_digest: str
    trust: str = "untrusted_manifest"


def admit_manifest(plugin_id: str, raw: dict[str, Any]) -> dict[str, Any]:
    digest = hashlib.sha256(repr(sorted(raw.items())).encode()).hexdigest()
    # Capability channel: schema-only, never reads description strings.
    capabilities = {
        "tools": [t["name"] for t in raw.get("tools", [])],
        "scopes": raw.get("scopes", []),
    }
    # Description channel: every string is tagged before it can be rendered.
    tagged: list[TaggedDescription] = []
    for tool in raw.get("tools", []):
        if "description" in tool:
            tagged.append(TaggedDescription(tool["description"], plugin_id, digest))
        for param in tool.get("parameters", {}).values():
            if isinstance(param, dict) and "description" in param:
                tagged.append(TaggedDescription(param["description"], plugin_id, digest))
    return {"capabilities": capabilities, "descriptions": tagged, "digest": digest}


def render_for_model(admitted: dict[str, Any]) -> str:
    for d in admitted["descriptions"]:
        if d.trust != "untrusted_manifest" or not d.manifest_digest:
            raise DescriptionChannelViolation(
                f"description from {d.plugin_id} lacks provenance tag; refusing to render"
            )
        if "<untrusted" in d.text or "</untrusted" in d.text:
            raise DescriptionChannelViolation(
                f"description from {d.plugin_id} attempts envelope spoofing"
            )
    return "\n".join(
        f'<untrusted source="{d.plugin_id}" digest="{d.manifest_digest[:12]}">{d.text}</untrusted>'
        for d in admitted["descriptions"]
    )


def resolve_capability(admitted: dict[str, Any], tool_name: str) -> str:
    # Structural invariant: resolution must not read description text.
    if tool_name in admitted["capabilities"]["tools"]:
        return tool_name
    raise DescriptionChannelViolation(
        f"tool {tool_name!r} not in declared capabilities; "
        "selection by description is forbidden"
    )
