Category: spec-conformance Severity: major
Location: src/arcp/_runtime/_handshake.py:89-91
Spec: ARCP v1.1 §6.3
What
Spec §6.3 (and §12) require RESUME_WINDOW_EXPIRED when the buffer no longer covers the requested last_event_seq. When the resume window has elapsed the record is swept and resume fails with PERMISSION_DENIED rather than RESUME_WINDOW_EXPIRED. Even when a record exists, the code replays from read_since_seq(last_event_seq) without checking the buffer still covers it (events may have been released via ack), so a gap is replayed silently. The ResumeWindowExpiredError class exists in _errors.py but is never raised anywhere in the codebase.
Evidence
record = runtime._pop_resumable(resume.session_id)
if record is None:
raise PermissionDeniedError(f"no resumable session for session_id={resume.session_id!r}")
Proposed fix
Distinguish an expired/trimmed window from an auth failure: if the resume record is absent due to window expiry, or the event log no longer covers resume.last_event_seq, raise ResumeWindowExpiredError. Keep PERMISSION_DENIED only for token/principal mismatch.
Acceptance criteria
Category: spec-conformance Severity: major
Location:
src/arcp/_runtime/_handshake.py:89-91Spec: ARCP v1.1 §6.3
What
Spec §6.3 (and §12) require
RESUME_WINDOW_EXPIREDwhen the buffer no longer covers the requestedlast_event_seq. When the resume window has elapsed the record is swept and resume fails withPERMISSION_DENIEDrather thanRESUME_WINDOW_EXPIRED. Even when a record exists, the code replays fromread_since_seq(last_event_seq)without checking the buffer still covers it (events may have been released via ack), so a gap is replayed silently. TheResumeWindowExpiredErrorclass exists in_errors.pybut is never raised anywhere in the codebase.Evidence
Proposed fix
Distinguish an expired/trimmed window from an auth failure: if the resume record is absent due to window expiry, or the event log no longer covers
resume.last_event_seq, raiseResumeWindowExpiredError. KeepPERMISSION_DENIEDonly for token/principal mismatch.Acceptance criteria
last_event_seq) yields asession.errorwith codeRESUME_WINDOW_EXPIRED, asserted by a test.