fix(dashboard): terminate SSE response heads immediately with ': open' comment frames - #57
Merged
Merged
Conversation
…pen' comment frame
W6 row ① fix-at-source (v3 side; w6-proxy root-caused the proxy
symptom). Bun only finalizes a streaming response's head when the FIRST
chunk enqueues. /api/update/events enqueued nothing on open unless the
event buffer had content, so an idle stream's head sat unterminated on
the wire until the 15s keep-alive — bare curl hung, browsers
direct-to-v3 waited 15s for EventSource open, and the v4 reverse-proxy's
hyper client (correctly) refused to forward an unfinished head.
Enqueue an SSE-legal comment frame (': open\n\n', invisible to
EventSource) as the first chunk in start(). Swept every other
ReadableStream SSE route in server.ts for the same lazy-head shape and
fixed the three that had it conditionally:
- /api/logs/<id>/stream — snapshot enqueues immediately ONLY when the
log file reads cleanly; missing/rotated file left the head hanging
until append or the 25s keep-alive.
- /api/audit/<team>/stream — first enqueue was async (.then) AND gated
on j.ok; empty/missing audit log hung the head until the 25s
keep-alive.
- /api/auth/openai-codex/<alias>/events — a fresh auth session has an
empty replay buffer; head hung until the first auth event or 15s
keep-alive.
Verified NOT lazy (no change): master /events (components/evy/server.ts)
writes a 'connected' event synchronously in start() — the W4 evidence
holds. The two /api/master/* SSE passthroughs forward an upstream body,
so their head timing is the upstream's.
No test added: dashboard/server.ts starts Bun.serve + the
notify-listener at module top level, so the suite can't import it
cheaply, and a comment frame doesn't justify new harness machinery.
Proof (scratch server :18790, scratch HOME + SUBCTL_CONFIG_DIR, bare
curl with NO Accept header): HTTP 200 + ': open' frame,
time_starttransfer=0.000639s (was: hung to the 15s keep-alive / curl -m
timeout). Gate: bun test dashboard/__tests__/ — 196 pass / 0 fail.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
W6 row ① fix-at-source (closet #428). Bun finalizes a streaming Response head only when the first chunk enqueues; frame-less-at-open SSE routes left their heads unterminated on the wire (spec-compliant clients wait — root-caused by w6-proxy, W6-A). Immediate
: opencomment frames in ReadableStream start() on the three lazy-headed routes (update/events + two audit/stream routes found in the same sweep). Complements the v4 proxy's SSE head grace (merge 9091a6c) — defense at both layers.Orchestrator-verified: dashboard suite 196/0 in clean worktree; live bare-curl proof on both ports follows post-deploy.
🤖 Generated with Claude Code