Skip to content

feat(server): narrow event subscriptions by session interest#37487

Open
armancharan wants to merge 17 commits into
anomalyco:v2from
armancharan:fix/event-subscription-sessions
Open

feat(server): narrow event subscriptions by session interest#37487
armancharan wants to merge 17 commits into
anomalyco:v2from
armancharan:fix/event-subscription-sessions

Conversation

@armancharan

@armancharan armancharan commented Jul 17, 2026

Copy link
Copy Markdown

Issue for this PR

Closes #36443

#36443

Parent: #36441

✧ raised · ○ in review · ● approved · ✓ merged

#36441 epic: scope streams + bound payloads

Merge in order:
v2
└ ○ #37486 location interest
   └ ○ #37487 session interest + fan-out bench ← this PR
      └ ○ #37585 stream ownership / diagnostics
         └ ○ #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 #37486. Merge that first, or take both together. Includes the non-gating fan-out benchmark Kit asked for on #36441 / #36443.

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Adds optional session interest on top of location scoping. Repeated session query params narrow delivery for events that carry a session identity (Event.sessionIDOf: durable aggregate ID or data.sessionID). Location-scoped events without a session still deliver. TUI reconnects the stream when the active session family changes.

Includes the 11-client fan-out regression that encodes once per event while offering only to interested subscribers. Location interest requires location[directory]; workspace-only queries are rejected.

How did you verify your code works?

  • packages/server test/event-feed.test.ts — location/session filter, encode-once, 11-client fan-out, workspace-without-directory rejected, global types bypass
  • packages/server test/event-feed-fanout.bench.test.ts — clients 1..16 × small/medium/large; encode-once and bytes independent of uninterested N (timings/RSS logged, non-gating)
  • packages/schema test/event.test.tssessionIDOf
  • packages/tui test/context/client-interest.test.tssubscribeInput / interestEqual
  • packages/tui test/cli/tui/client-scope.test.tsxevent.scope reconnects on interest change only
  • typecheck for schema, protocol, server, client, tui

Acceptance → test

  • Fan-out cost ∝ interested subscribers (encode-once; bytes scale with payload, not N) → accounting laws hold across client counts and payload sizes

  • Session A does not receive session B → delivers session-scoped events only to interested subscribers

  • Location-only events still flow under session interest → keeps location-only events flowing when session interest is set

  • Encode once for interested N → fans out eleven concurrent clients by interest, encoding once per event / encodes once for multiple scoped subscribers…

  • Workspace without directory rejected → rejects workspace interest without a directory

  • TUI reconnect on interest change → client-scope + client-interest tests above

Screenshots / recordings

N/A — not a UI layout change.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

armancharan and others added 2 commits July 17, 2026 21:58
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions

Copy link
Copy Markdown
Contributor

The following comment was made by an LLM, it may be inaccurate:

Based on my search, I found one related PR:

Related PR:

The current PR (#37487) builds on top of #37486 by adding session-level filtering on top of the location scoping that #37486 introduces. They are designed to be applied together as a stacked change.

No duplicate PRs found - the search shows only these two related PRs which are intentionally complementary features in a stack.

armancharan and others added 2 commits July 17, 2026 22:33
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread packages/schema/src/event.ts Outdated
armancharan and others added 8 commits July 17, 2026 22:59
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>
Comment thread packages/client/src/promise/generated/types.ts
Replace the hand-rolled unknown guards with decodeUnknownOption so
ephemeral sessionID extraction matches host Schema patterns.

Co-authored-by: Cursor <cursoragent@cursor.com>
@armancharan
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>
@armancharan
armancharan marked this pull request as ready for review July 18, 2026 02:20
armancharan and others added 2 commits July 18, 2026 12:37
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>
Co-authored-by: Cursor <cursoragent@cursor.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.

1 participant