# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/when-must-an-instance-refuse-a-skill-whose-manifest-signature-verifies-but-whose-declared-capability-graph-exceeds-the-registry-s-transitive-trust-clo.md
# Remnant Warrant:    https://corpusfetch.com/c/when-must-an-instance-refuse-a-skill-whose-manifest-signature-verifies-but-whose-declared-capability-graph-exceeds-the-registry-s-transitive-trust-clo.warrant.json
# Markdown SHA-256:   a5cfd8ff01bc8cf35195d7be1d411f7a4de48d4257722114041498cc6b4a0e5e
# Code AST SHA-256:   df97f5ae5a52143907937cc7858e8508b1fade5af58340986f14d9233cb04f06
# Verified Classes:   TransitiveClosureViolation
# Defensive Guards:   3 fail-closed invariants (zero external deps)

class TransitiveClosureViolation(RuntimeError):
    """Raised when a skill's recomputed transitive capability closure
    exceeds the requesting principal's trust closure, even though the
    manifest signature verifies and direct capabilities are in-closure."""
    pass


def admit_skill(manifest, principal, registry, closure_cache):
    # 1. Signature check (necessary, not sufficient).
    if not registry.verify_signature(manifest):
        raise TransitiveClosureViolation(
            f"signature invalid for {manifest.skill_id}"
        )

    principal_closure = frozenset(principal.capability_closure)

    # 2. Direct capability check.
    direct = frozenset(manifest.direct_capabilities)
    if not direct <= principal_closure:
        raise TransitiveClosureViolation(
            f"direct caps {direct - principal_closure} outside closure"
        )

    # 3. Transitive closure, recomputed against current policy,
    #    keyed by principal closure hash to prevent cross-principal leaks.
    cache_key = (
        manifest.skill_id,
        manifest.version,
        hash(principal_closure),
        registry.policy_version,
    )
    transitive = closure_cache.get(cache_key)
    if transitive is None:
        transitive = registry.recompute_transitive_closure(
            manifest, policy=registry.current_policy
        )
        closure_cache[cache_key] = transitive
    transitive = frozenset(transitive)

    excess = transitive - principal_closure
    if excess:
        # Narrow manifest with wide transitive closure: escalate severity.
        severity = "critical" if direct < transitive else "high"
        raise TransitiveClosureViolation(
            f"transitive closure for {manifest.skill_id}@"
            f"{manifest.version} exceeds principal closure by {excess} "
            f"(severity={severity}); quarantine, do not admit-with-warning"
        )

    return registry.commit_admission(manifest, principal)
