# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/how-does-an-instance-detect-a-shadow-registered-tool-capability-that-survives-registry-reload-in-agent-marketplaces.md
# Remnant Warrant:    https://corpusfetch.com/c/how-does-an-instance-detect-a-shadow-registered-tool-capability-that-survives-registry-reload-in-agent-marketplaces.warrant.json
# Markdown SHA-256:   5862fe6010d073026c32a69831a78f86655da576cc9f622cf5a839e932626e8c
# Code AST SHA-256:   3b3685164bcb3dcf2fdc8a90f64412c302a9ae1d9b74a9fd29f9bea97f517345
# Verified Classes:   RevokedCapabilityStillLiveError
# Defensive Guards:   1 fail-closed invariants (zero external deps)

class RevokedCapabilityStillLiveError(RuntimeError):
    """Raised when a tool removed from the registry remains invocable
    through a live binding (module map, delegation table, or import pin)."""
    pass


def assert_capability_revoked(tool_name, resolve_paths):
    """
    Verify that a revoked tool cannot be reached through ANY resolution path.

    resolve_paths: iterable of (path_name, resolver) where resolver(name)
    returns a callable or None. The registry descriptor list is only one
    path; the dangerous ones are the unmediated fallbacks.
    """
    live_paths = []
    for path_name, resolver in resolve_paths:
        try:
            target = resolver(tool_name)
        except KeyError:
            target = None
        if target is not None:
            live_paths.append(path_name)

    if live_paths:
        raise RevokedCapabilityStillLiveError(
            f"Tool {tool_name!r} was revoked from the registry but is still "
            f"reachable via live binding path(s): {live_paths}. "
            f"Descriptor-scoped reload did not revoke the capability. "
            f"Either clear the binding or remove the resolution path."
        )
    return True


def reload_registry(registry, resolver_paths):
    """
    Reload descriptors, then prove every previously-registered tool that is
    now absent is genuinely unreachable. Fail closed on any divergence.
    """
    prior_tools = set(registry.descriptor_names())
    registry.reload()
    current_tools = set(registry.descriptor_names())
    revoked = prior_tools - current_tools

    for name in revoked:
        # This is the check that descriptor scanning cannot perform.
        assert_capability_revoked(name, resolver_paths)

    return {"revoked": sorted(revoked), "verified_unreachable": True}
