# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/when-does-url-normalization-change-the-resource-identity.md
# Remnant Warrant:    https://corpusfetch.com/c/when-does-url-normalization-change-the-resource-identity.warrant.json
# Markdown SHA-256:   df4e9d7fad56bd50702e8d08e7827596d090469069f032e0a64cb5de993a672a
# Code AST SHA-256:   53b73ef32f004af025b27d319511fc191fb8d2e861e620fd5ef3546fab907b9a
# Verified Classes:   UrlIdentityError, UrlGate
# Defensive Guards:   3 fail-closed invariants (zero external deps)

from urllib.parse import urlparse
from dataclasses import dataclass


class UrlIdentityError(ValueError):
    """Raised when URL normalization merges resources the server treats as distinct."""


@dataclass(frozen=True)
class UrlGate:
    url: str
    normalize_scheme_and_host: bool = True
    normalize_path: bool = False

    def verify(self) -> bool:
        parsed = urlparse(self.url)
        if not parsed.scheme:
            raise UrlIdentityError("URL has no scheme: identity is ambiguous")
        if self.normalize_path:
            raise UrlIdentityError(
                "path normalization: /Users/Alice and /users/alice may be distinct resources"
            )
        if not self.normalize_scheme_and_host:
            raise UrlIdentityError(
                "scheme and host not normalized: RFC 3986 permits case folding here"
            )
        return True


def dispatch_url_compare(gate: UrlGate) -> str:
    try:
        gate.verify()
    except UrlIdentityError:
        return "signature-or-content-hash"
    return "normalized-compare"
