# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/how-should-an-instance-reconcile-mcp-http-native-transport-streaming-session-resumption-with-backpressure-when-the-client-resumes-mid-stream.md
# Remnant Warrant:    https://corpusfetch.com/c/how-should-an-instance-reconcile-mcp-http-native-transport-streaming-session-resumption-with-backpressure-when-the-client-resumes-mid-stream.warrant.json
# Markdown SHA-256:   650265c5ed5e21e817343e154dbcd9c904b4783f895095088feb2a9f0fa1a275
# Code AST SHA-256:   b8cb719ce2efd64e21a5cb82aac624c59c071df4e0be250c719bb6516ca6c072
# Verified Classes:   ResumeInvariantViolation, EventLog
# Defensive Guards:   1 fail-closed invariants (zero external deps)

class ResumeInvariantViolation(RuntimeError):
    """Raised when a stream resume cannot produce a gap-free suffix from Last-Event-ID."""
    pass


class EventLog:
    def __init__(self, retained_floor: int):
        self._events: dict[int, dict] = {}
        self._retained_floor = retained_floor

    def append(self, event_id: int, payload: dict) -> None:
        self._events[event_id] = payload

    def tail(self) -> int:
        return max(self._events) if self._events else 0

    def covers(self, start: int) -> bool:
        return start >= self._retained_floor and start <= self.tail() + 1

    def replay_from(self, start: int):
        for eid in range(start, self.tail() + 1):
            yield eid, self._events[eid]


def resume_stream(log: EventLog, last_event_id: int, buffer_head: int):
    """Resume a stream at last_event_id+1, honoring the gap-free invariant.

    buffer_head is the first event ID still present in the retained send buffer,
    or -1 if the buffer is empty/evicted.
    """
    start = last_event_id + 1

    if not log.covers(start):
        # Resume point is outside the reconstructible window. Do NOT silently
        # replay a partial range; that manufactures a gap the client cannot see.
        raise ResumeInvariantViolation(
            f"cannot resume at {start}: log retained floor is "
            f"{log._retained_floor}, tail is {log.tail()}"
        )

    # Aligned fast path: buffer head is exactly the next event and contiguous.
    if buffer_head == start:
        yield from log.replay_from(start)
        return

    # Misaligned (buffer ahead or behind the resume point): discard buffer,
    # treat log as sole source of truth.
    yield from log.replay_from(start)
