You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Split out of a review thread on #5955 (CodeRabbit, src/core/jsonrpc.rs), where it was raised against the MCP supervisor events that PR adds. It is not specific to them, which is why it is not fixed there.
What
The developer Event Log (GET /events/domain → Settings → Developer → Event Log) is a single process-wide stream. One process serves more than one workspace over its life — mcp::host's own module doc says so, and HOSTS is insert-only, so a workspace switch leaves the old one open — but the SSE envelope carries only {domain, event, agent, detail, timestamp}. A row from a workspace the user has switched away from is indistinguishable from one belonging to the workspace they are in.
Several DomainEvent variants already know which workspace they belong to and the envelope discards it:
Correction (2026-09-02). This section originally claimed there was "no live active-workspace signal". That was wrong, and the correction is what made #5955's related P1 fixable rather than deferrable. Config::load_or_init re-resolves the workspace on every call — resolve_config_dirs_ignoring_env reads active_user.toml from disk with no caching — and #5955 exposes that as config::active_workspace_dir(). What is missing is a cached signal, not any signal. The distinction matters here specifically: a marker read per decision is fine (#5955 pays it for the handful of events a supervisor tick produces), a marker read per streamed event is not.
There is no signal cheap enough for the SSE hot path.config::active_workspace_dir() is a disk read; the Event Log streams every domain event in the process. This needs an in-memory value updated when the workspace changes, which does not exist yet.
The identity cannot simply be put on the wire as-is.workspace_dir is an absolute path under the user's home directory, and this envelope feeds a settings panel and its NDJSON download. Forwarding it would print the user's home directory into a shared, exportable surface. An opaque, stable workspace handle would be needed instead.
Doing it for one event family alone would make those the only workspace-scoped rows in a panel whose other rows are not — a more confusing contract than the current one.
Sketch
A cheap in-memory active-workspace signal, updated wherever the workspace changes, that config::active_workspace_dir() can read through instead of hitting disk each time. This is the load-bearing piece and is useful beyond the Event Log — feat(mcp): surface reconnect-supervisor outcomes in the Event Log and notifications (#5931) #5955's notification bridge pays a marker read per decision precisely because this does not exist.
An opaque per-workspace handle on the envelope (not the path) for the variants that carry one.
A panel control: current workspace only (default) vs. all, so the process-wide view stays available for debugging.
Acceptance criteria
An in-memory active-workspace signal that reflects a switch without a per-read disk hit, with the existing on-disk resolution as its source of truth
Workspace-bound events carry an opaque workspace handle in the /events/domain envelope; no filesystem path reaches the client or the NDJSON export
Event Log defaults to the active workspace and can be switched to all workspaces
Applied uniformly to the channel, artifact and MCP-supervisor families, not one of them
Regression test across a workspace switch: rows from the previous workspace are excluded by default and included when 'all' is selected
Split out of a review thread on #5955 (CodeRabbit,
src/core/jsonrpc.rs), where it was raised against the MCP supervisor events that PR adds. It is not specific to them, which is why it is not fixed there.What
The developer Event Log (
GET /events/domain→ Settings → Developer → Event Log) is a single process-wide stream. One process serves more than one workspace over its life —mcp::host's own module doc says so, andHOSTSis insert-only, so a workspace switch leaves the old one open — but the SSE envelope carries only{domain, event, agent, detail, timestamp}. A row from a workspace the user has switched away from is indistinguishable from one belonging to the workspace they are in.Several
DomainEventvariants already know which workspace they belong to and the envelope discards it:ChannelMessageReceived/ChannelMessageProcessed—workspace_dir: PathBufArtifactReady/ArtifactFailed/ and siblings —workspace_dir: StringMcpServer{ProbeTimedOut,TransportDropped,Reconnected,ReconnectFailed,Parked}—workspace_dir: PathBuf(added in feat(mcp): surface reconnect-supervisor outcomes in the Event Log and notifications (#5931) #5955)Why it was not fixed in #5955
There is no signal cheap enough for the SSE hot path.
config::active_workspace_dir()is a disk read; the Event Log streams every domain event in the process. This needs an in-memory value updated when the workspace changes, which does not exist yet.The identity cannot simply be put on the wire as-is.
workspace_diris an absolute path under the user's home directory, and this envelope feeds a settings panel and its NDJSON download. Forwarding it would print the user's home directory into a shared, exportable surface. An opaque, stable workspace handle would be needed instead.Doing it for one event family alone would make those the only workspace-scoped rows in a panel whose other rows are not — a more confusing contract than the current one.
Sketch
config::active_workspace_dir()can read through instead of hitting disk each time. This is the load-bearing piece and is useful beyond the Event Log — feat(mcp): surface reconnect-supervisor outcomes in the Event Log and notifications (#5931) #5955's notification bridge pays a marker read per decision precisely because this does not exist.Acceptance criteria
/events/domainenvelope; no filesystem path reaches the client or the NDJSON export