From 3e21755c441da6cbf39d8f0c0b4557f68c2dda95 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 12 Nov 2026 23:50:18 +0000 Subject: [PATCH] docs: a ping is the replay boundary, a cursor frame is not States the agent event stream contract in FeedFrame and the channel plan, from the contract questions on #232. Refs #239. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01QNDehAAVazXavfSCUqc9om --- planning/claude-code-channel.md | 5 ++++- src/pepper_cli/api_client.py | 7 ++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/planning/claude-code-channel.md b/planning/claude-code-channel.md index 6ab3a63..7fb3a32 100644 --- a/planning/claude-code-channel.md +++ b/planning/claude-code-channel.md @@ -334,7 +334,10 @@ put that backlog into context on every Claude Code restart. Decided (ยง14 C): - An event whose `created_at` is older than the process start time minus 60 seconds is consumed without a push. Instead, once the stream has caught up (the first heartbeat after replay), push one `kind="backlog"` control event: how many messages were skipped, per topic id, and the oldest - and newest timestamps. The skill tells the sponsor, as it does today. + and newest timestamps. The skill tells the sponsor, as it does today. The heartbeat is the + boundary because the server sends a `: ping` only while it has nothing past the client's + position. A `cursor` frame is a skip marker, not a boundary: it can arrive mid-replay, or not + at all. - In-process reconnects resume from the cursor and push everything, since nothing they replay is from before the session. - With no cursor file, `rooms watch` starts from the beginning of the retained stream (`--since` diff --git a/src/pepper_cli/api_client.py b/src/pepper_cli/api_client.py index 7c5d72e..45ecb03 100644 --- a/src/pepper_cli/api_client.py +++ b/src/pepper_cli/api_client.py @@ -485,7 +485,12 @@ class FeedFrame: ``"comment"`` (empty ``payload``) stands for an SSE comment line, the server's ``: connected`` / ``: ping`` heartbeat: it carries nothing to act - on but tells the caller the connection is healthy. + on but tells the caller the connection is healthy. A ``: ping`` is also the + replay boundary: the server sends one only while it has nothing past the + caller's position, so the first ping after connecting means the stream has + caught up. A ``cursor`` frame is not a boundary: it can arrive mid-replay, + or not at all. A ``start=head`` stream opens with its head ``cursor`` frame + (after ``scope``) before any event or ping. ``id`` is the frame's SSE ``id:``: for an event frame the event id, for a ``cursor`` frame the cursor, ``None`` on ``error`` and ``scope``. Either