From 6182ae044bf12ce4ab7ade1b1d78885d38401793 Mon Sep 17 00:00:00 2001 From: nesquena-hermes Date: Sat, 4 Jul 2026 06:37:18 +0000 Subject: [PATCH] release #5513: correct RFC source anchors + self-validating test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Codex Phase-1 gate found the RFC cited stale/wrong source anchors (docs-only, but actively misleading to future implementers): /api/sessions/events is routed at routes.py:12345-12346 (RFC said 12320-12321 = /api/chat/cancel); _handle_session_events_stream at 16177 (RFC said 16142 = a gateway-sse comment); replay reads after_event_id/after_seq QUERY PARAMS (RFC said Last-Event-ID header — that's the *proposed* new-endpoint contract, not current). Corrected all six routes.py anchors + the replay-mechanism description, verified each against master. The accompanying test asserted the WRONG anchors and passed (codifying the error). Rewrote test_rfc_cites_current_global_endpoint_source to parse every routes.py anchor from the RFC and verify it lands on the real /api/sessions/events route + _handle_session_events_stream definition — so it now catches drift instead of locking in a stale number. Co-authored-by: rodboev --- docs/rfcs/session-sse-contract-v1.md | 25 ++++++----- ...test_issue4812_session_sse_contract_rfc.py | 41 ++++++++++++++----- 2 files changed, 45 insertions(+), 21 deletions(-) diff --git a/docs/rfcs/session-sse-contract-v1.md b/docs/rfcs/session-sse-contract-v1.md index d38da3e8..9f36662e 100644 --- a/docs/rfcs/session-sse-contract-v1.md +++ b/docs/rfcs/session-sse-contract-v1.md @@ -38,8 +38,8 @@ against current source before any route is added. - This RFC does **not** implement `GET /api/sessions/{session_id}/events`. No route, handler, or related code is added in this PR. - This RFC does **not** modify `GET /api/sessions/events` (the existing global - session-list invalidation stream routed at `api/routes.py:12320-12321` and - implemented by `_handle_session_events_stream()` at `api/routes.py:16142`). + session-list invalidation stream routed at `api/routes.py:12345-12346` and + implemented by `_handle_session_events_stream()` at `api/routes.py:16177`). - This RFC does **not** replace or modify existing streams: `/api/chat/stream`, `/api/approval/stream`, or `/api/clarify/stream`. - This RFC does **not** introduce Android, iOS, or PWA client code. @@ -53,8 +53,8 @@ against current source before any route is added. ### Existing global session-list stream `GET /api/sessions/events` is a **different endpoint** from the one this RFC -proposes. It is routed at `api/routes.py:12320-12321` and implemented by -`_handle_session_events_stream()` at `api/routes.py:16142`. It emits bare +proposes. It is routed at `api/routes.py:12345-12346` and implemented by +`_handle_session_events_stream()` at `api/routes.py:16177`. It emits bare `sessions_changed` events and keepalives for any change to the session list. It is a global invalidation signal, not a per-session lifecycle stream. The proposed `GET /api/sessions/{session_id}/events` is per-session and path-distinct. @@ -73,13 +73,16 @@ Line ranges in this inventory were verified against WebUI `master` when this RFC was written. Function, constant, and endpoint names are the stable anchors if source layout moves later. -- `_parse_run_journal_event_id()` and `_parse_run_journal_after_seq()` at - `api/routes.py:15638-15665` parse the cursor from `Last-Event-ID`. -- `_runner_event_id()` at `api/routes.py:15730-15737` constructs the event `id` +- `_parse_run_journal_event_id()` (`api/routes.py:15673-15686`) and + `_parse_run_journal_after_seq()` (`api/routes.py:15688-15701`) parse the replay + cursor from the `after_event_id` / `after_seq` **query params** (not the + `Last-Event-ID` header — that header is the *proposed* new-endpoint contract + below, §Reconnect). +- `_runner_event_id()` at `api/routes.py:15765-15772` constructs the event `id` field as `stream_id:seq`. -- Live event `id:` is emitted at `api/routes.py:15869-15885`. +- Live event `id:` is emitted during replay/stream at `api/routes.py:15703-15762`. - `_replay_run_journal()` reads events by `(session_id, stream_id)` at - `api/routes.py:15668-15700`. + `api/routes.py:15703-15735`. - `api/streaming.py:6265-6285` writes current live agent streams to `STREAMS[stream_id]`. - `api/streaming.py:6620-6634` appends SSE events to the run journal and carries @@ -159,7 +162,7 @@ position. **`event_id` is opaque to clients.** Its current source-compatible form is `stream_id:seq`, as constructed by `_runner_event_id()` at -`api/routes.py:15730-15737`. Clients must treat it as an opaque string and must +`api/routes.py:15765-15772`. Clients must treat it as an opaque string and must not parse or construct cursor values. **`seq` is monotonic within a stream/run.** It is not a session-global counter @@ -177,7 +180,7 @@ events. The live `STREAMS[stream_id]` queue (`api/streaming.py:6265-6285`) is not a reliable replay source because it holds only recent in-memory state. A future implementation must replay from the run journal via the existing -`_replay_run_journal()` path (`api/routes.py:15668-15700`) and fall back to the +`_replay_run_journal()` path (`api/routes.py:15703-15735`) and fall back to the snapshot mechanism when journal entries are unavailable for a given cursor. ## Snapshot fallback diff --git a/tests/test_issue4812_session_sse_contract_rfc.py b/tests/test_issue4812_session_sse_contract_rfc.py index c1996c04..e70925ec 100644 --- a/tests/test_issue4812_session_sse_contract_rfc.py +++ b/tests/test_issue4812_session_sse_contract_rfc.py @@ -91,18 +91,39 @@ class TestEndpointDistinction: ) def test_rfc_cites_current_global_endpoint_source(self): + """The RFC's source anchors for the existing global stream must be + ACCURATE against current api/routes.py — verify the cited lines actually + contain what the RFC claims, rather than string-matching a fixed number + (which silently rots and codifies wrong anchors, #5513 gate finding).""" + import re text = _rfc() - assert "api/routes.py:12320-12321" in text, ( - "RFC must cite the current global sessions/events route match" + routes = (REPO / "api" / "routes.py").read_text(encoding="utf-8").splitlines() + + # Pull every `api/routes.py:-` or `api/routes.py:` + # anchor the RFC cites and confirm the referenced span exists. + anchors = re.findall(r"api/routes\.py:(\d+)(?:-(\d+))?", text) + assert anchors, "RFC must cite at least one api/routes.py source anchor" + for start, end in anchors: + lo = int(start) + hi = int(end) if end else lo + assert 1 <= lo <= len(routes), f"RFC cites api/routes.py:{start} beyond EOF ({len(routes)} lines)" + assert 1 <= hi <= len(routes), f"RFC cites api/routes.py:{end} beyond EOF ({len(routes)} lines)" + + # The two load-bearing anchors must land on the real definitions. + def _anchor_line(label): + m = re.search(r"%s.*?api/routes\.py:(\d+)" % re.escape(label), text, re.DOTALL) + assert m, f"RFC must cite a routes.py anchor near {label!r}" + return int(m.group(1)) + + route_line = _anchor_line("routed at") + assert "/api/sessions/events" in routes[route_line - 1], ( + f"RFC's routed-at anchor api/routes.py:{route_line} must be the " + f"/api/sessions/events route; got: {routes[route_line - 1].strip()!r}" ) - assert "api/routes.py:16142" in text, ( - "RFC must cite the current _handle_session_events_stream definition" - ) - assert "api/routes.py:12296-12297" not in text, ( - "RFC must not cite the stale global sessions/events route range" - ) - assert "api/routes.py:16118" not in text, ( - "RFC must not cite the stale _handle_session_events_stream line" + handler_line = _anchor_line("_handle_session_events_stream()") + assert "def _handle_session_events_stream" in routes[handler_line - 1], ( + f"RFC's handler anchor api/routes.py:{handler_line} must be the " + f"_handle_session_events_stream definition; got: {routes[handler_line - 1].strip()!r}" ) def test_contracts_distinguishes_both_endpoints(self):