Skip to main content

Chat page main user flows

Required reading before changing chat-page behavior: switching chats, loading a chat, the composer and Send, streaming and re-attaching, or the history panel. Ticket: CFO-9379.

Why this exists

CFO-9358 made switching chats instant. Its tests checked how fast a chat appeared. None of them did what users do next: type and send. The change kept Send disabled for about half a second after each switch, and it reached production (fixed in CFO-9375, #4747 / #4750). The lesson is that a change to the chat page is tested against what users actually do on it, measured in PostHog, not only against the property the change set out to improve.

The flows (PostHog, 14 days to 2026-10-08)

What users do next, on /chat, after each of these events. “p25” is the fastest quarter of users.

After switching chats (chat_session_selected)

After sending (chat_message_sent)

What must always work, and the test that guards it

The page-level tests render the real ChatPage, SharedChatProvider and composer, remount the page per route like the App Router does, and hold the server’s answers back so each case controls what has loaded. Only the network and the streaming hook are mocked. chat-main-flows.test.tsx was checked to fail when the CFO-9358 regression is put back.

The rule for a chat-page change

  1. Re-measure. Run the two queries below for the components you touch. If a new next action shows up high in the list, or an existing one gets much faster, it is a flow to cover.
  2. Replay. Each flow your change can affect needs a page-level test that does what the user does, at their speed (for example, type straight after switching), and asserts what the user can do, such as Send being enabled. Assert on behavior, not on internal state.
  3. Keep the suite green. chat-main-flows.test.tsx must pass. If a change makes a case wrong, change the case in the same PR and say why.
  4. Say what was not tested live. If a live check on staging is blocked (for example, the e2e account is out of allowance), say so in the PR. Do not treat a blocked check as a passed one.
  5. Watch after release. composer_send_blocked with reason = 'submit-disabled' ran at about 0.35 an hour in the week before 2026-10-08. A rise after a chat release means users are hitting a disabled Send.

Re-measuring

Run these through the PostHog MCP (execute-sql). Change the anchor event in the last WHERE to measure what follows another action.
For after-send flows, use 'chat_message_sent' as the anchor and add 'chat_response_completed', 'chat_response_failed' and 'chat_generation_stopped' to the event list. Blocked sends by reason: