CedarCopilot wants to merge 1 commit into staging from fix/concentrate-stale-ui-sse
Not deployed
Libra has no production signal for this change yet because it has not deployed. Libra checks hourly for 3 days after each deploy.
A customer reported a deal "splitting into two" in the UI. The real cause: an open conversation went stale after a background-completed execution wrote its fields, and the frontend never learned about it, so the customer was looking at two different data snapshots side by side and mistook the discrepancy for a duplicated deal.
use-aop-refresh-watcher.ts only invalidated the conversation's query by polling for a
runId the current session itself had started. It had no way to learn about a write from
any other session or trigger , another rep's session, a cron, a webhook, a meeting sync,
an HubSpot/Salesforce sync , that touched the same conversation's fields while it was open in
this tab.
GET /api/conversation-events SSE endpoint (apps/server/src/http/app.ts),
mirroring the existing /doc-events pattern, that subscribes to the previously
push-only sseEventBus and forwards conversations notifications for the session user.use-aop-refresh-watcher.ts now also subscribes to this SSE channel (in addition to its
existing self-triggered poll) and invalidates the conversation's query whenever it sees a
conversations notification whose hint matches the open conversation , regardless of which
session or trigger produced the write.hint format into a new leaf module,
apps/server/src/services/sse/conversation-hint.ts (conversationFieldsHint), re-exported
through apps/server/src/lib/schemas.ts, so the client and the emitter
(apps/server/src/services/crm/conversations.ts) share the exact string format instead of
the frontend hand-copying a template string that could drift.apps/server/src/services/sse/event-bus.ts that hint is logging-only for
most notification types but is genuinely parsed for routing on conversations notifications.pnpm --filter @zero/server run types , cleanpnpm --filter @zero/mail run types , cleanpnpm deps:check , no dependency violationsš¤ Generated with Claude Code
The PR adds a per-user SSE route and client subscription intended to invalidate open conversation data after externally triggered field updates. The shared hint helper keeps emitter and client routing formats aligned, but the delivery design does not reliably reach all relevant clients.
/api/conversation-events and subscribes the conversation watcher through EventSource.The PR is not safe to merge because its API-local subscription cannot receive background worker events, and additional recipient and reconnect gaps still leave open conversations stale.
The primary delivery path terminates at a process-local worker EventEmitter rather than the API service hosting the SSE connection; even reachable emissions omit some authorized viewers and are permanently lost during client disconnects. The unchecked JSON assertion also violates an explicit repository requirement.
Files Needing Attention: apps/server/src/http/app.ts, apps/server/src/services/crm/conversations.ts, apps/mail/modules/crm/hooks/use-aop-refresh-watcher.ts
| Filename | Overview |
|---|---|
| apps/server/src/http/app.ts | Adds the SSE endpoint, but subscribes to a process-local bus that cannot receive worker |
Libra has not measured any production surfaces for this change yet.