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
- 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.
- 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.
- Keep the suite green.
chat-main-flows.test.tsxmust pass. If a change makes a case wrong, change the case in the same PR and say why. - 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.
- Watch after release.
composer_send_blockedwithreason = '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.
'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: