Address review: the overlay, not the connection, is the roll-call participant

An EventSource reconnect opens a replacement connection under the same
page-level clientId before the old connection is seen to close, so the
close handler used to retire the reconnected overlay's report and hand
its lease back mid-flight. remove_sse_client now retires a client's word
only when no other connection still carries its id, the roll call counts
distinct overlays (plus id-less connections) instead of raw connections,
and the overlay ignores a replayed target it already handled, so a
reconnect never starts a second claim or a second Go. Covered by two new
HTTP cases in crates/cli/tests/agent_target.rs, a protocol case in
tests/live-agent-target.test.mjs, and the overlay contract suite.

AI-assisted: implemented and tested with Claude Code under maintainer
direction.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Abdul Wahab
2026-09-15 05:45:49 +05:00
committed by Abdul Wahab
co-authored by Claude Fable 5
parent d397140a77
commit da403a3410
6 changed files with 135 additions and 4 deletions
+1 -1
View File
@@ -1468,7 +1468,7 @@ Binds `127.0.0.1:PORT`. CORS: if request has `Origin` and (origin is loopback ht
| `GET /design-system.json?token=` | 401 `Unauthorized` | 404 `{present:false}` if neither DESIGN.md nor `.impeccable/design.json`; else `{present:true, hasMd, hasSidecar, mdNewerThanJson, parsed?, parseError?, sidecar?, sidecarError?}` (`parsed` = parseDesignMd output; `sidecarError` = `'Failed to parse .impeccable/design.json: '+msg`) |
| `GET /design-system/raw?token=` | 401 | 200 `text/markdown; charset=utf-8` DESIGN.md verbatim; 404 `Not found` |
| `GET /source?token=&path=` | 401 | path required and no `..` else 400 `Bad path`; resolved must be inside cwd (relative check, not root itself) else 403 `Forbidden`; 404 `File not found`; 200 `text/html; charset=utf-8` raw file. Used by browser to read source, svelte manifest and `params.json`. |
| `GET /events?token=&clientId=` (SSE) | 401 | `clientId` (optional) is the overlay's per-page-load id; on close the server retires that client's agent-target roll-call report and releases a lease it held, then re-judges each pending roll call against the remaining clients. Headers `text/event-stream`, `Cache-Control: no-cache`, `Connection: keep-alive`; first frame `data: {"type":"connected","hasProjectContext":b,"agentPolling":b,"activeSessions":[…]}\n\n`; `: keepalive\n\n` every 30s; on connect: cancels exit timer and removes queued anonymous `exit` events. On close: if 0 clients, after 8000 ms (still 0) enqueue `{type:'exit'}`. |
| `GET /events?token=&clientId=` (SSE) | 401 | `clientId` (optional) is the overlay's per-page-load id; on close the server retires that client's agent-target roll-call report and releases a lease it held **only when no other connection still carries that id** (an EventSource reconnect opens the replacement before the old connection is seen to close), then re-judges each pending roll call against the remaining overlays (distinct ids, plus connections that sent none). The pending targets are replayed to every connection that opens; the overlay ignores a replay of a target it already handled. Headers `text/event-stream`, `Cache-Control: no-cache`, `Connection: keep-alive`; first frame `data: {"type":"connected","hasProjectContext":b,"agentPolling":b,"activeSessions":[…]}\n\n`; `: keepalive\n\n` every 30s; on connect: cancels exit timer and removes queued anonymous `exit` events. On close: if 0 clients, after 8000 ms (still 0) enqueue `{type:'exit'}`. |
| `POST /events` | body JSON `token` mismatch → 401 `{"error":"Unauthorized"}`; invalid JSON → 400 `{"error":"Invalid JSON"}` | see 6.1 |
| `GET /stop?token=` | 401 | 200 text `stopping`, then shutdown |
| `GET /poll?token=&timeout=&leaseMs=&types=` | 401 `{"error":"Unauthorized"}` | see 6.3 |