# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/when-must-an-instance-distinguish-sse-backpressure-from-session-resumption-in-mcp-http-native-transport.md
# Remnant Warrant:    https://corpusfetch.com/c/when-must-an-instance-distinguish-sse-backpressure-from-session-resumption-in-mcp-http-native-transport.warrant.json
# Markdown SHA-256:   a05be3ef5f1e9b615f64a00c2a6e312c788223473bf92a0f5dc7c478f2e7dd56
# Code AST SHA-256:   d6c6ab8b17b7c14753b244d94c2fe951c09027017263c62ff205847f0e452e1d
# Verified Classes:   ResumeWindowViolation, EventLog
# Defensive Guards:   4 fail-closed invariants (zero external deps)

class ResumeWindowViolation(RuntimeError):
    """Raised when a resume request cannot be satisfied without silent loss."""
    pass


class EventLog:
    def __init__(self, capacity: int):
        self.capacity = capacity
        self._events = []          # list of (event_id, payload)
        self._floor = 0            # lowest event_id still retained
        self._head = 0             # highest event_id assigned

    def enqueue(self, payload) -> int:
        # Event ID is assigned eagerly, before any write attempt.
        self._head += 1
        event_id = self._head
        if len(self._events) >= self.capacity:
            # Do NOT evict an event that a future resume may reference.
            # Signal upstream backpressure instead.
            raise ResumeWindowViolation(
                f"retention buffer full at event {event_id}; "
                f"floor={self._floor} head={self._head}; "
                "producer must block or session must fail resumably"
            )
        self._events.append((event_id, payload))
        return event_id

    def replay_from(self, last_event_id: int):
        if last_event_id < self._floor:
            raise ResumeWindowViolation(
                f"Last-Event-ID {last_event_id} predates retained floor "
                f"{self._floor}; unrecoverable gap, client must re-initialize"
            )
        if last_event_id > self._head:
            raise ResumeWindowViolation(
                f"Last-Event-ID {last_event_id} ahead of server head "
                f"{self._head}; session state mismatch"
            )
        return [p for eid, p in self._events if eid > last_event_id]


def handle_resume(log: EventLog, last_event_id: int):
    try:
        return log.replay_from(last_event_id)
    except ResumeWindowViolation as exc:
        # Never silently restart from head; surface the gap explicitly.
        raise ResumeWindowViolation(str(exc)) from exc
