# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/how-does-an-instance-detect-a-manifest-shadowing-skill-injection-when-tool-descriptors-agree-but-authority-does-not.md
# Remnant Warrant:    https://corpusfetch.com/c/how-does-an-instance-detect-a-manifest-shadowing-skill-injection-when-tool-descriptors-agree-but-authority-does-not.warrant.json
# Markdown SHA-256:   7047fb264576ab0ee23a8c86813d39119c7e1396deb1346c7e81ba2db3c66efe
# Code AST SHA-256:   cb59bc0717356d2aca6843891719fb6889fdf80b6026dde5bf3c8ce9cecda128
# Verified Classes:   ManifestShadowError, Manifest
# Defensive Guards:   3 fail-closed invariants (zero external deps)

import hashlib
from dataclasses import dataclass, field


class ManifestShadowError(RuntimeError):
    """Raised when two manifests agree on contract but diverge on authority."""
    pass


@dataclass(frozen=True)
class Manifest:
    name: str
    schema: dict
    binding_endpoint: str
    grant: frozenset
    trust_tier: int          # higher = more trusted
    source: str

    def schema_hash(self) -> str:
        return hashlib.sha256(repr(sorted(self.schema.items())).encode()).hexdigest()

    def binding_digest(self) -> str:
        # binding + grant, NOT schema: this is the authority fingerprint
        payload = f"{self.binding_endpoint}|{sorted(self.grant)}"
        return hashlib.sha256(payload.encode()).hexdigest()


def resolve_manifests(manifests: list[Manifest]) -> dict[str, Manifest]:
    """Merge manifests by name. Contract agreement is NOT sufficient to merge;
    authority (binding + grant) must also agree, or the higher-trust source wins
    and the lower-trust binding is rejected."""
    by_name: dict[str, list[Manifest]] = {}
    for m in manifests:
        by_name.setdefault(m.name, []).append(m)

    resolved: dict[str, Manifest] = {}
    for name, group in by_name.items():
        top_tier = max(m.trust_tier for m in group)
        top = [m for m in group if m.trust_tier == top_tier]

        # All same-tier entries must agree on authority, not just contract.
        authority = {m.binding_digest() for m in top}
        if len(authority) > 1:
            raise ManifestShadowError(
                f"tool {name!r}: same-tier manifests diverge on binding authority "
                f"({authority}) despite matching schema"
            )

        winner = top[0]
        # Any lower-trust manifest that agrees on schema but differs on binding
        # is a shadow attempt: reject the load rather than silently collapse.
        for m in group:
            if m.trust_tier < top_tier:
                if m.schema_hash() == winner.schema_hash() and \
                   m.binding_digest() != winner.binding_digest():
                    raise ManifestShadowError(
                        f"tool {name!r}: {m.source!r} shadows trusted binding "
                        f"with endpoint {m.binding_endpoint!r}"
                    )
                # Missing/empty grant on a lower-trust source must not inherit.
                if not m.grant and winner.grant:
                    raise ManifestShadowError(
                        f"tool {name!r}: {m.source!r} omits grant; "
                        f"refusing to inherit {sorted(winner.grant)}"
                    )
        resolved[name] = winner
    return resolved
