# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/when-must-an-instance-abandon-header-based-mcp-session-affinity-in-favor-of-stateless-transport-fallback-at-the-edge.md
# Remnant Warrant:    https://corpusfetch.com/c/when-must-an-instance-abandon-header-based-mcp-session-affinity-in-favor-of-stateless-transport-fallback-at-the-edge.warrant.json
# Markdown SHA-256:   f033d422d8d8c130d7ed7fcc108ad1040f8f405b1a315961ae57eaaeec647831
# Code AST SHA-256:   4f7e85bd6a8dcbe3af2c1d6d526e6034fdf24ac45b1cb4afa9b72d907d857bd4
# Verified Classes:   SessionAffinityViolation
# Defensive Guards:   2 fail-closed invariants (zero external deps)

class SessionAffinityViolation(RuntimeError):
    """Raised when a session-bearing request reaches an instance that cannot
    prove ownership or cluster-wide absence of the session."""
    pass


IDEMPOTENT_TOOLS = frozenset({"tools/list", "resources/list", "ping"})


def handle_request(session_id, method, shared_dir, deadline_ok):
    if session_id is None:
        return dispatch_stateless(method)

    if local_session_exists(session_id):
        return dispatch_with_session(session_id, method)

    # Local absence alone is NOT sufficient to fall back.
    if method in IDEMPOTENT_TOOLS:
        return dispatch_stateless(method)

    if not deadline_ok:
        # Directory unreachable within deadline => UNKNOWN, not ABSENT.
        raise SessionAffinityViolation(
            f"cannot confirm cluster-wide absence of session {session_id!r} "
            f"for non-idempotent method {method!r} within deadline"
        )

    if shared_dir.session_exists(session_id):
        # Another instance owns it; do not silently serve on a fresh session.
        raise SessionAffinityViolation(
            f"session {session_id!r} owned by another instance; "
            f"request must be re-pinned or rejected, not downgraded"
        )

    # Cluster-wide absence confirmed: safe to treat as a new session.
    return dispatch_stateless(method)
