fix(stream): every running agent's live text shares one connection, which ends when its steps do (#48) #68

Merged
cmoriarty merged 2 commits from fix/one-delta-stream-48 into main 2026-09-26 23:04:45 -04:00
Owner

Fixes #48.

osfd speaks HTTP/1.1, and a browser allows six connections per host across all its tabs. The console held one stream for the run plus one per running agent step. On production on 2026-09-26, run_01M3GB3KN38YT9TZJ7KA7RQ5M0 fanned out to four propose.spec steps and propose.design, which used all six: the light said offline, steps showed as silent, step details failed with "signal is aborted without reason", and the page wouldn't reload.

It lasted because a step's delta stream never ended when the step did. /healthz showed sse: {a: 1, b: 5} with only one step still running.

What changes

  • GET /api/deltas?steps=a,b,c: every step's deltas on one connection, each frame naming its step. The console opens one for its run's running agent steps and replaces it when that set changes. A page now holds two long-lived connections however many agents run.
  • Delta streams end with their steps. At connect and at every heartbeat the server looks the steps up; once none can still write, it sends end and closes, and the console doesn't reconnect. The old one-step route stays for pages loaded before the deploy, and ends the same way, which frees stuck connections as soon as the server is updated.
  • A timeout says what happened: "osfd did not answer within 15 s. If other Braid tabs are open, close them: the browser may be out of connections to osfd."

Verification

  • ./tools/test.sh: fast lane passed, with 1,778 backend, 414 UI unit and 66 browser tests. New tests cover:
    • the multiplexed stream, and end when the steps settle, both at once and mid-stream;
    • the console's single stream, its swap when the set changes, and no reconnect after end;
    • the timeout message.
  • e2e/connection-budget.spec.ts uses a new six-agent fixture run. It checks that one delta stream names all six steps, and that an ordinary request and a step's details still answer. Chromium enforces the same six-connection limit, so the old console fails it.
  • The OpenSpec change is archived in this PR. agent-transcript gains "Live text uses one connection however many agents run".

🤖 Generated with Claude Code

Fixes #48. osfd speaks HTTP/1.1, and a browser allows six connections per host across all its tabs. The console held one stream for the run plus one per running agent step. On production on 2026-09-26, `run_01M3GB3KN38YT9TZJ7KA7RQ5M0` fanned out to four `propose.spec` steps and `propose.design`, which used all six: the light said offline, steps showed as silent, step details failed with "signal is aborted without reason", and the page wouldn't reload. It lasted because a step's delta stream never ended when the step did. `/healthz` showed `sse: {a: 1, b: 5}` with only one step still running. ## What changes - **`GET /api/deltas?steps=a,b,c`**: every step's deltas on one connection, each frame naming its step. The console opens one for its run's running agent steps and replaces it when that set changes. A page now holds **two long-lived connections however many agents run**. - **Delta streams end with their steps.** At connect and at every heartbeat the server looks the steps up; once none can still write, it sends `end` and closes, and the console doesn't reconnect. The old one-step route stays for pages loaded before the deploy, and ends the same way, which frees stuck connections as soon as the server is updated. - **A timeout says what happened:** "osfd did not answer within 15 s. If other Braid tabs are open, close them: the browser may be out of connections to osfd." ## Verification - `./tools/test.sh`: fast lane passed, with 1,778 backend, 414 UI unit and 66 browser tests. New tests cover: - the multiplexed stream, and `end` when the steps settle, both at once and mid-stream; - the console's single stream, its swap when the set changes, and no reconnect after `end`; - the timeout message. - `e2e/connection-budget.spec.ts` uses a new six-agent fixture run. It checks that one delta stream names all six steps, and that an ordinary request and a step's details still answer. Chromium enforces the same six-connection limit, so the old console fails it. - The OpenSpec change is archived in this PR. `agent-transcript` gains "Live text uses one connection however many agents run". 🤖 Generated with [Claude Code](https://claude.com/claude-code)
osfd speaks HTTP/1.1, and a browser allows six connections per host across all its tabs. The
console held one stream for the run and one per running agent step, so on production a
fan-out of four propose.spec steps and propose.design used all six. The light said offline,
steps showed as silent, step details failed with "signal is aborted without reason", and the
page would not reload. It lasted because a step's delta stream never ended with the step:
/healthz showed five open streams for steps that had finished minutes earlier.

GET /api/deltas?steps=a,b,c carries every step's deltas on one connection; each frame already
names its step. The console opens one for its run's running agent steps and replaces it when
that set changes, so a page holds two long-lived connections however many agents run.

At connect and at every heartbeat the server looks the steps up, and once none is still
writing it sends an `end` frame and closes. The console does not reconnect after `end`. The
one-step /api/steps/{id}/deltas stays, for pages loaded before this, and ends the same way.

A request osfd does not answer in time now says so, and suggests closing other Braid tabs,
instead of the browser's abort text.

The fixture serves /api/deltas and has a six-agent run. A browser test on it checks that one
delta stream names all six steps and that an ordinary request and a step's details still
answer. Chromium enforces the same six-connection limit, so the old console fails it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Archive one-delta-stream
Some checks failed
deploy / deploy (push) Has been cancelled
fea8788677
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
cmoriarty/braid!68
No description provided.