Skip to content

feature(Stream): Replay missed bars on reconnect, add --since and --replay - #31

Merged
szemyd merged 1 commit into
mainfrom
claude/stream-replay
Nov 13, 2026
Merged

szemyd merged 1 commit into
mainfrom
claude/stream-replay

Conversation

@almostintuitive

Copy link
Copy Markdown
Contributor

The live feed now keeps recent bars and replays them to a subscribe that carries since (dream-faster/unravel-router#1111). This uses that in aperiodic stream, so a reconnect no longer leaves a gap.

What changes

  • Replay on reconnect (on by default; --replay=false turns it off). A reconnect asks for each channel's bars since the newest one received. If none was received, it asks from one bar before the previous subscribe. Replayed rows print first, marked "replay":true, then the live rows.
  • --since replays from a time of your choosing on the first connect: an RFC 3339 time or how long ago (30m). It needs a 1m or longer interval, the only ones the server keeps.
  • A summary of each replay goes to stderr: bars, rows, the time range, and bars the server doesn't hold (to fill from REST).
  • Truncated replays are followed up. The server caps one replay; the CLI then asks again from the next bar, up to 50 times.
  • Busy refusals are retried. After a server restart the server can refuse a subscribe with limit_exceeded while many clients replay at once. The CLI sends it again after a 1 to 2 s random pause, and after 5 tries subscribes without the replay.
  • 16 MiB message limit, up from 1 MiB. One replay frame carries a whole bar, which is over a megabyte on an all-symbols channel. At 1 MiB the socket would close, reconnect and ask for the same replay forever.
  • Output stays the same for existing users. Live rows print exactly as before: replay is left out when false. --count still counts only live rows.
  • Older servers: they ignore since. Production answers replayed with unavailable: true until replay is turned on there.

Tests

go test -run 'TestStream_' ./... passes, with seven new tests:

  • --since replays before the live rows, including a 2 MiB frame;
  • a reconnect replays from the newest bar;
  • --replay=false sends no since;
  • a busy refusal is sent again;
  • a truncated replay is followed up from the next bar;
  • --since is refused below 1m or when unparseable;
  • no since is sent at 15s.

The *_live_test.go suites need APERIODIC_API_KEY and were not run here.


Generated by Claude Code

@almostintuitive
almostintuitive marked this pull request as ready for review November 12, 2026 12:51
@szemyd
szemyd added this pull request to stack #34 November 13, 2026 13:24
@szemyd
szemyd merged commit 20df5b9 into main Nov 13, 2026
9 checks passed
@szemyd
szemyd deleted the claude/stream-replay branch November 13, 2026 13:25
szemyd added a commit that referenced this pull request Nov 13, 2026
…and retry refused follow-ups (#33)

This PR is stacked on #31 and merges into its branch. It
fixes review findings checked against the server in
dream-faster/unravel-router#1149 and dream-faster/unravel-router#1199.

## What changes

- **A drop during a catch-up resumes where the replay got to.** The live
rows held during a replay arrive before `replayed`, so `lastBar` runs
ahead of a replay that is still catching up. A reconnect used to resume
from it and skip the rest of the gap. `replayFrom` now tracks each
unfinished replay's bar, advanced by each replay frame's `time`, and a
reconnect resumes from there first.
- **An empty truncated replay** (`to` null) is asked for again from
`from`. If it comes back empty again from the same bar, that bar is
larger than the server's cap. Stderr then says so instead of "more to
come", and the stream stops asking. `StreamReplay.FollowedUp` tells the
CLI whether a follow-up was sent.
- **A refused follow-up is sent again.** A follow-up refused with
`limit_exceeded` is sent again after a jittered pause, up to
`streamBusyRetries` times, then the stream warns. Running out of the 50
follow-ups also warns now, instead of stopping without a word.
- **Docs:** the `streamMessageLimit` comment is updated (replayed bars
now come in small frames), and so is the README's replay paragraph.

## Tests

`go test -run 'TestStream_' ./...` passes. New tests:
- an empty truncated replay is asked for again from `from`, then given
up with a message;
- a drop during a catch-up resumes from where the replay got to;
- a refused follow-up is sent again, with no warning.

`go vet` and `gofmt` are clean. The full `go test ./...` has the same 8
failures as this PR's base branch: they are the `*_live_test.go` suites,
which need `APERIODIC_API_KEY` and network access.

https://claude.ai/code/session_01MoDcuxddwYnzAPetT7cR5r

---
_Generated by [Claude
Code](https://claude.ai/code/session_01MoDcuxddwYnzAPetT7cR5r)_

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants