fix(server): enforce event stream ownership and diagnostics#37585
Open
armancharan wants to merge 26 commits into
Open
fix(server): enforce event stream ownership and diagnostics#37585armancharan wants to merge 26 commits into
armancharan wants to merge 26 commits into
Conversation
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Narrow unknown event data with object/`in` checks so sessionID is read without an assertion. Co-authored-by: Cursor <cursoragent@cursor.com>
Helpers only need directory; no test supplies a workspace. Co-authored-by: Cursor <cursoragent@cursor.com>
No test supplies a workspace; avoid an unnecessary brand cast. Co-authored-by: Cursor <cursoragent@cursor.com>
Filter interested subscribers once before encode, require directory for location scope (reject workspace-only queries), and cover those cases in tests. Co-authored-by: Cursor <cursoragent@cursor.com>
Collect matching subscribers first so encode/offer share one pass. Co-authored-by: Cursor <cursoragent@cursor.com>
Extract pure interest helpers and cover subscribeInput/equality plus ClientProvider.event.scope reconnecting only when interest changes. Co-authored-by: Cursor <cursoragent@cursor.com>
Serialize TUI subscribe generations, cancel SSE readers on abort, bridge Bun disconnects so EventFeed queues release, and expose content-free feed counters for leak detection. Co-authored-by: Cursor <cursoragent@cursor.com>
Avoid a hard EventFeed.Service requirement on the debug handler so CLI serve Effect inference stays compatible with the runtime handler map. Co-authored-by: Cursor <cursoragent@cursor.com>
Contributor
|
Thanks for your contribution! This PR doesn't have a linked issue. All PRs must reference an existing issue. Please:
See CONTRIBUTING.md for details. |
Contributor
|
The following comment was made by an LLM, it may be inaccurate: Based on my search, the PRs found are all explicitly mentioned as related work in PR #37585's description (parent stack and sibling work under #36441). These are not duplicates but intentionally related:
No duplicate PRs found |
6 tasks
armancharan
commented
Jul 18, 2026
Replace the hand-rolled unknown guards with decodeUnknownOption so ephemeral sessionID extraction matches host Schema patterns. Co-authored-by: Cursor <cursoragent@cursor.com>
armancharan
marked this pull request as draft
July 18, 2026 02:09
Map HttpApi-decoded ctx.query through interestFromSubscribeQuery, and route deepObject URLSearchParams through the same Schema before building Interest. Co-authored-by: Cursor <cursoragent@cursor.com>
Also derive EventFeed.Diagnostics from the protocol Schema and lock the generation boundary so prior-generation event IDs are not delivered. Co-authored-by: Cursor <cursoragent@cursor.com>
armancharan
commented
Jul 18, 2026
One test was asserting connect, interest change, and no-op scope together. Split into three named cases with a shared mount helper. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
armancharan
marked this pull request as ready for review
July 18, 2026 02:44
Co-authored-by: Cursor <cursoragent@cursor.com>
armancharan
commented
Jul 18, 2026
armancharan
commented
Jul 18, 2026
Co-authored-by: Cursor <cursoragent@cursor.com>
This was referenced Jul 18, 2026
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.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.
Issue for this PR
Closes #36445
#36445
Parent: #36441
Related: #36311 (minimal Bun SSE disconnect bridge on the event path only — not a platform-wide fix)
✧ raised · ○ in review · ● approved · ✓ merged
#36441 epic: scope streams + bound payloads
Merge in order:
v2
└ ○ #37486 location interest
└ ○ #37487 session interest + fan-out bench
└ ○ #37585 stream ownership / diagnostics ← this PR
└ ○ #37586 reconnect herd
Siblings under the epic (not git parents of the stack tip):
└ ○ #37559 session blobs + payloadHash
└ ○ #37570 ensure-on-first-failure → feeds #37586
Stacked on #37487 (
fix/event-subscription-sessions). GitHub base isv2because the parent branch is fork-only; ownership-only diff: armancharan/opencode@fix/event-subscription-sessions...event-stream-ownership — retarget base onto that branch after #37487 merges (or when the branch exists on anomalyco).Type of change
What does this PR do?
Guarantees one active event stream per TUI generation, prompt resource release on failure/teardown, and content-free diagnostics for leak detection.
AbortControlleron every exit; reconnect wait1000 + random(0..500)ms so N clients do not phase-lockresponse.body) so Bun sees client disconnect under custom fetchEventFeed.diagnostics()counters (active/opens/closes/serializedEvents/serializedBytes/overflows); debugGET /api/debug/event-feed; IncomingMessageaborted/close→ServerResponse.destroy()soacquireReleaseruns (2.0: standalone SSE disconnect can wedge Bun server at 100% CPU #36311 bridge, event path only)How did you verify your code works?
packages/servertest/event-feed.test.ts— eleven-client churn → baseline; overflow counts; content-free dumppackages/servertest/event-feed-fanout.bench.test.ts— from stack base: fan-out accounting laws (clients × sizes)packages/servertest/event-feed-ownership.test.ts— scope cancel → baseline; real-socket abort closes body; eleven sequential scopes never accumulatepackages/tuitest/cli/tui/client-ownership.test.tsx— rapid interest ≤1 stream; teardown → 0; prior generation does not receive events after reconnectpackages/tuitest/cli/tui/client-scope.test.tsx— connect / reconnect on change / no-op when unchanged (split)packages/server,packages/tui, andpackages/cliAcceptance → test
teardown leaves zero active event streams+rapid interest changes never exceed one active event streamrapid interest changes never exceed one active event streamreturns active subscriber count to baseline when scopes close after eleven-client churn+eleven sequential subscribe scopes never accumulate active subscriberscanceling a subscriber scope…+aborting a real Node HTTP client returns EventFeed.active to baselineevent IDs from a prior generation are not delivered after interest reconnectreturns active…dump asserts + overflow countersScreenshots / recordings
N/A — not a UI layout change.
Checklist